2
0

sqtable.cpp 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  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::Exists(const SQObjectPtr &key)
  113. {
  114. if(type(key) == OT_NULL)
  115. return false;
  116. _HashNode *n = _Get(key, HashObj(key) & (_numofnodes - 1));
  117. return n ? true : false;
  118. }
  119. bool SQTable::NewSlot(const SQObjectPtr &key,const SQObjectPtr &val)
  120. {
  121. assert(type(key) != OT_NULL);
  122. SQHash h = HashObj(key) & (_numofnodes - 1);
  123. _HashNode *n = _Get(key, h);
  124. if (n) {
  125. n->val = val;
  126. return false;
  127. }
  128. _HashNode *mp = &_nodes[h];
  129. //n = mp;
  130. //key not found I'll insert it
  131. //main pos is not free
  132. if(type(mp->key) != OT_NULL) {
  133. n = _firstfree; /* get a free place */
  134. SQHash mph = HashObj(mp->key) & (_numofnodes - 1);
  135. _HashNode *othern; /* main position of colliding node */
  136. if (mp > n && (othern = &_nodes[mph]) != mp){
  137. /* yes; move colliding node into free position */
  138. while (othern->next != mp){
  139. assert(othern->next != NULL);
  140. othern = othern->next; /* find previous */
  141. }
  142. othern->next = n; /* redo the chain with `n' in place of `mp' */
  143. n->key = mp->key;
  144. n->val = mp->val;/* copy colliding node into free pos. (mp->next also goes) */
  145. n->next = mp->next;
  146. mp->key.Null();
  147. mp->val.Null();
  148. mp->next = NULL; /* now `mp' is free */
  149. }
  150. else{
  151. /* new node will go into free position */
  152. n->next = mp->next; /* chain new position */
  153. mp->next = n;
  154. mp = n;
  155. }
  156. }
  157. mp->key = key;
  158. for (;;) { /* correct `firstfree' */
  159. if (type(_firstfree->key) == OT_NULL && _firstfree->next == NULL) {
  160. mp->val = val;
  161. _usednodes++;
  162. return true; /* OK; table still has a free place */
  163. }
  164. else if (_firstfree == _nodes) break; /* cannot decrement from here */
  165. else (_firstfree)--;
  166. }
  167. Rehash(true);
  168. return NewSlot(key, val);
  169. }
  170. SQInteger SQTable::Next(bool getweakrefs,const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval)
  171. {
  172. SQInteger idx = (SQInteger)TranslateIndex(refpos);
  173. while (idx < _numofnodes) {
  174. if(type(_nodes[idx].key) != OT_NULL) {
  175. //first found
  176. _HashNode &n = _nodes[idx];
  177. outkey = n.key;
  178. outval = getweakrefs?(SQObject)n.val:_realval(n.val);
  179. //return idx for the next iteration
  180. return ++idx;
  181. }
  182. ++idx;
  183. }
  184. //nothing to iterate anymore
  185. return -1;
  186. }
  187. bool SQTable::Set(const SQObjectPtr &key, const SQObjectPtr &val)
  188. {
  189. _HashNode *n = _Get(key, HashObj(key) & (_numofnodes - 1));
  190. if (n) {
  191. n->val = val;
  192. return true;
  193. }
  194. return false;
  195. }
  196. void SQTable::_ClearNodes()
  197. {
  198. for(SQInteger i = 0;i < _numofnodes; i++) { _HashNode &n = _nodes[i]; n.key.Null(); n.val.Null(); }
  199. }
  200. void SQTable::Finalize()
  201. {
  202. _ClearNodes();
  203. SetDelegate(NULL);
  204. }
  205. void SQTable::Clear()
  206. {
  207. _ClearNodes();
  208. _usednodes = 0;
  209. Rehash(true);
  210. }