Пример #1
0
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);
}
Пример #2
0
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);
}
Пример #3
0
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;
}
Пример #4
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();
}
Пример #5
0
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();
}