sqtable.cpp
00001
00002
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
00048 if(oldsize<4)oldsize=4;
00049 _HashNode *nold=_nodes;
00050 SQInteger nelems=CountUsed();
00051 if (nelems >= oldsize-oldsize/4)
00052 AllocNodes(oldsize*2);
00053 else if (nelems <= oldsize/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
00108
00109
00110 if(type(mp->key) != OT_NULL) {
00111 n = _firstfree;
00112 SQHash mph = HashObj(mp->key) & (_numofnodes - 1);
00113 _HashNode *othern;
00114
00115 if (mp > n && (othern = &_nodes[mph]) != mp){
00116
00117 while (othern->next != mp){
00118 assert(othern->next != NULL);
00119 othern = othern->next;
00120 }
00121 othern->next = n;
00122 n->key = mp->key;
00123 n->val = mp->val;
00124 n->next = mp->next;
00125 mp->key = _null_;
00126 mp->val = _null_;
00127 mp->next = NULL;
00128 }
00129 else{
00130
00131 n->next = mp->next;
00132 mp->next = n;
00133 mp = n;
00134 }
00135 }
00136 mp->key = key;
00137
00138 for (;;) {
00139 if (type(_firstfree->key) == OT_NULL && _firstfree->next == NULL) {
00140 mp->val = val;
00141 _usednodes++;
00142 return true;
00143 }
00144 else if (_firstfree == _nodes) break;
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
00157 _HashNode &n = _nodes[idx];
00158 outkey = n.key;
00159 outval = getweakrefs?(SQObject)n.val:_realval(n.val);
00160
00161 return ++idx;
00162 }
00163 ++idx;
00164 }
00165
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 }