sqstate.cpp 19 KB

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