property_map.cpp

来自「konqueror3 embedded版本, KDE环境下的当家浏览器的嵌入式版」· C++ 代码 · 共 534 行

CPP
534
字号
/* *  This file is part of the KDE libraries *  Copyright (C) 2003 Apple Computer, Inc. * *  This library is free software; you can redistribute it and/or *  modify it under the terms of the GNU Library General Public *  License as published by the Free Software Foundation; either *  version 2 of the License, or (at your option) any later version. * *  This library is distributed in the hope that it will be useful, *  but WITHOUT ANY WARRANTY; without even the implied warranty of *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU *  Library General Public License for more details. * *  You should have received a copy of the GNU Library General Public License *  along with this library; see the file COPYING.LIB.  If not, write to *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, *  Boston, MA 02110-1301, USA. * */#include "property_map.h"#include "object.h"#include "reference_list.h"#include <assert.h>#define DEBUG_PROPERTIES 0#define DO_CONSISTENCY_CHECK 0#define DUMP_STATISTICS 0#define USE_SINGLE_ENTRY 1// At the time I added USE_SINGLE_ENTRY, the optimization still gave a 1.5%// performance boost to the iBench JavaScript benchmark so I didn't remove it.#if !DO_CONSISTENCY_CHECK#define checkConsistency() ((void)0)#endifnamespace KJS {#if DUMP_STATISTICSstatic int numProbes;static int numCollisions;struct PropertyMapStatisticsExitLogger { ~PropertyMapStatisticsExitLogger(); };static PropertyMapStatisticsExitLogger logger;PropertyMapStatisticsExitLogger::~PropertyMapStatisticsExitLogger(){    printf("\nKJS::PropertyMap statistics\n\n");    printf("%d probes\n", numProbes);    printf("%d collisions (%.1f%%)\n", numCollisions, 100.0 * numCollisions / numProbes);}#endifstruct PropertyMapHashTable{    int sizeMask;    int size;    int keyCount;    PropertyMapHashTableEntry entries[1];};class SavedProperty {public:    Identifier key;    Value value;    int attributes;};SavedProperties::SavedProperties() : _count(0), _properties(0) { }SavedProperties::~SavedProperties(){    delete [] _properties;}// Algorithm concepts from Algorithms in C++, Sedgewick.PropertyMap::PropertyMap() : _table(0){}PropertyMap::~PropertyMap(){    if (!_table) {#if USE_SINGLE_ENTRY        UString::Rep *key = _singleEntry.key;        if (key)            key->deref();#endif        return;    }    for (int i = 0; i < _table->size; i++) {        UString::Rep *key = _table->entries[i].key;        if (key)	  key->deref();    }    free(_table);}void PropertyMap::clear(){    if (!_table) {#if USE_SINGLE_ENTRY        UString::Rep *key = _singleEntry.key;        if (key) {            key->deref();            _singleEntry.key = 0;        }#endif        return;    }    for (int i = 0; i < _table->size; i++) {        UString::Rep *key = _table->entries[i].key;        if (key) {            key->deref();            _table->entries[i].key = 0;        }    }    _table->keyCount = 0;}inline int PropertyMap::hash(const UString::Rep *s) const{    return s->hash() & _table->sizeMask;}ValueImp *PropertyMap::get(const Identifier &name, int &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;    }    int i = hash(rep);#if DUMP_STATISTICS    ++numProbes;    numCollisions += _table->entries[i].key && _table->entries[i].key != rep;#endif    while (UString::Rep *key = _table->entries[i].key) {        if (rep == key) {            attributes = _table->entries[i].attributes;            return _table->entries[i].value;        }        i = (i + 1) & _table->sizeMask;    }    return 0;}ValueImp *PropertyMap::get(const Identifier &name) const{    assert(!name.isNull());    UString::Rep *rep = name._ustring.rep;    if (!_table) {#if USE_SINGLE_ENTRY        UString::Rep *key = _singleEntry.key;        if (rep == key)            return _singleEntry.value;#endif        return 0;    }    int i = hash(rep);#if DUMP_STATISTICS    ++numProbes;    numCollisions += _table->entries[i].key && _table->entries[i].key != rep;#endif    while (UString::Rep *key = _table->entries[i].key) {        if (rep == key)            return _table->entries[i].value;        i = (i + 1) & _table->sizeMask;    }    return 0;}#if DEBUG_PROPERTIESstatic void printAttributes(int attributes){    if (attributes == 0)        printf ("None ");    if (attributes & ReadOnly)        printf ("ReadOnly ");    if (attributes & DontEnum)        printf ("DontEnum ");    if (attributes & DontDelete)        printf ("DontDelete ");    if (attributes & Internal)        printf ("Internal ");    if (attributes & Function)        printf ("Function ");}#endifvoid PropertyMap::put(const Identifier &name, ValueImp *value, int attributes){    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) {                _singleEntry.value = value;                return;            }        } else {            rep->ref();            _singleEntry.key = rep;            _singleEntry.value = value;            _singleEntry.attributes = attributes;            checkConsistency();            return;        }    }#endif    if (!_table || _table->keyCount * 2 >= _table->size)        expand();    int i = hash(rep);#if DUMP_STATISTICS    ++numProbes;    numCollisions += _table->entries[i].key && _table->entries[i].key != rep;#endif    while (UString::Rep *key = _table->entries[i].key) {        if (rep == key) {            // Put a new value in an existing hash table entry.            _table->entries[i].value = value;            // Attributes are intentionally not updated.            return;        }        i = (i + 1) & _table->sizeMask;    }    // Create a new hash table entry.    rep->ref();    _table->entries[i].key = rep;    _table->entries[i].value = value;    _table->entries[i].attributes = attributes;    ++_table->keyCount;    checkConsistency();}inline void PropertyMap::insert(UString::Rep *key, ValueImp *value, int attributes){    assert(_table);    int i = hash(key);#if DUMP_STATISTICS    ++numProbes;    numCollisions += _table->entries[i].key && _table->entries[i].key != key;#endif    while (_table->entries[i].key)        i = (i + 1) & _table->sizeMask;    _table->entries[i].key = key;    _table->entries[i].value = value;    _table->entries[i].attributes = attributes;}void PropertyMap::expand(){    checkConsistency();    Table *oldTable = _table;    int oldTableSize = oldTable ? oldTable->size : 0;    int newTableSize = oldTableSize ? oldTableSize * 2 : 16;    _table = (Table *)calloc(1, sizeof(Table) + (newTableSize - 1) * sizeof(Entry) );    _table->size = newTableSize;    _table->sizeMask = newTableSize - 1;    _table->keyCount = oldTable ? oldTable->keyCount : 0;#if USE_SINGLE_ENTRY    UString::Rep *key = _singleEntry.key;    if (key) {        insert(key, _singleEntry.value, _singleEntry.attributes);	_table->keyCount++;        _singleEntry.key = 0;    }#endif    for (int i = 0; i != oldTableSize; ++i) {        UString::Rep *key = oldTable->entries[i].key;        if (key)            insert(key, oldTable->entries[i].value, oldTable->entries[i].attributes);    }    free(oldTable);    checkConsistency();}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.    int i = hash(rep);#if DUMP_STATISTICS    ++numProbes;    numCollisions += _table->entries[i].key && _table->entries[i].key != rep;#endif    while ((key = _table->entries[i].key)) {        if (rep == key)            break;        i = (i + 1) & _table->sizeMask;    }    if (!key)        return;    // Remove the one key.    key->deref();    _table->entries[i].key = 0;    assert(_table->keyCount >= 1);    --_table->keyCount;    // Reinsert all the items to the right in the same cluster.    while (1) {        i = (i + 1) & _table->sizeMask;        key = _table->entries[i].key;        if (!key)            break;        _table->entries[i].key = 0;        insert(key, _table->entries[i].value, _table->entries[i].attributes);    }    checkConsistency();}void PropertyMap::mark() const{    if (!_table) {#if USE_SINGLE_ENTRY        if (_singleEntry.key) {            ValueImp *v = _singleEntry.value;            if (!v->marked())                v->mark();        }#endif        return;    }    for (int i = 0; i != _table->size; ++i) {        if (_table->entries[i].key) {            ValueImp *v = _table->entries[i].value;            if (!v->marked())                v->mark();        }    }}void PropertyMap::addEnumerablesToReferenceList(ReferenceList &list, const Object &base) const{    if (!_table) {#if USE_SINGLE_ENTRY        UString::Rep *key = _singleEntry.key;        if (key && !(_singleEntry.attributes & DontEnum))            list.append(Reference(base, Identifier(key)));#endif        return;    }    for (int i = 0; i != _table->size; ++i) {        UString::Rep *key = _table->entries[i].key;        if (key && !(_table->entries[i].attributes & DontEnum))            list.append(Reference(base, Identifier(key)));    }}void PropertyMap::addSparseArrayPropertiesToReferenceList(ReferenceList &list, const Object &base) const{    if (!_table) {#if USE_SINGLE_ENTRY        UString::Rep *key = _singleEntry.key;        if (key) {            UString k(key);            bool fitsInULong;            unsigned long i = k.toULong(&fitsInULong);            if (fitsInULong && i <= 0xFFFFFFFFU)                list.append(Reference(base, Identifier(key)));        }#endif        return;    }    for (int i = 0; i != _table->size; ++i) {        UString::Rep *key = _table->entries[i].key;        if (key) {            UString k(key);            bool fitsInULong;            unsigned long i = k.toULong(&fitsInULong);            if (fitsInULong && i <= 0xFFFFFFFFU)                list.append(Reference(base, Identifier(key)));        }    }}void PropertyMap::save(SavedProperties &p) const{    int count = 0;    if (!_table) {#if USE_SINGLE_ENTRY        if (_singleEntry.key && !(_singleEntry.attributes & (ReadOnly | DontEnum | Function)))            ++count;#endif    } else {        for (int i = 0; i != _table->size; ++i)            if (_table->entries[i].key && !(_table->entries[i].attributes & (ReadOnly | DontEnum | Function)))                ++count;    }    delete [] p._properties;    p._count = count;    if (count == 0) {        p._properties = 0;        return;    }    p._properties = new SavedProperty [count];    SavedProperty *prop = p._properties;    if (!_table) {#if USE_SINGLE_ENTRY        if (_singleEntry.key && !(_singleEntry.attributes & (ReadOnly | DontEnum | Function))) {            prop->key = Identifier(_singleEntry.key);            prop->value = Value(_singleEntry.value);            prop->attributes = _singleEntry.attributes;            ++prop;        }#endif    } else {        for (int i = 0; i != _table->size; ++i) {            if (_table->entries[i].key && !(_table->entries[i].attributes & (ReadOnly | DontEnum | Function))) {                prop->key = Identifier(_table->entries[i].key);                prop->value = Value(_table->entries[i].value);                prop->attributes = _table->entries[i].attributes;                ++prop;            }        }    }}void PropertyMap::restore(const SavedProperties &p){    for (int i = 0; i != p._count; ++i)        put(p._properties[i].key, p._properties[i].value.imp(), p._properties[i].attributes);}#if DO_CONSISTENCY_CHECKvoid PropertyMap::checkConsistency(){    if (!_table)        return;    int count = 0;    for (int j = 0; j != _table->size; ++j) {        UString::Rep *rep = _table->entries[j].key;        if (!rep)            continue;        int i = hash(rep);        while (UString::Rep *key = _table->entries[i].key) {            if (rep == key)                break;            i = (i + 1) & _table->sizeMask;        }        assert(i == j);        count++;    }    assert(count == _table->keyCount);    assert(_table->size >= 16);    assert(_table->sizeMask);    assert(_table->size == _table->sizeMask + 1);}#endif // DO_CONSISTENCY_CHECK} // namespace KJS

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?