sqtable.cpp

00001 /*
00002 see copyright notice in squirrel.h
00003 */
00004 #include "sqpcheader.h"
00005 #include "sqvm.h"
00006 #include "sqtable.h"
00007 #include "sqfuncproto.h"
00008 #include "sqclosure.h"
00009 
00010 SQTable::SQTable(SQSharedState *ss,SQInteger nInitialSize)
00011 {
00012   SQInteger pow2size=MINPOWER2;
00013   while(nInitialSize>pow2size)pow2size=pow2size<<1;
00014   AllocNodes(pow2size);
00015   _usednodes = 0;
00016   _delegate = NULL;
00017   INIT_CHAIN();
00018   ADD_TO_CHAIN(&_sharedstate->_gc_chain,this);
00019 }
00020 
00021 void SQTable::Remove(const SQObjectPtr &key)
00022 {
00023 
00024   _HashNode *n = _Get(key, HashObj(key) & (_numofnodes - 1));
00025   if (n) {
00026     n->val = n->key = _null_;
00027     _usednodes--;
00028     Rehash(false);
00029   }
00030 }
00031 
00032 void SQTable::AllocNodes(SQInteger nSize)
00033 {
00034   _HashNode *nodes=(_HashNode *)SQ_MALLOC(sizeof(_HashNode)*nSize);
00035   for(SQInteger i=0;i<nSize;i++){
00036     new (&nodes[i]) _HashNode;
00037     nodes[i].next=NULL;
00038   }
00039   _numofnodes=nSize;
00040   _nodes=nodes;
00041   _firstfree=&_nodes[_numofnodes-1];
00042 }
00043 
00044 void SQTable::Rehash(bool force)
00045 {
00046   SQInteger oldsize=_numofnodes;
00047   //prevent problems with the integer division
00048   if(oldsize<4)oldsize=4;
00049   _HashNode *nold=_nodes;
00050   SQInteger nelems=CountUsed();
00051   if (nelems >= oldsize-oldsize/4)  /* using more than 3/4? */
00052     AllocNodes(oldsize*2);
00053   else if (nelems <= oldsize/4 &&  /* less than 1/4? */
00054     oldsize > MINPOWER2)
00055     AllocNodes(oldsize/2);
00056   else if(force)
00057     AllocNodes(oldsize);
00058   else
00059     return;
00060   _usednodes = 0;
00061   for (SQInteger i=0; i<oldsize; i++) {
00062     _HashNode *old = nold+i;
00063     if (type(old->key) != OT_NULL)
00064       NewSlot(old->key,old->val);
00065   }
00066   for(SQInteger k=0;k<oldsize;k++)
00067     nold[k].~_HashNode();
00068   SQ_FREE(nold,oldsize*sizeof(_HashNode));
00069 }
00070 
00071 SQTable *SQTable::Clone()
00072 {
00073   SQTable *nt=Create(_opt_ss(this),_numofnodes);
00074   SQInteger ridx=0;
00075   SQObjectPtr key,val;
00076   while((ridx=Next(true,ridx,key,val))!=-1){
00077     nt->NewSlot(key,val);
00078   }
00079   nt->SetDelegate(_delegate);
00080   return nt;
00081 }
00082 
00083 bool SQTable::Get(const SQObjectPtr &key,SQObjectPtr &val)
00084 {
00085   if(type(key) == OT_NULL)
00086     return false;
00087   _HashNode *n = _Get(key, HashObj(key) & (_numofnodes - 1));
00088   if (n) {
00089     val = _realval(n->val);
00090     return true;
00091   }
00092   return false;
00093 }
00094 bool SQTable::NewSlot(const SQObjectPtr &key,const SQObjectPtr &val)
00095 {
00096   assert(type(key) != OT_NULL);
00097   SQHash h = HashObj(key) & (_numofnodes - 1);
00098   _HashNode *n = _Get(key, h);
00099   if (n) {
00100     n->val = val;
00101     return false;
00102   }
00103   _HashNode *mp = &_nodes[h];
00104   n = mp;
00105 
00106 
00107   //key not found I'll insert it
00108   //main pos is not free
00109 
00110   if(type(mp->key) != OT_NULL) {
00111     n = _firstfree;  /* get a free place */
00112     SQHash mph = HashObj(mp->key) & (_numofnodes - 1);
00113     _HashNode *othern;  /* main position of colliding node */
00114 
00115     if (mp > n && (othern = &_nodes[mph]) != mp){
00116       /* yes; move colliding node into free position */
00117       while (othern->next != mp){
00118         assert(othern->next != NULL);
00119         othern = othern->next;  /* find previous */
00120       }
00121       othern->next = n;  /* redo the chain with `n' in place of `mp' */
00122       n->key = mp->key;
00123       n->val = mp->val;/* copy colliding node into free pos. (mp->next also goes) */
00124       n->next = mp->next;
00125       mp->key = _null_;
00126       mp->val = _null_;
00127       mp->next = NULL;  /* now `mp' is free */
00128     }
00129     else{
00130       /* new node will go into free position */
00131       n->next = mp->next;  /* chain new position */
00132       mp->next = n;
00133       mp = n;
00134     }
00135   }
00136   mp->key = key;
00137 
00138   for (;;) {  /* correct `firstfree' */
00139     if (type(_firstfree->key) == OT_NULL && _firstfree->next == NULL) {
00140       mp->val = val;
00141       _usednodes++;
00142       return true;  /* OK; table still has a free place */
00143     }
00144     else if (_firstfree == _nodes) break;  /* cannot decrement from here */
00145     else (_firstfree)--;
00146   }
00147   Rehash(true);
00148   return NewSlot(key, val);
00149 }
00150 
00151 SQInteger SQTable::Next(bool getweakrefs,const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval)
00152 {
00153   SQInteger idx = (SQInteger)TranslateIndex(refpos);
00154   while (idx < _numofnodes) {
00155     if(type(_nodes[idx].key) != OT_NULL) {
00156       //first found
00157       _HashNode &n = _nodes[idx];
00158       outkey = n.key;
00159       outval = getweakrefs?(SQObject)n.val:_realval(n.val);
00160       //return idx for the next iteration
00161       return ++idx;
00162     }
00163     ++idx;
00164   }
00165   //nothing to iterate anymore
00166   return -1;
00167 }
00168 
00169 
00170 bool SQTable::Set(const SQObjectPtr &key, const SQObjectPtr &val)
00171 {
00172   _HashNode *n = _Get(key, HashObj(key) & (_numofnodes - 1));
00173   if (n) {
00174     n->val = val;
00175     return true;
00176   }
00177   return false;
00178 }
00179 
00180 void SQTable::_ClearNodes()
00181 {
00182   for(SQInteger i = 0;i < _numofnodes; i++) { _nodes[i].key = _null_; _nodes[i].val = _null_; }
00183 }
00184 
00185 void SQTable::Finalize()
00186 {
00187   _ClearNodes();
00188   SetDelegate(NULL);
00189 }
00190 
00191 void SQTable::Clear()
00192 {
00193   _ClearNodes();
00194   _usednodes = 0;
00195   Rehash(true);
00196 }

Generated on Thu Oct 1 11:03:11 2009 for OpenTTD by  doxygen 1.5.6