@@ -8,6 +8,91 @@ use std::cell::RefCell;
88use std:: collections:: HashMap ;
99use std:: rc:: Rc ;
1010
11+ /// Slot-based storage with free list for O(1) allocation and deallocation
12+ struct SlotVec < T > {
13+ slots : Vec < Option < T > > ,
14+ free_list : Vec < u32 > ,
15+ count : usize ,
16+ }
17+
18+ #[ allow( unused) ]
19+ impl < T > SlotVec < T > {
20+ fn new ( ) -> Self {
21+ Self {
22+ slots : Vec :: new ( ) ,
23+ free_list : Vec :: new ( ) ,
24+ count : 0 ,
25+ }
26+ }
27+
28+ fn with_capacity ( capacity : usize ) -> Self {
29+ Self {
30+ slots : Vec :: with_capacity ( capacity) ,
31+ free_list : Vec :: with_capacity ( capacity / 4 ) ,
32+ count : 0 ,
33+ }
34+ }
35+
36+ /// O(1) insertion - reuse free slot or append new slot
37+ #[ inline]
38+ fn insert ( & mut self , value : T ) -> u32 {
39+ self . count += 1 ;
40+
41+ if let Some ( free_id) = self . free_list . pop ( ) {
42+ self . slots [ free_id as usize ] = Some ( value) ;
43+ free_id
44+ } else {
45+ let id = self . slots . len ( ) as u32 ;
46+ self . slots . push ( Some ( value) ) ;
47+ id
48+ }
49+ }
50+
51+ /// O(1) lookup - direct array indexing
52+ #[ inline]
53+ fn get ( & self , id : u32 ) -> Option < & T > {
54+ self . slots . get ( id as usize ) . and_then ( |slot| slot. as_ref ( ) )
55+ }
56+
57+ /// O(1) removal - mark as free and add to free list
58+ #[ inline]
59+ fn remove ( & mut self , id : u32 ) -> Option < T > {
60+ if let Some ( slot) = self . slots . get_mut ( id as usize ) {
61+ if let Some ( value) = slot. take ( ) {
62+ self . free_list . push ( id) ;
63+ self . count -= 1 ;
64+ return Some ( value) ;
65+ }
66+ }
67+ None
68+ }
69+
70+ #[ inline]
71+ fn len ( & self ) -> usize {
72+ self . count
73+ }
74+
75+ /// Shrink memory after GC
76+ fn shrink_to_fit ( & mut self ) {
77+ if self . free_list . len ( ) < self . slots . len ( ) / 4 {
78+ self . free_list . shrink_to_fit ( ) ;
79+ return ;
80+ }
81+
82+ while let Some ( None ) = self . slots . last ( ) {
83+ let removed_id = self . slots . len ( ) - 1 ;
84+ self . slots . pop ( ) ;
85+
86+ if let Some ( pos) = self . free_list . iter ( ) . rposition ( |& id| id as usize == removed_id) {
87+ self . free_list . swap_remove ( pos) ;
88+ }
89+ }
90+
91+ self . slots . shrink_to_fit ( ) ;
92+ self . free_list . shrink_to_fit ( ) ;
93+ }
94+ }
95+
1196/// Object IDs - u32 is enough for most use cases (4 billion objects)
1297#[ derive( Clone , Copy , PartialEq , Eq , Hash , Debug ) ]
1398pub struct StringId ( pub u32 ) ;
@@ -63,17 +148,10 @@ impl FunctionId {
63148
64149/// Object Pool for all heap-allocated Lua objects
65150pub struct ObjectPool {
66- // Object storage - 所有类型都用 Rc 包装以防止 HashMap rehash 导致指针失效
67- strings : HashMap < StringId , Rc < LuaString > > ,
68- tables : HashMap < TableId , Rc < RefCell < LuaTable > > > ,
69- userdata : HashMap < UserdataId , Rc < RefCell < LuaUserdata > > > ,
70- functions : HashMap < FunctionId , Rc < RefCell < lua_value:: LuaFunction > > > ,
71-
72- // ID generators
73- next_string_id : StringId ,
74- next_table_id : TableId ,
75- next_userdata_id : UserdataId ,
76- next_function_id : FunctionId ,
151+ strings : SlotVec < Rc < LuaString > > ,
152+ tables : SlotVec < Rc < RefCell < LuaTable > > > ,
153+ userdata : SlotVec < Rc < RefCell < LuaUserdata > > > ,
154+ functions : SlotVec < Rc < RefCell < lua_value:: LuaFunction > > > ,
77155
78156 // String interning table (hash -> id mapping)
79157 // For strings ≤ 64 bytes, we intern them for memory efficiency
@@ -84,14 +162,10 @@ pub struct ObjectPool {
84162impl ObjectPool {
85163 pub fn new ( ) -> Self {
86164 ObjectPool {
87- strings : HashMap :: with_capacity ( 128 ) ,
88- tables : HashMap :: with_capacity ( 16 ) ,
89- userdata : HashMap :: with_capacity ( 0 ) ,
90- functions : HashMap :: with_capacity ( 64 ) ,
91- next_string_id : StringId ( 1 ) , // 0 reserved for null/invalid
92- next_table_id : TableId ( 1 ) ,
93- next_userdata_id : UserdataId ( 1 ) ,
94- next_function_id : FunctionId ( 1 ) ,
165+ strings : SlotVec :: with_capacity ( 128 ) ,
166+ tables : SlotVec :: with_capacity ( 16 ) ,
167+ userdata : SlotVec :: with_capacity ( 0 ) ,
168+ functions : SlotVec :: with_capacity ( 64 ) ,
95169 string_intern : HashMap :: with_capacity ( 128 ) ,
96170 max_intern_length : 64 ,
97171 }
@@ -115,43 +189,37 @@ impl ObjectPool {
115189 // Check intern table
116190 if let Some ( & id) = self . string_intern . get ( & hash) {
117191 // Verify content (hash collision check)
118- if let Some ( existing) = self . strings . get ( & id ) {
192+ if let Some ( existing) = self . strings . get ( id . 0 ) {
119193 if existing. as_str ( ) == s {
120194 return id;
121195 }
122196 }
123197 }
124198
125199 // Create new interned string
126- let id = self . next_string_id ;
127- self . next_string_id = id. next ( ) ;
128-
129200 let lua_string = Rc :: new ( LuaString :: new ( s. to_string ( ) ) ) ;
130- self . strings . insert ( id, lua_string) ;
201+ let slot_id = self . strings . insert ( lua_string) ;
202+ let id = StringId ( slot_id) ;
131203 self . string_intern . insert ( hash, id) ;
132204
133205 id
134206 } else {
135207 // Long string - no interning
136- let id = self . next_string_id ;
137- self . next_string_id = id. next ( ) ;
138-
139208 let lua_string = Rc :: new ( LuaString :: new ( s. to_string ( ) ) ) ;
140- self . strings . insert ( id, lua_string) ;
141-
142- id
209+ let slot_id = self . strings . insert ( lua_string) ;
210+ StringId ( slot_id)
143211 }
144212 }
145213
146214 /// Get string by ID
147215 #[ inline]
148216 pub fn get_string ( & self , id : StringId ) -> Option < & Rc < LuaString > > {
149- self . strings . get ( & id )
217+ self . strings . get ( id . 0 )
150218 }
151219
152220 /// Remove string (called by GC)
153221 pub fn remove_string ( & mut self , id : StringId ) -> Option < Rc < LuaString > > {
154- if let Some ( string) = self . strings . remove ( & id ) {
222+ if let Some ( string) = self . strings . remove ( id . 0 ) {
155223 // Also remove from intern table if present
156224 if string. as_str ( ) . len ( ) <= self . max_intern_length {
157225 use std:: collections:: hash_map:: DefaultHasher ;
@@ -177,78 +245,64 @@ impl ObjectPool {
177245
178246 /// Create a new table
179247 pub fn create_table ( & mut self , array_size : usize , hash_size : usize ) -> TableId {
180- let id = self . next_table_id ;
181- self . next_table_id = id. next ( ) ;
182-
183- self . tables . insert (
184- id,
185- Rc :: new ( RefCell :: new ( LuaTable :: new ( array_size, hash_size) ) ) ,
186- ) ;
187-
188- id
248+ let table = Rc :: new ( RefCell :: new ( LuaTable :: new ( array_size, hash_size) ) ) ;
249+ let slot_id = self . tables . insert ( table) ;
250+ TableId ( slot_id)
189251 }
190252
191253 /// Get table by ID
192254 #[ inline]
193255 pub fn get_table ( & self , id : TableId ) -> Option < & Rc < RefCell < LuaTable > > > {
194- self . tables . get ( & id )
256+ self . tables . get ( id . 0 )
195257 }
196258
197259 /// Remove table (called by GC)
198260 pub fn remove_table ( & mut self , id : TableId ) -> Option < Rc < RefCell < LuaTable > > > {
199- self . tables . remove ( & id )
261+ self . tables . remove ( id . 0 )
200262 }
201263
202264 // ============ Userdata Operations ============
203265
204266 /// Create new userdata
205267 pub fn create_userdata ( & mut self , data : LuaUserdata ) -> UserdataId {
206- let id = self . next_userdata_id ;
207- self . next_userdata_id = id. next ( ) ;
208-
209- self . userdata . insert ( id, Rc :: new ( RefCell :: new ( data) ) ) ;
210-
211- id
268+ let slot_id = self . userdata . insert ( Rc :: new ( RefCell :: new ( data) ) ) ;
269+ UserdataId ( slot_id)
212270 }
213271
214272 /// Get userdata by ID
215273 #[ inline]
216274 pub fn get_userdata ( & self , id : UserdataId ) -> Option < & Rc < RefCell < LuaUserdata > > > {
217- self . userdata . get ( & id )
275+ self . userdata . get ( id . 0 )
218276 }
219277
220278 /// Get mutable userdata by ID (actually returns &Rc<RefCell<>> - mutate via borrow_mut)
221279 #[ inline]
222280 pub fn get_userdata_mut ( & mut self , id : UserdataId ) -> Option < & Rc < RefCell < LuaUserdata > > > {
223- self . userdata . get ( & id )
281+ self . userdata . get ( id . 0 )
224282 }
225283
226284 /// Remove userdata (called by GC)
227285 pub fn remove_userdata ( & mut self , id : UserdataId ) -> Option < Rc < RefCell < LuaUserdata > > > {
228- self . userdata . remove ( & id )
286+ self . userdata . remove ( id . 0 )
229287 }
230288
231289 // ============ Function Operations ============
232290
233291 /// Create a new function
234292 pub fn create_function ( & mut self , func : LuaFunction ) -> FunctionId {
235- let id = self . next_function_id ;
236- self . next_function_id = id. next ( ) ;
237-
238- self . functions
239- . insert ( id, std:: rc:: Rc :: new ( RefCell :: new ( func) ) ) ;
240- id
293+ let slot_id = self . functions . insert ( Rc :: new ( RefCell :: new ( func) ) ) ;
294+ FunctionId ( slot_id)
241295 }
242296
243297 /// Get function by ID
244298 #[ inline]
245299 pub fn get_function ( & self , id : FunctionId ) -> Option < & std:: rc:: Rc < RefCell < LuaFunction > > > {
246- self . functions . get ( & id )
300+ self . functions . get ( id . 0 )
247301 }
248302
249303 /// Remove function (called by GC)
250304 pub fn remove_function ( & mut self , id : FunctionId ) -> Option < std:: rc:: Rc < RefCell < LuaFunction > > > {
251- self . functions . remove ( & id )
305+ self . functions . remove ( id . 0 )
252306 }
253307
254308 // ============ Statistics ============
0 commit comments