[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    branches/KDE/3.5/kdelibs/kjs
From:       Germain Garand <germain () ebooksfrance ! com>
Date:       2006-06-29 10:05:05
Message-ID: 1151575505.543903.2865.nullmailer () svn ! kde ! org
[Download RAW message or body]

SVN commit 556121 by ggarand:

apply patch from  Fredrik Johansson <fredrik@mumme.se>

for correct ordering of array properties

BUG: 28474

approved by Harri



 M  +133 -10   property_map.cpp  


--- branches/KDE/3.5/kdelibs/kjs/property_map.cpp #556120:556121
@@ -63,6 +63,13 @@
     int sizeMask;
     int size;
     int keyCount;
+
+    // gets initialized in expand, an array that stores insert order of a particular \
hash +    int *hashToIndex; // NOTE: is one based 1,2,3 etc..
+
+    // keeps trac on how many insertions we have made, cant use keyCount because \
delete a key in the middle messes things +    int indexCount;
+
     PropertyMapHashTableEntry entries[1];
 };
 
@@ -102,6 +109,10 @@
         if (key)
 	  key->deref();
     }
+    // fredrik added to cleanup sortorder
+    if (_table)
+        delete [] _table->hashToIndex;
+
     free(_table);
 }
 
@@ -216,7 +227,9 @@
     assert(!name.isNull());
     assert(value != 0);
 
+#if DO_CONSISTENCY_CHECK // speed, why call a stub if we dont need to??
     checkConsistency();
+#endif
 
     UString::Rep *rep = name._ustring.rep;
 
@@ -244,10 +257,8 @@
         }
     }
 #endif
-
     if (!_table || _table->keyCount * 2 >= _table->size)
         expand();
-
     int i = hash(rep);
 #if DUMP_STATISTICS
     ++numProbes;
@@ -270,7 +281,13 @@
     _table->entries[i].attributes = attributes;
     ++_table->keyCount;
 
+    // store insert order
+    _table->indexCount++;
+    _table->hashToIndex[i] = _table->indexCount;
+
+#if DO_CONSISTENCY_CHECK// speed, why call a stub if we dont need to??
     checkConsistency();
+#endif
 }
 
 inline void PropertyMap::insert(UString::Rep *key, ValueImp *value, int attributes)
@@ -292,42 +309,97 @@
 
 void PropertyMap::expand()
 {
+#if DO_CONSISTENCY_CHECK// speed, why call a stub if we dont need to??
     checkConsistency();
+#endif
+    Table *oldTable = _table;
 
-    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) \
); +
+    // Is this realy the best way? wouldnt it be easier to use new/delete on an \
array instead +    // and do a pointer in Table to that array, that way we wouldnt \
need to delete the whole _table +    // every time we need to expand
+    _table = (Table *)calloc(1, sizeof(Table) + ((newTableSize - 1) * sizeof(Entry)) \
); +
+    int *p = new int[newTableSize];
+    for (int i = 0; i < newTableSize; i++)
+        p[i] = 0;
+
+    _table->hashToIndex = p;
+
     _table->size = newTableSize;
+
     _table->sizeMask = newTableSize - 1;
+
     _table->keyCount = oldTable ? oldTable->keyCount : 0;
 
+    _table->indexCount = oldTable ? oldTable->indexCount : 0;
+
 #if USE_SINGLE_ENTRY
     UString::Rep *key = _singleEntry.key;
     if (key) {
         insert(key, _singleEntry.value, _singleEntry.attributes);
-	_table->keyCount++;
+        _table->keyCount++;
         _singleEntry.key = 0;
+
+        // store sort order
+        // first get the id of newly inserted key, check for trashed hash, then \
store it +        int k = hash(key);
+#if DUMP_STATISTICS
+    ++numProbes;
+    numCollisions += _table->entries[k].key && _table->entries[k].key != key;
+#endif
+        while (UString::Rep *newKey = _table->entries[k].key) {
+             if (key == newKey)
+                 break;
+             k = (k + 1) & _table->sizeMask;
+        }
+        _table->indexCount++;
+        _table->hashToIndex[k] = _table->indexCount;
     }
 #endif
 
     for (int i = 0; i != oldTableSize; ++i) {
         UString::Rep *key = oldTable->entries[i].key;
-        if (key)
+        if (key) {
             insert(key, oldTable->entries[i].value, \
oldTable->entries[i].attributes); +
+            // store sort order
+            // first get the id of newly inserted key, check for trashed hash, then \
store it +            int k = hash(key);
+#if DUMP_STATISTICS
+    ++numProbes;
+    numCollisions += _table->entries[k].key && _table->entries[k].key != key;
+#endif
+            while (UString::Rep *newKey = _table->entries[k].key) {
+                if (key == newKey)
+                    break;
+                k = (k + 1) & _table->sizeMask;
+            }
+            // store hashindex on the newly inserted entry
+            _table->hashToIndex[k] = oldTable->hashToIndex[i];
+        }
     }
 
