void PropertyMap::checkConsistency() { if (!_table) return; int count = 0; int sentinelCount = 0; for (int j = 0; j != _table->size; ++j) { UString::Rep *rep = _table->entries[j].key; if (!rep) continue; if (rep == deletedSentinel()) { ++sentinelCount; continue; } unsigned h = rep->hash(); int i = h & _table->sizeMask; int k = 0; while (UString::Rep *key = _table->entries[i].key) { if (rep == key) break; if (k == 0) k = 1 | (h % _table->sizeMask); i = (i + k) & _table->sizeMask; } assert(i == j); ++count; } assert(count == _table->keyCount); assert(sentinelCount == _table->sentinelCount); assert(_table->size >= 16); assert(_table->sizeMask); assert(_table->size == _table->sizeMask + 1); }
PassRefPtr<StringImpl> AtomicString::add(const KJS::UString& ustring) { if (ustring.isNull()) return 0; UString::Rep* string = ustring.rep(); unsigned length = string->size(); if (!length) return StringImpl::empty(); HashAndCharacters buffer = { string->hash(), string->data(), length }; pair<HashSet<StringImpl*>::iterator, bool> addResult = stringTable->add<HashAndCharacters, HashAndCharactersTranslator>(buffer); if (!addResult.second) return *addResult.first; return adoptRef(*addResult.first); }
JSValue *PropertyMap::get(const Identifier &name, unsigned &attributes) const { assert(!name.isNull()); UString::Rep *rep = name._ustring.rep(); if (!_table) { #if USE_SINGLE_ENTRY UString::Rep *key = _singleEntry.key; if (rep == key) { attributes = _singleEntry.attributes; return _singleEntry.value; } #endif return 0; } unsigned h = rep->hash(); int sizeMask = _table->sizeMask; Entry *entries = _table->entries; int i = h & sizeMask; int k = 0; #if DUMP_STATISTICS ++numProbes; numCollisions += entries[i].key && entries[i].key != rep; #endif while (UString::Rep *key = entries[i].key) { if (rep == key) { attributes = entries[i].attributes; return entries[i].value; } if (k == 0) k = 1 | (h % sizeMask); i = (i + k) & sizeMask; #if DUMP_STATISTICS ++numRehashes; #endif } return 0; }
void PropertyMap::remove(const Identifier &name) { assert(!name.isNull()); checkConsistency(); UString::Rep *rep = name._ustring.rep(); UString::Rep *key; if (!_table) { #if USE_SINGLE_ENTRY key = _singleEntry.key; if (rep == key) { key->deref(); _singleEntry.key = 0; checkConsistency(); } #endif return; } // Find the thing to remove. unsigned h = rep->hash(); int sizeMask = _table->sizeMask; Entry *entries = _table->entries; int i = h & sizeMask; int k = 0; #if DUMP_STATISTICS ++numProbes; ++numRemoves; numCollisions += entries[i].key && entries[i].key != rep; #endif while ((key = entries[i].key)) { if (rep == key) break; if (k == 0) k = 1 | (h % sizeMask); i = (i + k) & sizeMask; #if DUMP_STATISTICS ++numRehashes; #endif } if (!key) return; // Replace this one element with the deleted sentinel. Also set value to 0 and attributes to DontEnum // to help callers that iterate all keys not have to check for the sentinel. key->deref(); key = deletedSentinel(); entries[i].key = key; entries[i].value = 0; entries[i].attributes = DontEnum; assert(_table->keyCount >= 1); --_table->keyCount; ++_table->sentinelCount; if (_table->sentinelCount * 4 >= _table->size) rehash(); checkConsistency(); }
void PropertyMap::put(const Identifier &name, JSValue *value, int attributes, bool roCheck) { assert(!name.isNull()); assert(value != 0); checkConsistency(); UString::Rep *rep = name._ustring.rep(); #if DEBUG_PROPERTIES printf("adding property %s, attributes = 0x%08x (", name.ascii(), attributes); printAttributes(attributes); printf(")\n"); #endif #if USE_SINGLE_ENTRY if (!_table) { UString::Rep *key = _singleEntry.key; if (key) { if (rep == key && !(roCheck && (_singleEntry.attributes & ReadOnly))) { _singleEntry.value = value; return; } } else { rep->ref(); _singleEntry.key = rep; _singleEntry.value = value; _singleEntry.attributes = static_cast<short>(attributes); checkConsistency(); return; } } #endif if (!_table || _table->keyCount * 2 >= _table->size) expand(); unsigned h = rep->hash(); int sizeMask = _table->sizeMask; Entry *entries = _table->entries; int i = h & sizeMask; int k = 0; bool foundDeletedElement = false; int deletedElementIndex = 0; /* initialize to make the compiler happy */ #if DUMP_STATISTICS ++numProbes; numCollisions += entries[i].key && entries[i].key != rep; #endif while (UString::Rep *key = entries[i].key) { if (rep == key) { if (roCheck && (_table->entries[i].attributes & ReadOnly)) return; // Put a new value in an existing hash table entry. entries[i].value = value; // Attributes are intentionally not updated. return; } // If we find the deleted-element sentinel, remember it for use later. if (key == deletedSentinel() && !foundDeletedElement) { foundDeletedElement = true; deletedElementIndex = i; } if (k == 0) k = 1 | (h % sizeMask); i = (i + k) & sizeMask; #if DUMP_STATISTICS ++numRehashes; #endif } // Use either the deleted element or the 0 at the end of the chain. if (foundDeletedElement) { i = deletedElementIndex; --_table->sentinelCount; } // Create a new hash table entry. rep->ref(); entries[i].key = rep; entries[i].value = value; entries[i].attributes = static_cast<short>(attributes); entries[i].index = ++_table->lastIndexUsed; ++_table->keyCount; checkConsistency(); }