@@ -77,24 +77,37 @@ impl<IT, N> Key<IT, N> {
7777 }
7878}
7979
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+
8091// Data type that stores values and returns a key that can be used to manipulate
8192// the stored values.
8293// Values can be read by anyone but can only be modified using the key.
8394pub 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 > ,
87100 free_count : usize
88101}
89102
90103impl < IT , N > Slots < IT , N >
91- where N : ArrayLength < Option < IT > > + ArrayLength < usize > + Unsigned {
104+ where N : ArrayLength < Entry < IT > > + Unsigned {
92105 pub fn new ( ) -> Self {
93106 let size = N :: to_usize ( ) ;
94107
95108 Self {
96- items : GenericArray :: default ( ) ,
97- free_list : GenericArray :: generate ( | i : usize | size - i - 1 ) ,
109+ items : GenericArray :: generate ( |i| i . checked_sub ( 1 ) . map ( Entry :: EmptyNext ) . unwrap_or ( Entry :: EmptyLast ) ) ,
110+ next_free : size. checked_sub ( 1 ) ,
98111 free_count : size
99112 }
100113 }
@@ -108,37 +121,41 @@ impl<IT, N> Slots<IT, N>
108121 }
109122
110123 fn free ( & mut self , idx : usize ) {
111- self . free_list [ self . free_count ] = idx;
124+ self . items [ idx] = match self . next_free {
125+ Some ( n) => Entry :: EmptyNext ( n) ,
126+ None => Entry :: EmptyLast
127+ } ;
128+ self . next_free = Some ( idx) ;
112129 self . free_count += 1 ;
113130 }
114131
115132 fn alloc ( & mut self ) -> Option < usize > {
116- if self . count ( ) == self . capacity ( ) {
117- None
118- } else {
119- let i = self . free_list [ self . free_count - 1 ] ;
120- self . free_count -= 1 ;
121- Some ( i)
122- }
133+ let index = self . next_free ?;
134+ self . next_free = match self . items [ index] {
135+ Entry :: EmptyNext ( n) => Some ( n) ,
136+ Entry :: EmptyLast => None ,
137+ _ => unreachable ! ( "Non-empty item in entry behind free chain" ) ,
138+ } ;
139+ self . free_count -= 1 ;
140+ Some ( index)
123141 }
124142
125143 pub fn store ( & mut self , item : IT ) -> Result < Key < IT , N > , IT > {
126144 match self . alloc ( ) {
127145 Some ( i) => {
128- self . items [ i] = Some ( item) ;
146+ self . items [ i] = Entry :: Used ( item) ;
129147 Ok ( Key :: new ( i) )
130148 }
131149 None => Err ( item)
132150 }
133151 }
134152
135153 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 ! ( )
154+ let taken = core:: mem:: replace ( & mut self . items [ key. index ] , Entry :: EmptyLast ) ;
155+ self . free ( key. index ) ;
156+ match taken {
157+ Entry :: Used ( item) => item,
158+ _ => panic ! ( )
142159 }
143160 }
144161
@@ -151,15 +168,15 @@ impl<IT, N> Slots<IT, N>
151168
152169 pub fn try_read < T , F > ( & self , key : usize , function : F ) -> Option < T > where F : FnOnce ( & IT ) -> T {
153170 match & self . items [ key] {
154- Some ( item) => Some ( function ( & item) ) ,
155- None => None
171+ Entry :: Used ( item) => Some ( function ( & item) ) ,
172+ _ => None
156173 }
157174 }
158175
159176 pub fn modify < T , F > ( & mut self , key : & Key < IT , N > , function : F ) -> T where F : FnOnce ( & mut IT ) -> T {
160177 match self . items [ key. index ] {
161- Some ( ref mut item) => function ( item) ,
162- None => panic ! ( )
178+ Entry :: Used ( ref mut item) => function ( item) ,
179+ _ => panic ! ( )
163180 }
164181 }
165182}
0 commit comments