+    if (oldTable){
+        delete [] oldTable->hashToIndex;
+    }
     free(oldTable);
 
+#if DO_CONSISTENCY_CHECK// speed, why call a stub if we dont need to??
     checkConsistency();
+#endif
 }
 
 void PropertyMap::remove(const Identifier &name)
 {
     assert(!name.isNull());
 
+#if DO_CONSISTENCY_CHECK// speed, why call a stub if we dont need to??
     checkConsistency();
+#endif
 
     UString::Rep *rep = name._ustring.rep;
 
@@ -356,6 +428,7 @@
             break;
         i = (i + 1) & _table->sizeMask;
     }
+
     if (!key)
         return;
 
@@ -371,11 +444,30 @@
         key = _table->entries[i].key;
         if (!key)
             break;
+
         _table->entries[i].key = 0;
+
         insert(key, _table->entries[i].value, _table->entries[i].attributes);
+
+        // store the index of the new hash
+        int k = hash(key);
+#if DUMP_STATISTICS
+    ++numProbes;
+    numCollisions += _table->entries[k].key && _table->entries[k].key != key;
+#endif
+        while (UString::Rep *newKey = _table->entries[k].key) {
+            if (key == newKey)
+                break;
+            k = (k + 1) & _table->sizeMask;
+        }
+
+        // store hashindex on the newly moved entry
+        _table->hashToIndex[k] = _table->hashToIndex[i];
     }
 
+#if DO_CONSISTENCY_CHECK// speed, why call a stub if we dont need to??
     checkConsistency();
+#endif
 }
 
 void PropertyMap::mark() const
@@ -411,15 +503,45 @@
         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)));
+    // Allocate a buffer to use to sort the keys.
+    int indexSize = _table->indexCount + 1; // indexes is one based
+    UString::Rep **allKeys = new UString::Rep*[indexSize];
+
+    for (int i = 0; i < indexSize; i++)
+        allKeys[i] = NULL;
+
+    // push  valid hashes to the array allKeys, using insert order as index.
+    // we need to pass array hashes instead of pointers to keys, because we got
+    // memory corruption sometimes, seems that Identifier in below call deletes the \
key +    int size = _table->size;
+    Entry *entries = _table->entries;
+    for (int i = 0; i != size; ++i) {
+        if (entries[i].key && !(entries[i].attributes & DontEnum)) {
+            int idx = _table->hashToIndex[i];
+            if (idx) {
+                allKeys[idx] = entries[i].key;
+            } else { // nonsorted key, failure
+                //cout<<"Error with in KJS \
property_map.addEnumerablesToReferenceList \nUnsorted key"<<endl; +                \
assert(0==1); // allways throw error if get here +            }
+        }
     }
+    // Put the keys of the sorted entries into the reference list.
+    for (int i = 0; i < indexSize; ++i) {
+        if (allKeys[i] != NULL){
+            list.append(Reference(base, Identifier(allKeys[i])));
+        }
+        allKeys[i] = NULL; // dont deallocate key by accident, when we delete \
allKeys +    }
+
+    // Deallocate the buffer.
+    delete [] allKeys;
 }
 
 void PropertyMap::addSparseArrayPropertiesToReferenceList(ReferenceList &list, const \
Object &base) const  {
+    // NOTE: I did'nt add sort in this method because It seems to be referenced in \
ArrayInstanceImp +    // only and arrays are sorted by definition, dont need the \
extra overhead  if (!_table) {
 #if USE_SINGLE_ENTRY
         UString::Rep *key = _singleEntry.key;
@@ -520,6 +642,7 @@
             i = (i + 1) & _table->sizeMask;
         }
         assert(i == j);
+        assert(_table->hashToIndex[i] > 0);
         count++;
     }
     assert(count == _table->keyCount);


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic