sqstate.cpp 18 KB

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