@@ -77,24 +77,41 @@ impl<IT, N> Key<IT, N> {
77
77
}
78
78
}
79
79
80
+ /// Module to hide the Entry type which needs to be public due to the generic-array internals.
81
+ mod entry {
82
+ pub enum Entry < IT > {
83
+ Used ( IT ) ,
84
+ EmptyNext ( usize ) ,
85
+ EmptyLast
86
+ }
87
+ }
88
+
89
+ use entry:: Entry ;
90
+
80
91
// Data type that stores values and returns a key that can be used to manipulate
81
92
// the stored values.
82
93
// Values can be read by anyone but can only be modified using the key.
83
94
pub struct Slots < IT , N >
84
- where N : ArrayLength < Option < IT > > + ArrayLength < usize > + Unsigned {
85
- items : GenericArray < Option < IT > , N > ,
86
- free_list : GenericArray < usize , N > ,
95
+ where N : ArrayLength < Entry < IT > > + Unsigned {
96
+ items : GenericArray < Entry < IT > , N > ,
97
+ // Could be optimized by making it just usize and relying on free_count to determine its
98
+ // validity
99
+ next_free : Option < usize > ,
87
100
free_count : usize
88
101
}
89
102
90
103
impl < IT , N > Slots < IT , N >
91
- where N : ArrayLength < Option < IT > > + ArrayLength < usize > + Unsigned {
104
+ where N : ArrayLength < Entry < IT > > + Unsigned {
92
105
pub fn new ( ) -> Self {
93
106
let size = N :: to_usize ( ) ;
94
107
95
108
Self {
96
- items : GenericArray :: default ( ) ,
97
- free_list : GenericArray :: generate ( |i : usize | size - i - 1 ) ,
109
+ // Fill back-to-front
110
+ // items: GenericArray::generate(|i: usize| if i == 0 { Entry::EmptyLast } else { Entry::EmptyNext(i - 1) }),
111
+ // next_free: size.checked_sub(1),
112
+ // Fill front-to-back
113
+ items : GenericArray :: generate ( |i : usize | if i == size - 1 { Entry :: EmptyLast } else { Entry :: EmptyNext ( i + 1 ) } ) ,
114
+ next_free : Some ( 0 ) ,
98
115
free_count : size
99
116
}
100
117
}
@@ -108,37 +125,45 @@ impl<IT, N> Slots<IT, N>
108
125
}
109
126
110
127
fn free ( & mut self , idx : usize ) {
111
- self . free_list [ self . free_count ] = idx;
128
+ self . items [ idx] = match self . next_free {
129
+ Some ( n) => Entry :: EmptyNext ( n) ,
130
+ None => Entry :: EmptyLast
131
+ } ;
132
+ self . next_free = Some ( idx) ;
112
133
self . free_count += 1 ;
113
134
}
114
135
115
136
fn alloc ( & mut self ) -> Option < usize > {
116
137
if self . count ( ) == self . capacity ( ) {
117
138
None
118
139
} else {
119
- let i = self . free_list [ self . free_count - 1 ] ;
140
+ let result = self . next_free ;
141
+ self . next_free = match self . items [ result. expect ( "Count mismatch" ) ] {
142
+ Entry :: EmptyNext ( n) => Some ( n) ,
143
+ Entry :: EmptyLast => None ,
144
+ _ => unreachable ! ( "Non-empty item in entry behind free chain" ) ,
145
+ } ;
120
146
self . free_count -= 1 ;
121
- Some ( i )
147
+ result
122
148
}
123
149
}
124
150
125
151
pub fn store ( & mut self , item : IT ) -> Result < Key < IT , N > , IT > {
126
152
match self . alloc ( ) {
127
153
Some ( i) => {
128
- self . items [ i] = Some ( item) ;
154
+ self . items [ i] = Entry :: Used ( item) ;
129
155
Ok ( Key :: new ( i) )
130
156
}
131
157
None => Err ( item)
132
158
}
133
159
}
134
160
135
161
pub fn take ( & mut self , key : Key < IT , N > ) -> IT {
136
- match self . items [ key. index ] . take ( ) {
137
- Some ( item) => {
138
- self . free ( key. index ) ;
139
- item
140
- }
141
- None => panic ! ( )
162
+ let taken = core:: mem:: replace ( & mut self . items [ key. index ] , Entry :: EmptyLast ) ;
163
+ self . free ( key. index ) ;
164
+ match taken {
165
+ Entry :: Used ( item) => item,
166
+ _ => panic ! ( )
142
167
}
143
168
}
144
169
@@ -151,15 +176,15 @@ impl<IT, N> Slots<IT, N>
151
176
152
177
pub fn try_read < T , F > ( & self , key : usize , function : F ) -> Option < T > where F : Fn ( & IT ) -> T {
153
178
match & self . items [ key] {
154
- Some ( item) => Some ( function ( & item) ) ,
155
- None => None
179
+ Entry :: Used ( item) => Some ( function ( & item) ) ,
180
+ _ => None
156
181
}
157
182
}
158
183
159
184
pub fn modify < T , F > ( & mut self , key : & Key < IT , N > , function : F ) -> T where F : Fn ( & mut IT ) -> T {
160
185
match self . items [ key. index ] {
161
- Some ( ref mut item) => function ( item) ,
162
- None => panic ! ( )
186
+ Entry :: Used ( ref mut item) => function ( item) ,
187
+ _ => panic ! ( )
163
188
}
164
189
}
165
190
}
0 commit comments