22 #include "property_map.h"
25 #include "reference_list.h"
29 #define DEBUG_PROPERTIES 0
30 #define DO_CONSISTENCY_CHECK 0
31 #define DUMP_STATISTICS 0
32 #define USE_SINGLE_ENTRY 1
37 #if !DO_CONSISTENCY_CHECK
38 #define checkConsistency() ((void)0)
46 static int numCollisions;
48 struct PropertyMapStatisticsExitLogger { ~PropertyMapStatisticsExitLogger(); };
50 static PropertyMapStatisticsExitLogger logger;
52 PropertyMapStatisticsExitLogger::~PropertyMapStatisticsExitLogger()
54 printf(
"\nKJS::PropertyMap statistics\n\n");
55 printf(
"%d probes\n", numProbes);
56 printf(
"%d collisions (%.1f%%)\n", numCollisions, 100.0 * numCollisions / numProbes);
61 struct PropertyMapHashTable
73 PropertyMapHashTableEntry entries[1];
83 SavedProperties::SavedProperties() : _count(0), _properties(0) { }
85 SavedProperties::~SavedProperties()
87 delete [] _properties;
92 PropertyMap::PropertyMap() : _table(0)
96 PropertyMap::~PropertyMap()
100 UString::Rep *
key = _singleEntry.key;
107 for (
int i = 0; i < _table->size; i++) {
108 UString::Rep *
key = _table->entries[i].key;
114 delete [] _table->hashToIndex;
119 void PropertyMap::clear()
123 UString::Rep *
key = _singleEntry.key;
126 _singleEntry.key = 0;
132 for (
int i = 0; i < _table->size; i++) {
133 UString::Rep *
key = _table->entries[i].key;
136 _table->entries[i].key = 0;
139 _table->keyCount = 0;
142 inline int PropertyMap::hash(
const UString::Rep *s)
const
144 return s->hash() & _table->sizeMask;
147 ValueImp *PropertyMap::get(
const Identifier &name,
int &attributes)
const
149 assert(!
name.isNull());
151 UString::Rep *rep =
name._ustring.rep;
155 UString::Rep *
key = _singleEntry.key;
157 attributes = _singleEntry.attributes;
158 return _singleEntry.value;
167 numCollisions += _table->entries[i].key && _table->entries[i].key != rep;
169 while (UString::Rep *key = _table->entries[i].key) {
171 attributes = _table->entries[i].attributes;
172 return _table->entries[i].value;
174 i = (i + 1) & _table->sizeMask;
179 ValueImp *PropertyMap::get(
const Identifier &name)
const
181 assert(!
name.isNull());
183 UString::Rep *rep =
name._ustring.rep;
187 UString::Rep *
key = _singleEntry.key;
189 return _singleEntry.value;
197 numCollisions += _table->entries[i].key && _table->entries[i].key != rep;
199 while (UString::Rep *key = _table->entries[i].key) {
201 return _table->entries[i].value;
202 i = (i + 1) & _table->sizeMask;
208 static void printAttributes(
int attributes)
212 if (attributes & ReadOnly)
213 printf (
"ReadOnly ");
214 if (attributes & DontEnum)
215 printf (
"DontEnum ");
216 if (attributes & DontDelete)
217 printf (
"DontDelete ");
218 if (attributes & Internal)
219 printf (
"Internal ");
220 if (attributes & Function)
221 printf (
"Function ");
225 void PropertyMap::put(
const Identifier &name, ValueImp *value,
int attributes)
227 assert(!
name.isNull());
230 #if DO_CONSISTENCY_CHECK
234 UString::Rep *rep =
name._ustring.rep;
237 printf(
"adding property %s, attributes = 0x%08x (",
name.ascii(), attributes);
238 printAttributes(attributes);
244 UString::Rep *
key = _singleEntry.key;
247 _singleEntry.value = value;
252 _singleEntry.key = rep;
253 _singleEntry.value = value;
254 _singleEntry.attributes = attributes;
260 if (!_table || _table->keyCount * 2 >= _table->size)
265 numCollisions += _table->entries[i].key && _table->entries[i].key != rep;
267 while (UString::Rep *key = _table->entries[i].key) {
270 _table->entries[i].value = value;
274 i = (i + 1) & _table->sizeMask;
279 _table->entries[i].key = rep;
280 _table->entries[i].value = value;
281 _table->entries[i].attributes = attributes;
285 _table->indexCount++;
286 _table->hashToIndex[i] = _table->indexCount;
288 #if DO_CONSISTENCY_CHECK
293 inline void PropertyMap::insert(UString::Rep *key, ValueImp *value,
int attributes)
300 numCollisions += _table->entries[i].key && _table->entries[i].key !=
key;
302 while (_table->entries[i].key)
303 i = (i + 1) & _table->sizeMask;
305 _table->entries[i].key = key;
306 _table->entries[i].value = value;
307 _table->entries[i].attributes = attributes;
310 void PropertyMap::expand()
312 #if DO_CONSISTENCY_CHECK
315 Table *oldTable = _table;
317 int oldTableSize = oldTable ? oldTable->size : 0;
319 int newTableSize = oldTableSize ? oldTableSize * 2 : 16;
324 _table = (Table *)calloc(1,
sizeof(Table) + ((newTableSize - 1) *
sizeof(Entry)) );
326 int *p =
new int[newTableSize];
327 for (
int i = 0; i < newTableSize; i++)
330 _table->hashToIndex = p;
332 _table->size = newTableSize;
334 _table->sizeMask = newTableSize - 1;
336 _table->keyCount = oldTable ? oldTable->keyCount : 0;
338 _table->indexCount = oldTable ? oldTable->indexCount : 0;
341 UString::Rep *
key = _singleEntry.key;
343 insert(key, _singleEntry.value, _singleEntry.attributes);
345 _singleEntry.key = 0;
352 numCollisions += _table->entries[k].key && _table->entries[k].key !=
key;
354 while (UString::Rep *newKey = _table->entries[k].key) {
357 k = (k + 1) & _table->sizeMask;
359 _table->indexCount++;
360 _table->hashToIndex[k] = _table->indexCount;
364 for (
int i = 0; i != oldTableSize; ++i) {
365 UString::Rep *
key = oldTable->entries[i].key;
367 insert(key, oldTable->entries[i].value, oldTable->entries[i].attributes);
374 numCollisions += _table->entries[k].key && _table->entries[k].key !=
key;
376 while (UString::Rep *newKey = _table->entries[k].key) {
379 k = (k + 1) & _table->sizeMask;
382 _table->hashToIndex[k] = oldTable->hashToIndex[i];
387 delete [] oldTable->hashToIndex;
391 #if DO_CONSISTENCY_CHECK
396 void PropertyMap::remove(
const Identifier &name)
398 assert(!
name.isNull());
400 #if DO_CONSISTENCY_CHECK
404 UString::Rep *rep =
name._ustring.rep;
410 key = _singleEntry.key;
413 _singleEntry.key = 0;
424 numCollisions += _table->entries[i].key && _table->entries[i].key != rep;
426 while ((key = _table->entries[i].key)) {
429 i = (i + 1) & _table->sizeMask;
437 _table->entries[i].key = 0;
438 assert(_table->keyCount >= 1);
443 i = (i + 1) & _table->sizeMask;
444 key = _table->entries[i].key;
448 _table->entries[i].key = 0;
450 insert(key, _table->entries[i].value, _table->entries[i].attributes);
456 numCollisions += _table->entries[k].key && _table->entries[k].key !=
key;
458 while (UString::Rep *newKey = _table->entries[k].key) {
461 k = (k + 1) & _table->sizeMask;
465 _table->hashToIndex[k] = _table->hashToIndex[i];
468 #if DO_CONSISTENCY_CHECK
473 void PropertyMap::mark()
const
477 if (_singleEntry.key) {
478 ValueImp *v = _singleEntry.value;
486 for (
int i = 0; i != _table->size; ++i) {
487 if (_table->entries[i].key) {
488 ValueImp *v = _table->entries[i].value;
495 void PropertyMap::addEnumerablesToReferenceList(ReferenceList &list,
const Object &base)
const
499 UString::Rep *
key = _singleEntry.key;
500 if (key && !(_singleEntry.attributes & DontEnum))
501 list.append(Reference(base, Identifier(key)));
507 int indexSize = _table->indexCount + 1;
508 UString::Rep **allKeys =
new UString::Rep*[indexSize];
510 for (
int i = 0; i < indexSize; i++)
516 int size = _table->size;
517 Entry *entries = _table->entries;
518 for (
int i = 0; i != size; ++i) {
519 if (entries[i].key && !(entries[i].attributes & DontEnum)) {
520 int idx = _table->hashToIndex[i];
522 allKeys[idx] = entries[i].key;
530 for (
int i = 0; i < indexSize; ++i) {
531 if (allKeys[i] != NULL){
532 list.append(Reference(base, Identifier(allKeys[i])));
541 void PropertyMap::addSparseArrayPropertiesToReferenceList(ReferenceList &list,
const Object &base)
const
547 UString::Rep *
key = _singleEntry.key;
551 unsigned long i = k.toULong(&fitsInULong);
552 if (fitsInULong && i <= 0xFFFFFFFFU)
553 list.append(Reference(base, Identifier(key)));
559 for (
int i = 0; i != _table->size; ++i) {
560 UString::Rep *
key = _table->entries[i].key;
564 unsigned long i = k.toULong(&fitsInULong);
565 if (fitsInULong && i <= 0xFFFFFFFFU)
566 list.append(Reference(base, Identifier(key)));
571 void PropertyMap::save(SavedProperties &p)
const
577 if (_singleEntry.key && !(_singleEntry.attributes & (ReadOnly | DontEnum | Function)))
581 for (
int i = 0; i != _table->size; ++i)
582 if (_table->entries[i].key && !(_table->entries[i].attributes & (ReadOnly | DontEnum | Function)))
586 delete [] p._properties;
595 p._properties =
new SavedProperty [count];
597 SavedProperty *prop = p._properties;
601 if (_singleEntry.key && !(_singleEntry.attributes & (ReadOnly | DontEnum | Function))) {
602 prop->key = Identifier(_singleEntry.key);
603 prop->value = Value(_singleEntry.value);
604 prop->attributes = _singleEntry.attributes;
609 for (
int i = 0; i != _table->size; ++i) {
610 if (_table->entries[i].key && !(_table->entries[i].attributes & (ReadOnly | DontEnum | Function))) {
611 prop->key = Identifier(_table->entries[i].key);
612 prop->value = Value(_table->entries[i].value);
613 prop->attributes = _table->entries[i].attributes;
620 void PropertyMap::restore(
const SavedProperties &p)
622 for (
int i = 0; i != p._count; ++i)
623 put(p._properties[i].key, p._properties[i].value.imp(), p._properties[i].attributes);
626 #if DO_CONSISTENCY_CHECK
628 void PropertyMap::checkConsistency()
634 for (
int j = 0; j != _table->size; ++j) {
635 UString::Rep *rep = _table->entries[j].key;
639 while (UString::Rep *key = _table->entries[i].key) {
642 i = (i + 1) & _table->sizeMask;
645 assert(_table->hashToIndex[i] > 0);
648 assert(count == _table->keyCount);
649 assert(_table->size >= 16);
650 assert(_table->sizeMask);
651 assert(_table->size == _table->sizeMask + 1);
const TDEShortcut & insert()
TQString name(StdAccel id)