sqtable.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. /*
  2. see copyright notice in squirrel.h
  3. */
  4. #include "sqpcheader.h"
  5. #include "sqvm.h"
  6. #include "sqtable.h"
  7. #include "sqfuncproto.h"
  8. #include "sqclosure.h"
  9. SQTable::SQTable(SQSharedState *ss,SQInteger nInitialSize):_usednodes(0)
  10. {
  11. SQInteger pow2size=MINPOWER2;
  12. while(nInitialSize>pow2size)pow2size=pow2size<<1;
  13. AllocNodes(pow2size);
  14. _delegate = NULL;
  15. INIT_CHAIN();
  16. ADD_TO_CHAIN(&_sharedstate->_gc_chain,this);
  17. }
  18. void SQTable::Remove(const SQObjectPtr &key)
  19. {
  20. _HashNode *n = _Get(key, HashObj(key) & (_numofnodes - 1));
  21. if (n) {
  22. n->val.Null();
  23. n->key.Null();
  24. _usednodes--;
  25. Rehash(false);
  26. }
  27. }
  28. void SQTable::AllocNodes(SQInteger nSize)
  29. {
  30. _HashNode *nodes=(_HashNode *)SQ_MALLOC(sizeof(_HashNode)*nSize);
  31. for(SQInteger i=0;i<nSize;i++){
  32. _HashNode &n = nodes[i];
  33. new (&n) _HashNode;
  34. n.next=NULL;
  35. }
  36. _numofnodes=nSize;
  37. _nodes=nodes;
  38. _firstfree=&_nodes[_numofnodes-1];
  39. }
  40. void SQTable::Rehash(bool force)
  41. {
  42. SQInteger oldsize=_numofnodes;
  43. //prevent problems with the integer division
  44. if(oldsize<4)oldsize=4;
  45. _HashNode *nold=_nodes;
  46. SQInteger nelems=CountUsed();
  47. if (nelems >= oldsize-oldsize/4) /* using more than 3/4? */
  48. AllocNodes(oldsize*2);
  49. else if (nelems <= oldsize/4 && /* less than 1/4? */
  50. oldsize > MINPOWER2)
  51. AllocNodes(oldsize/2);
  52. else if(force)
  53. AllocNodes(oldsize);
  54. else
  55. return;
  56. _usednodes = 0;
  57. for (SQInteger i=0; i<oldsize; i++) {
  58. _HashNode *old = nold+i;
  59. if (sq_type(old->key) != OT_NULL)
  60. NewSlot(old->key,old->val);
  61. }
  62. for(SQInteger k=0;k<oldsize;k++)
  63. nold[k].~_HashNode();
  64. SQ_FREE(nold,oldsize*sizeof(_HashNode));
  65. }
  66. SQTable *SQTable::Clone()
  67. {
  68. SQTable *nt=Create(_opt_ss(this),_numofnodes);
  69. #ifdef _FAST_CLONE
  70. _HashNode *basesrc = _nodes;
  71. _HashNode *basedst = nt->_nodes;
  72. _HashNode *src = _nodes;
  73. _HashNode *dst = nt->_nodes;
  74. SQInteger n = 0;
  75. for(n = 0; n < _numofnodes; n++) {
  76. dst->key = src->key;
  77. dst->val = src->val;
  78. if(src->next) {
  79. assert(src->next > basesrc);
  80. dst->next = basedst + (src->next - basesrc);
  81. assert(dst != dst->next);
  82. }
  83. dst++;
  84. src++;
  85. }
  86. assert(_firstfree > basesrc);
  87. assert(_firstfree != NULL);
  88. nt->_firstfree = basedst + (_firstfree - basesrc);
  89. nt->_usednodes = _usednodes;
  90. #else
  91. SQInteger ridx=0;
  92. SQObjectPtr key,val;
  93. while((ridx=Next(true,ridx,key,val))!=-1){
  94. nt->NewSlot(key,val);
  95. }
  96. #endif
  97. nt->SetDelegate(_delegate);
  98. return nt;
  99. }
  100. bool SQTable::Get(const SQObjectPtr &key,SQObjectPtr &val)
  101. {
  102. if(sq_type(key) == OT_NULL)
  103. return false;
  104. _HashNode *n = _Get(key, HashObj(key) & (_numofnodes - 1));
  105. if (n) {
  106. val = _realval(n->val);
  107. return true;
  108. }
  109. return false;
  110. }
  111. bool SQTable::Exists(const SQObjectPtr &key)
  112. {
  113. if(sq_type(key) == OT_NULL)
  114. return false;
  115. _HashNode *n = _Get(key, HashObj(key) & (_numofnodes - 1));
  116. return n ? true : false;
  117. }
  118. bool SQTable::NewSlot(const SQObjectPtr &key,const SQObjectPtr &val)
  119. {
  120. assert(sq_type(key) != OT_NULL);
  121. SQHash h = HashObj(key) & (_numofnodes - 1);
  122. _HashNode *n = _Get(key, h);
  123. if (n) {
  124. n->val = val;
  125. return false;
  126. }
  127. _HashNode *mp = &_nodes[h];
  128. //n = mp;
  129. //key not found I'll insert it
  130. //main pos is not free
  131. if(sq_type(mp->key) != OT_NULL) {
  132. n = _firstfree; /* get a free place */
  133. SQHash mph = HashObj(mp->key) & (_numofnodes - 1);
  134. _HashNode *othern; /* main position of colliding node */
  135. if (mp > n && (othern = &_nodes[mph]) != mp){
  136. /* yes; move colliding node into free position */
  137. while (othern->next != mp){
  138. assert(othern->next != NULL);
  139. othern = othern->next; /* find previous */
  140. }
  141. othern->next = n; /* redo the chain with `n' in place of `mp' */
  142. n->key = mp->key;
  143. n->val = mp->val;/* copy colliding node into free pos. (mp->next also goes) */
  144. n->next = mp->next;
  145. mp->key.Null();
  146. mp->val.Null();
  147. mp->next = NULL; /* now `mp' is free */
  148. }
  149. else{
  150. /* new node will go into free position */
  151. n->next = mp->next; /* chain new position */
  152. mp->next = n;
  153. mp = n;
  154. }
  155. }
  156. mp->key = key;
  157. for (;;) { /* correct `firstfree' */
  158. if (sq_type(_firstfree->key) == OT_NULL && _firstfree->next == NULL) {
  159. mp->val = val;
  160. _usednodes++;
  161. return true; /* OK; table still has a free place */
  162. }
  163. else if (_firstfree == _nodes) break; /* cannot decrement from here */
  164. else (_firstfree)--;
  165. }
  166. Rehash(true);
  167. return NewSlot(key, val);
  168. }
  169. SQInteger SQTable::Next(bool getweakrefs,const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval)
  170. {
  171. SQInteger idx = (SQInteger)SQTranslateIndex(refpos);
  172. while (idx < _numofnodes) {
  173. if(sq_type(_nodes[idx].key) != OT_NULL) {
  174. //first found
  175. _HashNode &n = _nodes[idx];
  176. outkey = n.key;
  177. outval = getweakrefs?(SQObject)n.val:_realval(n.val);
  178. //return idx for the next iteration
  179. return ++idx;
  180. }
  181. ++idx;
  182. }
  183. //nothing to iterate anymore
  184. return -1;
  185. }
  186. bool SQTable::Set(const SQObjectPtr &key, const SQObjectPtr &val)
  187. {
  188. _HashNode *n = _Get(key, HashObj(key) & (_numofnodes - 1));
  189. if (n) {
  190. n->val = val;
  191. return true;
  192. }
  193. return false;
  194. }
  195. void SQTable::_ClearNodes()
  196. {
  197. for(SQInteger i = 0;i < _numofnodes; i++) { _HashNode &n = _nodes[i]; n.key.Null(); n.val.Null(); }
  198. }
  199. void SQTable::Finalize()
  200. {
  201. _ClearNodes();
  202. SetDelegate(NULL);
  203. }
  204. void SQTable::Clear()
  205. {
  206. _ClearNodes();
  207. _usednodes = 0;
  208. Rehash(true);
  209. }