bfea9c4950176fb59b6ed8344b98f60a5c408942
[supertux.git] / external / squirrel / squirrel / sqstate.cpp
1 /*\r
2         see copyright notice in squirrel.h\r
3 */\r
4 #include "sqpcheader.h"\r
5 #include "sqopcodes.h"\r
6 #include "sqvm.h"\r
7 #include "sqfuncproto.h"\r
8 #include "sqclosure.h"\r
9 #include "sqstring.h"\r
10 #include "sqtable.h"\r
11 #include "sqarray.h"\r
12 #include "squserdata.h"\r
13 #include "sqclass.h"\r
14 \r
15 //SQObjectPtr _null_;\r
16 //SQObjectPtr _true_(true);\r
17 //SQObjectPtr _false_(false);\r
18 //SQObjectPtr _one_((SQInteger)1);\r
19 //SQObjectPtr _minusone_((SQInteger)-1);\r
20 \r
21 SQSharedState::SQSharedState()\r
22 {\r
23         _compilererrorhandler = NULL;\r
24         _printfunc = NULL;\r
25         _errorfunc = NULL;\r
26         _debuginfo = false;\r
27         _notifyallexceptions = false;\r
28 }\r
29 \r
30 #define newsysstring(s) {       \\r
31         _systemstrings->push_back(SQString::Create(this,s));    \\r
32         }\r
33 \r
34 #define newmetamethod(s) {      \\r
35         _metamethods->push_back(SQString::Create(this,s));      \\r
36         _table(_metamethodsmap)->NewSlot(_metamethods->back(),(SQInteger)(_metamethods->size()-1)); \\r
37         }\r
38 \r
39 bool CompileTypemask(SQIntVec &res,const SQChar *typemask)\r
40 {\r
41         SQInteger i = 0;\r
42         \r
43         SQInteger mask = 0;\r
44         while(typemask[i] != 0) {\r
45                 \r
46                 switch(typemask[i]){\r
47                                 case 'o': mask |= _RT_NULL; break;\r
48                                 case 'i': mask |= _RT_INTEGER; break;\r
49                                 case 'f': mask |= _RT_FLOAT; break;\r
50                                 case 'n': mask |= (_RT_FLOAT | _RT_INTEGER); break;\r
51                                 case 's': mask |= _RT_STRING; break;\r
52                                 case 't': mask |= _RT_TABLE; break;\r
53                                 case 'a': mask |= _RT_ARRAY; break;\r
54                                 case 'u': mask |= _RT_USERDATA; break;\r
55                                 case 'c': mask |= (_RT_CLOSURE | _RT_NATIVECLOSURE); break;\r
56                                 case 'b': mask |= _RT_BOOL; break;\r
57                                 case 'g': mask |= _RT_GENERATOR; break;\r
58                                 case 'p': mask |= _RT_USERPOINTER; break;\r
59                                 case 'v': mask |= _RT_THREAD; break;\r
60                                 case 'x': mask |= _RT_INSTANCE; break;\r
61                                 case 'y': mask |= _RT_CLASS; break;\r
62                                 case 'r': mask |= _RT_WEAKREF; break;\r
63                                 case '.': mask = -1; res.push_back(mask); i++; mask = 0; continue;\r
64                                 case ' ': i++; continue; //ignores spaces\r
65                                 default:\r
66                                         return false;\r
67                 }\r
68                 i++;\r
69                 if(typemask[i] == '|') { \r
70                         i++; \r
71                         if(typemask[i] == 0)\r
72                                 return false;\r
73                         continue; \r
74                 }\r
75                 res.push_back(mask);\r
76                 mask = 0;\r
77                 \r
78         }\r
79         return true;\r
80 }\r
81 \r
82 SQTable *CreateDefaultDelegate(SQSharedState *ss,SQRegFunction *funcz)\r
83 {\r
84         SQInteger i=0;\r
85         SQTable *t=SQTable::Create(ss,0);\r
86         while(funcz[i].name!=0){\r
87                 SQNativeClosure *nc = SQNativeClosure::Create(ss,funcz[i].f,0);\r
88                 nc->_nparamscheck = funcz[i].nparamscheck;\r
89                 nc->_name = SQString::Create(ss,funcz[i].name);\r
90                 if(funcz[i].typemask && !CompileTypemask(nc->_typecheck,funcz[i].typemask))\r
91                         return NULL;\r
92                 t->NewSlot(SQString::Create(ss,funcz[i].name),nc);\r
93                 i++;\r
94         }\r
95         return t;\r
96 }\r
97 \r
98 void SQSharedState::Init()\r
99 {       \r
100         _scratchpad=NULL;\r
101         _scratchpadsize=0;\r
102 #ifndef NO_GARBAGE_COLLECTOR\r
103         _gc_chain=NULL;\r
104 #endif\r
105         _stringtable = (SQStringTable*)SQ_MALLOC(sizeof(SQStringTable));\r
106         new (_stringtable) SQStringTable(this);\r
107         sq_new(_metamethods,SQObjectPtrVec);\r
108         sq_new(_systemstrings,SQObjectPtrVec);\r
109         sq_new(_types,SQObjectPtrVec);\r
110         _metamethodsmap = SQTable::Create(this,MT_LAST-1);\r
111         //adding type strings to avoid memory trashing\r
112         //types names\r
113         newsysstring(_SC("null"));\r
114         newsysstring(_SC("table"));\r
115         newsysstring(_SC("array"));\r
116         newsysstring(_SC("closure"));\r
117         newsysstring(_SC("string"));\r
118         newsysstring(_SC("userdata"));\r
119         newsysstring(_SC("integer"));\r
120         newsysstring(_SC("float"));\r
121         newsysstring(_SC("userpointer"));\r
122         newsysstring(_SC("function"));\r
123         newsysstring(_SC("generator"));\r
124         newsysstring(_SC("thread"));\r
125         newsysstring(_SC("class"));\r
126         newsysstring(_SC("instance"));\r
127         newsysstring(_SC("bool"));\r
128         //meta methods\r
129         newmetamethod(MM_ADD);\r
130         newmetamethod(MM_SUB);\r
131         newmetamethod(MM_MUL);\r
132         newmetamethod(MM_DIV);\r
133         newmetamethod(MM_UNM);\r
134         newmetamethod(MM_MODULO);\r
135         newmetamethod(MM_SET);\r
136         newmetamethod(MM_GET);\r
137         newmetamethod(MM_TYPEOF);\r
138         newmetamethod(MM_NEXTI);\r
139         newmetamethod(MM_CMP);\r
140         newmetamethod(MM_CALL);\r
141         newmetamethod(MM_CLONED);\r
142         newmetamethod(MM_NEWSLOT);\r
143         newmetamethod(MM_DELSLOT);\r
144         newmetamethod(MM_TOSTRING);\r
145         newmetamethod(MM_NEWMEMBER);\r
146         newmetamethod(MM_INHERITED);\r
147 \r
148         _constructoridx = SQString::Create(this,_SC("constructor"));\r
149         _registry = SQTable::Create(this,0);\r
150         _consts = SQTable::Create(this,0);\r
151         _table_default_delegate = CreateDefaultDelegate(this,_table_default_delegate_funcz);\r
152         _array_default_delegate = CreateDefaultDelegate(this,_array_default_delegate_funcz);\r
153         _string_default_delegate = CreateDefaultDelegate(this,_string_default_delegate_funcz);\r
154         _number_default_delegate = CreateDefaultDelegate(this,_number_default_delegate_funcz);\r
155         _closure_default_delegate = CreateDefaultDelegate(this,_closure_default_delegate_funcz);\r
156         _generator_default_delegate = CreateDefaultDelegate(this,_generator_default_delegate_funcz);\r
157         _thread_default_delegate = CreateDefaultDelegate(this,_thread_default_delegate_funcz);\r
158         _class_default_delegate = CreateDefaultDelegate(this,_class_default_delegate_funcz);\r
159         _instance_default_delegate = CreateDefaultDelegate(this,_instance_default_delegate_funcz);\r
160         _weakref_default_delegate = CreateDefaultDelegate(this,_weakref_default_delegate_funcz);\r
161 \r
162 }\r
163 \r
164 SQSharedState::~SQSharedState()\r
165 {\r
166         _constructoridx.Null();\r
167         _table(_registry)->Finalize();\r
168         _table(_consts)->Finalize();\r
169         _table(_metamethodsmap)->Finalize();\r
170         _registry.Null();\r
171         _consts.Null();\r
172         _metamethodsmap.Null();\r
173         while(!_systemstrings->empty()) {\r
174                 _systemstrings->back().Null();\r
175                 _systemstrings->pop_back();\r
176         }\r
177         _thread(_root_vm)->Finalize();\r
178         _root_vm.Null();\r
179         _table_default_delegate.Null();\r
180         _array_default_delegate.Null();\r
181         _string_default_delegate.Null();\r
182         _number_default_delegate.Null();\r
183         _closure_default_delegate.Null();\r
184         _generator_default_delegate.Null();\r
185         _thread_default_delegate.Null();\r
186         _class_default_delegate.Null();\r
187         _instance_default_delegate.Null();\r
188         _weakref_default_delegate.Null();\r
189         _refs_table.Finalize();\r
190 #ifndef NO_GARBAGE_COLLECTOR\r
191         SQCollectable *t = _gc_chain;\r
192         SQCollectable *nx = NULL;\r
193         if(t) {\r
194                 t->_uiRef++;\r
195                 while(t) {\r
196                         t->Finalize();\r
197                         nx = t->_next;\r
198                         if(nx) nx->_uiRef++;\r
199                         if(--t->_uiRef == 0)\r
200                                 t->Release();\r
201                         t = nx;\r
202                 }\r
203         }\r
204         assert(_gc_chain==NULL); //just to proove a theory\r
205         while(_gc_chain){\r
206                 _gc_chain->_uiRef++;\r
207                 _gc_chain->Release();\r
208         }\r
209 #endif\r
210 \r
211         sq_delete(_types,SQObjectPtrVec);\r
212         sq_delete(_systemstrings,SQObjectPtrVec);\r
213         sq_delete(_metamethods,SQObjectPtrVec);\r
214         sq_delete(_stringtable,SQStringTable);\r
215         if(_scratchpad)SQ_FREE(_scratchpad,_scratchpadsize);\r
216 }\r
217 \r
218 \r
219 SQInteger SQSharedState::GetMetaMethodIdxByName(const SQObjectPtr &name)\r
220 {\r
221         if(type(name) != OT_STRING)\r
222                 return -1;\r
223         SQObjectPtr ret;\r
224         if(_table(_metamethodsmap)->Get(name,ret)) {\r
225                 return _integer(ret);\r
226         }\r
227         return -1;\r
228 }\r
229 \r
230 #ifndef NO_GARBAGE_COLLECTOR\r
231 \r
232 void SQSharedState::MarkObject(SQObjectPtr &o,SQCollectable **chain)\r
233 {\r
234         switch(type(o)){\r
235         case OT_TABLE:_table(o)->Mark(chain);break;\r
236         case OT_ARRAY:_array(o)->Mark(chain);break;\r
237         case OT_USERDATA:_userdata(o)->Mark(chain);break;\r
238         case OT_CLOSURE:_closure(o)->Mark(chain);break;\r
239         case OT_NATIVECLOSURE:_nativeclosure(o)->Mark(chain);break;\r
240         case OT_GENERATOR:_generator(o)->Mark(chain);break;\r
241         case OT_THREAD:_thread(o)->Mark(chain);break;\r
242         case OT_CLASS:_class(o)->Mark(chain);break;\r
243         case OT_INSTANCE:_instance(o)->Mark(chain);break;\r
244         case OT_OUTER:_outer(o)->Mark(chain);break;\r
245         case OT_FUNCPROTO:_funcproto(o)->Mark(chain);break;\r
246         default: break; //shutup compiler\r
247         }\r
248 }\r
249 \r
250 \r
251 void SQSharedState::RunMark(SQVM *vm,SQCollectable **tchain)\r
252 {\r
253         SQVM *vms = _thread(_root_vm);\r
254         \r
255         vms->Mark(tchain);\r
256         \r
257         _refs_table.Mark(tchain);\r
258         MarkObject(_registry,tchain);\r
259         MarkObject(_consts,tchain);\r
260         MarkObject(_metamethodsmap,tchain);\r
261         MarkObject(_table_default_delegate,tchain);\r
262         MarkObject(_array_default_delegate,tchain);\r
263         MarkObject(_string_default_delegate,tchain);\r
264         MarkObject(_number_default_delegate,tchain);\r
265         MarkObject(_generator_default_delegate,tchain);\r
266         MarkObject(_thread_default_delegate,tchain);\r
267         MarkObject(_closure_default_delegate,tchain);\r
268         MarkObject(_class_default_delegate,tchain);\r
269         MarkObject(_instance_default_delegate,tchain);\r
270         MarkObject(_weakref_default_delegate,tchain);\r
271 \r
272 }\r
273 \r
274 SQInteger SQSharedState::ResurrectUnreachable(SQVM *vm)\r
275 {\r
276         SQInteger n=0;\r
277         SQCollectable *tchain=NULL;\r
278 \r
279         RunMark(vm,&tchain);\r
280 \r
281         SQCollectable *resurrected = _gc_chain;\r
282         SQCollectable *t = resurrected;\r
283         //SQCollectable *nx = NULL;\r
284 \r
285         _gc_chain = tchain;\r
286 \r
287         SQArray *ret = NULL;\r
288         if(resurrected) {\r
289                 ret = SQArray::Create(this,0);\r
290                 SQCollectable *rlast = NULL;\r
291                 while(t) {\r
292                         rlast = t;\r
293                         SQObjectType type = t->GetType();\r
294                         if(type != OT_FUNCPROTO && type != OT_OUTER) {\r
295                                 SQObject sqo;\r
296                                 sqo._type = type;\r
297                                 sqo._unVal.pRefCounted = t;\r
298                                 ret->Append(sqo);\r
299                         }\r
300                         t = t->_next;\r
301                         n++;\r
302                 }\r
303 \r
304                 assert(rlast->_next == NULL);\r
305                 rlast->_next = _gc_chain;\r
306                 if(_gc_chain)\r
307                 {\r
308                         _gc_chain->_prev = rlast;\r
309                 }\r
310                 _gc_chain = resurrected;\r
311         }\r
312 \r
313         t = _gc_chain;\r
314         while(t) {\r
315                 t->UnMark();\r
316                 t = t->_next;\r
317         }\r
318 \r
319         if(ret) {\r
320                 SQObjectPtr temp = ret;\r
321                 vm->Push(temp);\r
322         }\r
323         else {\r
324                 vm->PushNull();\r
325         }\r
326         return n;\r
327 }\r
328 \r
329 SQInteger SQSharedState::CollectGarbage(SQVM *vm)\r
330 {\r
331         SQInteger n = 0;\r
332         SQCollectable *tchain = NULL;\r
333 \r
334         RunMark(vm,&tchain);\r
335 \r
336         SQCollectable *t = _gc_chain;\r
337         SQCollectable *nx = NULL;\r
338         if(t) {\r
339                 t->_uiRef++;\r
340                 while(t) {\r
341                         t->Finalize();\r
342                         nx = t->_next;\r
343                         if(nx) nx->_uiRef++;\r
344                         if(--t->_uiRef == 0)\r
345                                 t->Release();\r
346                         t = nx;\r
347                         n++;\r
348                 }\r
349         }\r
350 \r
351         t = tchain;\r
352         while(t) {\r
353                 t->UnMark();\r
354                 t = t->_next;\r
355         }\r
356         _gc_chain = tchain;\r
357         \r
358         return n;\r
359 }\r
360 #endif\r
361 \r
362 #ifndef NO_GARBAGE_COLLECTOR\r
363 void SQCollectable::AddToChain(SQCollectable **chain,SQCollectable *c)\r
364 {\r
365     c->_prev = NULL;\r
366         c->_next = *chain;\r
367         if(*chain) (*chain)->_prev = c;\r
368         *chain = c;\r
369 }\r
370 \r
371 void SQCollectable::RemoveFromChain(SQCollectable **chain,SQCollectable *c)\r
372 {\r
373         if(c->_prev) c->_prev->_next = c->_next;\r
374         else *chain = c->_next;\r
375         if(c->_next)\r
376                 c->_next->_prev = c->_prev;\r
377         c->_next = NULL;\r
378         c->_prev = NULL;\r
379 }\r
380 #endif\r
381 \r
382 SQChar* SQSharedState::GetScratchPad(SQInteger size)\r
383 {\r
384         SQInteger newsize;\r
385         if(size>0) {\r
386                 if(_scratchpadsize < size) {\r
387                         newsize = size + (size>>1);\r
388                         _scratchpad = (SQChar *)SQ_REALLOC(_scratchpad,_scratchpadsize,newsize);\r
389                         _scratchpadsize = newsize;\r
390 \r
391                 }else if(_scratchpadsize >= (size<<5)) {\r
392                         newsize = _scratchpadsize >> 1;\r
393                         _scratchpad = (SQChar *)SQ_REALLOC(_scratchpad,_scratchpadsize,newsize);\r
394                         _scratchpadsize = newsize;\r
395                 }\r
396         }\r
397         return _scratchpad;\r
398 }\r
399 \r
400 RefTable::RefTable()\r
401 {\r
402         AllocNodes(4);\r
403 }\r
404 \r
405 void RefTable::Finalize()\r
406 {\r
407         RefNode *nodes = _nodes;\r
408         for(SQUnsignedInteger n = 0; n < _numofslots; n++) {\r
409                 nodes->obj.Null();\r
410                 nodes++;\r
411         }\r
412 }\r
413 \r
414 RefTable::~RefTable()\r
415 {\r
416         SQ_FREE(_buckets,(_numofslots * sizeof(RefNode *)) + (_numofslots * sizeof(RefNode)));\r
417 }\r
418 \r
419 #ifndef NO_GARBAGE_COLLECTOR\r
420 void RefTable::Mark(SQCollectable **chain)\r
421 {\r
422         RefNode *nodes = (RefNode *)_nodes;\r
423         for(SQUnsignedInteger n = 0; n < _numofslots; n++) {\r
424                 if(type(nodes->obj) != OT_NULL) {\r
425                         SQSharedState::MarkObject(nodes->obj,chain);\r
426                 }\r
427                 nodes++;\r
428         }\r
429 }\r
430 #endif\r
431 \r
432 void RefTable::AddRef(SQObject &obj)\r
433 {\r
434         SQHash mainpos;\r
435         RefNode *prev;\r
436         RefNode *ref = Get(obj,mainpos,&prev,true);\r
437         ref->refs++;\r
438 }\r
439 \r
440 SQUnsignedInteger RefTable::GetRefCount(SQObject &obj)\r
441 {\r
442      SQHash mainpos;\r
443      RefNode *prev;\r
444      RefNode *ref = Get(obj,mainpos,&prev,true);\r
445      return ref->refs;\r
446 }\r
447 \r
448 \r
449 SQBool RefTable::Release(SQObject &obj)\r
450 {\r
451         SQHash mainpos;\r
452         RefNode *prev;\r
453         RefNode *ref = Get(obj,mainpos,&prev,false);\r
454         if(ref) {\r
455                 if(--ref->refs == 0) {\r
456                         SQObjectPtr o = ref->obj;\r
457                         if(prev) {\r
458                                 prev->next = ref->next;\r
459                         }\r
460                         else {\r
461                                 _buckets[mainpos] = ref->next;\r
462                         }\r
463                         ref->next = _freelist;\r
464                         _freelist = ref;\r
465                         _slotused--;\r
466                         ref->obj.Null();\r
467                         //<<FIXME>>test for shrink?\r
468                         return SQTrue;\r
469                 }\r
470         }\r
471         else {\r
472                 assert(0);\r
473         }\r
474         return SQFalse;\r
475 }\r
476 \r
477 void RefTable::Resize(SQUnsignedInteger size)\r
478 {\r
479         RefNode **oldbucks = _buckets;\r
480         RefNode *t = _nodes;\r
481         SQUnsignedInteger oldnumofslots = _numofslots;\r
482         AllocNodes(size);\r
483         //rehash\r
484         SQUnsignedInteger nfound = 0;\r
485         for(SQUnsignedInteger n = 0; n < oldnumofslots; n++) {\r
486                 if(type(t->obj) != OT_NULL) {\r
487                         //add back;\r
488                         assert(t->refs != 0);\r
489                         RefNode *nn = Add(::HashObj(t->obj)&(_numofslots-1),t->obj);\r
490                         nn->refs = t->refs; \r
491                         t->obj.Null();\r
492                         nfound++;\r
493                 }\r
494                 t++;\r
495         }\r
496         assert(nfound == oldnumofslots);\r
497         SQ_FREE(oldbucks,(oldnumofslots * sizeof(RefNode *)) + (oldnumofslots * sizeof(RefNode)));\r
498 }\r
499 \r
500 RefTable::RefNode *RefTable::Add(SQHash mainpos,SQObject &obj)\r
501 {\r
502         RefNode *t = _buckets[mainpos];\r
503         RefNode *newnode = _freelist;\r
504         newnode->obj = obj;\r
505         _buckets[mainpos] = newnode;\r
506         _freelist = _freelist->next;\r
507         newnode->next = t;\r
508         assert(newnode->refs == 0);\r
509         _slotused++;\r
510         return newnode;\r
511 }\r
512 \r
513 RefTable::RefNode *RefTable::Get(SQObject &obj,SQHash &mainpos,RefNode **prev,bool add)\r
514 {\r
515         RefNode *ref;\r
516         mainpos = ::HashObj(obj)&(_numofslots-1);\r
517         *prev = NULL;\r
518         for (ref = _buckets[mainpos]; ref; ) {\r
519                 if(_rawval(ref->obj) == _rawval(obj) && type(ref->obj) == type(obj))\r
520                         break;\r
521                 *prev = ref;\r
522                 ref = ref->next;\r
523         }\r
524         if(ref == NULL && add) {\r
525                 if(_numofslots == _slotused) {\r
526                         assert(_freelist == 0);\r
527                         Resize(_numofslots*2);\r
528                         mainpos = ::HashObj(obj)&(_numofslots-1);\r
529                 }\r
530                 ref = Add(mainpos,obj);\r
531         }\r
532         return ref;\r
533 }\r
534 \r
535 void RefTable::AllocNodes(SQUnsignedInteger size)\r
536 {\r
537         RefNode **bucks;\r
538         RefNode *nodes;\r
539         bucks = (RefNode **)SQ_MALLOC((size * sizeof(RefNode *)) + (size * sizeof(RefNode)));\r
540         nodes = (RefNode *)&bucks[size];\r
541         RefNode *temp = nodes;\r
542         SQUnsignedInteger n;\r
543         for(n = 0; n < size - 1; n++) {\r
544                 bucks[n] = NULL;\r
545                 temp->refs = 0;\r
546                 new (&temp->obj) SQObjectPtr;\r
547                 temp->next = temp+1;\r
548                 temp++;\r
549         }\r
550         bucks[n] = NULL;\r
551         temp->refs = 0;\r
552         new (&temp->obj) SQObjectPtr;\r
553         temp->next = NULL;\r
554         _freelist = nodes;\r
555         _nodes = nodes;\r
556         _buckets = bucks;\r
557         _slotused = 0;\r
558         _numofslots = size;\r
559 }\r
560 //////////////////////////////////////////////////////////////////////////\r
561 //SQStringTable\r
562 /*\r
563 * The following code is based on Lua 4.0 (Copyright 1994-2002 Tecgraf, PUC-Rio.)\r
564 * http://www.lua.org/copyright.html#4\r
565 * http://www.lua.org/source/4.0.1/src_lstring.c.html\r
566 */\r
567 \r
568 SQStringTable::SQStringTable(SQSharedState *ss)\r
569 {\r
570         _sharedstate = ss;\r
571         AllocNodes(4);\r
572         _slotused = 0;\r
573 }\r
574 \r
575 SQStringTable::~SQStringTable()\r
576 {\r
577         SQ_FREE(_strings,sizeof(SQString*)*_numofslots);\r
578         _strings = NULL;\r
579 }\r
580 \r
581 void SQStringTable::AllocNodes(SQInteger size)\r
582 {\r
583         _numofslots = size;\r
584         _strings = (SQString**)SQ_MALLOC(sizeof(SQString*)*_numofslots);\r
585         memset(_strings,0,sizeof(SQString*)*_numofslots);\r
586 }\r
587 \r
588 SQString *SQStringTable::Add(const SQChar *news,SQInteger len)\r
589 {\r
590         if(len<0)\r
591                 len = (SQInteger)scstrlen(news);\r
592         SQHash newhash = ::_hashstr(news,len);\r
593         SQHash h = newhash&(_numofslots-1);\r
594         SQString *s;\r
595         for (s = _strings[h]; s; s = s->_next){\r
596                 if(s->_len == len && (!memcmp(news,s->_val,rsl(len))))\r
597                         return s; //found\r
598         }\r
599 \r
600         SQString *t = (SQString *)SQ_MALLOC(rsl(len)+sizeof(SQString));\r
601         new (t) SQString;\r
602         t->_sharedstate = _sharedstate;\r
603         memcpy(t->_val,news,rsl(len));\r
604         t->_val[len] = _SC('\0');\r
605         t->_len = len;\r
606         t->_hash = newhash;\r
607         t->_next = _strings[h];\r
608         _strings[h] = t;\r
609         _slotused++;\r
610         if (_slotused > _numofslots)  /* too crowded? */\r
611                 Resize(_numofslots*2);\r
612         return t;\r
613 }\r
614 \r
615 void SQStringTable::Resize(SQInteger size)\r
616 {\r
617         SQInteger oldsize=_numofslots;\r
618         SQString **oldtable=_strings;\r
619         AllocNodes(size);\r
620         for (SQInteger i=0; i<oldsize; i++){\r
621                 SQString *p = oldtable[i];\r
622                 while(p){\r
623                         SQString *next = p->_next;\r
624                         SQHash h = p->_hash&(_numofslots-1);\r
625                         p->_next = _strings[h];\r
626                         _strings[h] = p;\r
627                         p = next;\r
628                 }\r
629         }\r
630         SQ_FREE(oldtable,oldsize*sizeof(SQString*));\r
631 }\r
632 \r
633 void SQStringTable::Remove(SQString *bs)\r
634 {\r
635         SQString *s;\r
636         SQString *prev=NULL;\r
637         SQHash h = bs->_hash&(_numofslots - 1);\r
638         \r
639         for (s = _strings[h]; s; ){\r
640                 if(s == bs){\r
641                         if(prev)\r
642                                 prev->_next = s->_next;\r
643                         else\r
644                                 _strings[h] = s->_next;\r
645                         _slotused--;\r
646                         SQInteger slen = s->_len;\r
647                         s->~SQString();\r
648                         SQ_FREE(s,sizeof(SQString) + rsl(slen));\r
649                         return;\r
650                 }\r
651                 prev = s;\r
652                 s = s->_next;\r
653         }\r
654         assert(0);//if this fail something is wrong\r
655 }\r