2 see copyright notice in squirrel.h
4 #include "sqpcheader.h"
7 #include "sqfuncproto.h"
10 SQTable::SQTable(SQSharedState *ss,int nInitialSize)
12 int pow2size=MINPOWER2;
13 while(nInitialSize>pow2size)pow2size=pow2size<<1;
19 ADD_TO_CHAIN(&_sharedstate->_gc_chain,this);
22 void SQTable::Remove(const SQObjectPtr &key)
24 _HashNode *n = _Get(key, HashKey(key) & (_numofnodes - 1));
26 n->val = n->key = _null_;
32 void SQTable::AllocNodes(int nSize)
34 _HashNode *nodes=(_HashNode *)SQ_MALLOC(sizeof(_HashNode)*nSize);
35 for(int i=0;i<nSize;i++){
36 new (&nodes[i]) _HashNode;
41 _firstfree=&_nodes[_numofnodes-1];
44 int SQTable::CountUsed()
47 for(int i=0;i<_numofnodes;i++){
48 if(type(_nodes[i].key)!=OT_NULL) n++;
53 void SQTable::Rehash(bool force)
55 int oldsize=_numofnodes;
56 //prevent problems with the integer division
57 if(oldsize<4)oldsize=4;
58 _HashNode *nold=_nodes;
59 int nelems=CountUsed();
60 if (nelems >= oldsize-oldsize/4) /* using more than 3/4? */
61 AllocNodes(oldsize*2);
62 else if (nelems <= oldsize/4 && /* less than 1/4? */
64 AllocNodes(oldsize/2);
70 for (int i=0; i<oldsize; i++) {
71 _HashNode *old = nold+i;
72 if (type(old->key) != OT_NULL)
73 NewSlot(old->key,old->val);
75 for(int k=0;k<oldsize;k++)
77 SQ_FREE(nold,oldsize*sizeof(_HashNode));
80 SQTable *SQTable::Clone()
82 SQTable *nt=Create(_opt_ss(this),_numofnodes);
85 while((ridx=Next(ridx,key,val))!=-1){
88 nt->SetDelegate(_delegate);
92 bool SQTable::Get(const SQObjectPtr &key,SQObjectPtr &val)
94 _HashNode *n = _Get(key, HashKey(key) & (_numofnodes - 1));
101 bool SQTable::NewSlot(const SQObjectPtr &key,const SQObjectPtr &val)
103 unsigned long h = HashKey(key) & (_numofnodes - 1);
104 _HashNode *n = _Get(key, h);
109 _HashNode *mp = &_nodes[h];
112 //key not found I'll insert it
113 //main pos is not free
115 if(type(mp->key)!=OT_NULL) {
117 _HashNode *othern; /* main position of colliding node */
118 n = _firstfree; /* get a free place */
119 if (mp > n && (othern = &_nodes[h]) != mp){
120 /* yes; move colliding node into free position */
121 while (othern->next != mp)
122 othern = othern->next; /* find previous */
123 othern->next = n; /* redo the chain with `n' in place of `mp' */
124 *n = *mp; /* copy colliding node into free pos. (mp->next also goes) */
125 mp->next = NULL; /* now `mp' is free */
128 /* new node will go into free position */
129 n->next = mp->next; /* chain new position */
136 for (;;) { /* correct `firstfree' */
137 if (type(_firstfree->key) == OT_NULL) {
140 return true; /* OK; table still has a free place */
142 else if (_firstfree == _nodes) break; /* cannot decrement from here */
146 return NewSlot(key, val);
149 int SQTable::Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval)
151 int idx = (int)TranslateIndex(refpos);
152 while (idx < _numofnodes) {
153 if(type(_nodes[idx].key) != OT_NULL) {
155 outkey = _nodes[idx].key;
156 outval = _nodes[idx].val;
157 //return idx for the next iteration
162 //nothing to iterate anymore
166 bool SQTable::SetDelegate(SQTable *mt)
170 if (temp->_delegate == this) return false; //cycle detected
171 temp = temp->_delegate;
173 if (mt) __ObjAddRef(mt);
174 __ObjRelease(_delegate);
179 bool SQTable::Set(const SQObjectPtr &key, const SQObjectPtr &val)
181 _HashNode *n = _Get(key, HashKey(key) & (_numofnodes - 1));
189 void SQTable::Finalize()
191 for(int i = 0;i < _numofnodes; i++) { _nodes[i].key = _null_; _nodes[i].val = _null_; }