bool SQTable::NewSlot(const SQObjectPtr &key,const SQObjectPtr &val) { assert(sqtype(key) != OT_NULL); SQHash h = HashObj(key) & (_numofnodes - 1); _HashNode *n = _Get(key, h); if (n) { n->val = val; return false; } _HashNode *mp = &_nodes[h]; n = mp; //key not found I'll insert it //main pos is not free if(sqtype(mp->key) != OT_NULL) { n = _firstfree; /* get a free place */ SQHash mph = HashObj(mp->key) & (_numofnodes - 1); _HashNode *othern; /* main position of colliding node */ if (mp > n && (othern = &_nodes[mph]) != mp){ /* yes; move colliding node into free position */ while (othern->next != mp){ assert(othern->next != NULL); othern = othern->next; /* find previous */ } othern->next = n; /* redo the chain with `n' in place of `mp' */ n->key = mp->key; n->val = mp->val;/* copy colliding node into free pos. (mp->next also goes) */ n->next = mp->next; mp->key.Null(); mp->val.Null(); mp->next = NULL; /* now `mp' is free */ } else{ /* new node will go into free position */ n->next = mp->next; /* chain new position */ mp->next = n; mp = n; } } mp->key = key; for (;;) { /* correct `firstfree' */ if (sqtype(_firstfree->key) == OT_NULL && _firstfree->next == NULL) { mp->val = val; _usednodes++; return true; /* OK; table still has a free place */ } else if (_firstfree == _nodes) break; /* cannot decrement from here */ else (_firstfree)--; } Rehash(true); return NewSlot(key, val); }
void SQTable::Rehash(bool force) { SQInteger oldsize=_numofnodes; //prevent problems with the integer division if(oldsize<4)oldsize=4; _HashNode *nold=_nodes; SQInteger nelems=CountUsed(); if (nelems >= oldsize-oldsize/4) /* using more than 3/4? */ AllocNodes(oldsize*2); else if (nelems <= oldsize/4 && /* less than 1/4? */ oldsize > MINPOWER2) AllocNodes(oldsize/2); else if(force) AllocNodes(oldsize); else return; _usednodes = 0; for (SQInteger i=0; i<oldsize; i++) { _HashNode *old = nold+i; if (sqtype(old->key) != OT_NULL) NewSlot(old->key,old->val); } for(SQInteger k=0;k<oldsize;k++) nold[k].~_HashNode(); SQ_FREE(nold,oldsize*sizeof(_HashNode)); }
bool SQInstance::GetMetaMethod(SQVM SQ_UNUSED_ARG(*v),SQMetaMethod mm,SQObjectPtr &res) { if(sqtype(_class->_metamethods[mm]) != OT_NULL) { res = _class->_metamethods[mm]; return true; } return false; }
bool SQTable::Get(const SQObjectPtr &key,SQObjectPtr &val) { if(sqtype(key) == OT_NULL) return false; _HashNode *n = _Get(key, HashObj(key) & (_numofnodes - 1)); if (n) { val = _realval(n->val); return true; } return false; }
SQInteger SQTable::Next(bool getweakrefs,const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval) { SQInteger idx = (SQInteger)TranslateIndex(refpos); while (idx < _numofnodes) { if(sqtype(_nodes[idx].key) != OT_NULL) { //first found _HashNode &n = _nodes[idx]; outkey = n.key; outval = getweakrefs?(SQObject)n.val:_realval(n.val); //return idx for the next iteration return ++idx; } ++idx; } //nothing to iterate anymore return -1; }
bool SQClass::NewSlot(SQSharedState *ss,const SQObjectPtr &key,const SQObjectPtr &val,bool bstatic) { SQObjectPtr temp; bool belongs_to_static_table = sqtype(val) == OT_CLOSURE || sqtype(val) == OT_NATIVECLOSURE || bstatic; if(_locked && !belongs_to_static_table) return false; //the class already has an instance so cannot be modified if(_members->Get(key,temp) && _isfield(temp)) //overrides the default value { _defaultvalues[_member_idx(temp)].val = val; return true; } if(belongs_to_static_table) { SQInteger mmidx; if((sqtype(val) == OT_CLOSURE || sqtype(val) == OT_NATIVECLOSURE) && (mmidx = ss->GetMetaMethodIdxByName(key)) != -1) { _metamethods[mmidx] = val; } else { SQObjectPtr theval = val; if(_base && sqtype(val) == OT_CLOSURE) { theval = _closure(val)->Clone(); _closure(theval)->_base = _base; __ObjAddRef(_base); //ref for the closure } if(sqtype(temp) == OT_NULL) { bool isconstructor; SQVM::IsEqual(ss->_constructoridx, key, isconstructor); if(isconstructor) { _constructoridx = (SQInteger)_methods.size(); } SQClassMember m; m.val = theval; _members->NewSlot(key,SQObjectPtr(_make_method_idx(_methods.size()))); _methods.push_back(m); } else { _methods[_member_idx(temp)].val = theval; } } return true; } SQClassMember m; m.val = val; _members->NewSlot(key,SQObjectPtr(_make_field_idx(_defaultvalues.size()))); _defaultvalues.push_back(m); return true; }