sqtable.cpp 5.7 KB

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