Chromium Code Reviews| Index: src/objects.h |
| diff --git a/src/objects.h b/src/objects.h |
| index c4d3f251c318173946ab614ff661c3da679eb6fa..33375763cb73a8e4d09a7096f3a761bd1d46fc1e 100644 |
| --- a/src/objects.h |
| +++ b/src/objects.h |
| @@ -92,6 +92,9 @@ |
| // - CompilationCacheTable |
| // - CodeCacheHashTable |
| // - MapCache |
| +// - OrderedHashTable |
| +// - OrderedHashSet |
| +// - OrderedHashMap |
| // - Context |
| // - JSFunctionResultCache |
| // - ScopeInfo |
| @@ -4249,6 +4252,163 @@ class ObjectHashTable: public HashTable<ObjectHashTableShape<2>, Object*> { |
| }; |
| +// OrderedHashTable is a HashTable with Object keys that preserves |
| +// insertion order. There are Map and Set interfaces (OrderedHashMap |
| +// and OrderedHashTable, below). It is meant to be used by JSMap/JSSet. |
| +// |
| +// Only Object* keys are supported, with Object::SameValue() used as the |
|
arv (Not doing code reviews)
2014/04/07 00:01:21
ES6 Map/Set uses SameValueZero (which treats -0 an
|
| +// equality operator and Object::GetHash() for the hash function. |
| +// |
| +// Based on the "Deterministic Hash Table" as described by Jason Orendorff at |
| +// https://wiki.mozilla.org/User:Jorend/Deterministic_hash_tables |
| +// Originally attributed to Tyler Close. |
| +// |
| +// Memory layout: |
| +// [0]: bucket count |
| +// [1]: element count |
| +// [2]: deleted element count |
| +// [3..(NumberOfBuckets() - 1)]: "hash table", where each item is an offset |
| +// into the data table (see below) where the |
| +// first item in this bucket is stored. |
| +// [3 + NumberOfBuckets()..length]: "data table", an array of length |
| +// Capacity() * kEntrySize, where the first entrysize |
| +// items are handled by the derived class and the |
| +// item at kChainOffset is another entry into the |
| +// data table indicating the next entry in this hash |
| +// bucket. |
| +template<class Derived, int entrysize> |
| +class OrderedHashTable: public FixedArray { |
| + public: |
| + // Returns an OrderedHashTable with a capacity of at least |capacity|. |
| + static Handle<Derived> Allocate( |
| + Isolate* isolate, int capacity, PretenureFlag pretenure = NOT_TENURED); |
| + |
| + // Returns an OrderedHashTable (possibly |table|) with enough space |
| + // to add at least one new element, or returns a Failure if a GC occurs. |
| + static Handle<Derived> EnsureGrowable(Handle<Derived> table); |
| + |
| + // Returns an OrderedHashTable (possibly |table|) that's shrunken |
| + // if possible. |
| + static Handle<Derived> Shrink(Handle<Derived> table); |
| + |
| + // Returns kNotFound if the key isn't present. |
| + int FindEntry(Object* key); |
| + |
| + int NumberOfElements() { |
| + return Smi::cast(get(kNumberOfElementsIndex))->value(); |
| + } |
| + |
| + int NumberOfDeletedElements() { |
| + return Smi::cast(get(kNumberOfDeletedElementsIndex))->value(); |
| + } |
| + |
| + int NumberOfBuckets() { |
| + return Smi::cast(get(kNumberOfBucketsIndex))->value(); |
| + } |
| + |
| + // Returns the index into the data table where the new entry |
| + // should be placed. The table is assumed to have enough space |
| + // for a new entry. |
| + int AddEntry(int hash); |
| + |
| + // Removes the entry, and puts the_hole in entrysize pointers |
| + // (leaving the hash table chain intact). |
| + void RemoveEntry(int entry); |
| + |
| + // Returns an index into |this| for the given entry. |
| + int EntryToIndex(int entry) { |
| + return kHashTableStartIndex + NumberOfBuckets() + (entry * kEntrySize); |
| + } |
| + |
| + static const int kNotFound = -1; |
| + |
| + private: |
| + static Handle<Derived> Rehash(Handle<Derived> table, int new_capacity); |
| + |
| + void SetNumberOfBuckets(int num) { |
| + set(kNumberOfBucketsIndex, Smi::FromInt(num)); |
| + } |
| + |
| + void SetNumberOfElements(int num) { |
| + set(kNumberOfElementsIndex, Smi::FromInt(num)); |
| + } |
| + |
| + void SetNumberOfDeletedElements(int num) { |
| + set(kNumberOfDeletedElementsIndex, Smi::FromInt(num)); |
| + } |
| + |
| + int Capacity() { |
| + return NumberOfBuckets() * kLoadFactor; |
| + } |
| + |
| + Object* KeyAt(int entry) { return get(EntryToIndex(entry)); } |
| + |
| + // Returns the next entry for the given entry. |
| + int ChainAt(int entry) { |
| + return Smi::cast(get(EntryToIndex(entry) + kChainOffset))->value(); |
| + } |
| + |
| + int HashToBucket(int hash) { |
| + return hash & (NumberOfBuckets() - 1); |
| + } |
| + |
| + int HashToEntry(int hash) { |
| + int bucket = HashToBucket(hash); |
| + return Smi::cast(get(kHashTableStartIndex + bucket))->value(); |
| + } |
| + |
| + static const int kNumberOfBucketsIndex = 0; |
| + static const int kNumberOfElementsIndex = kNumberOfBucketsIndex + 1; |
| + static const int kNumberOfDeletedElementsIndex = kNumberOfElementsIndex + 1; |
| + static const int kHashTableStartIndex = kNumberOfDeletedElementsIndex + 1; |
| + |
| + static const int kEntrySize = entrysize + 1; |
| + static const int kChainOffset = entrysize; |
| + |
| + static const int kLoadFactor = 2; |
| + static const int kMaxCapacity = |
| + (FixedArray::kMaxLength - kHashTableStartIndex) |
| + / (1 + (kEntrySize * kLoadFactor)); |
| +}; |
| + |
| + |
| +class OrderedHashSet: public OrderedHashTable<OrderedHashSet, 1> { |
| + public: |
| + static OrderedHashSet* cast(Object* obj) { |
| + ASSERT(obj->IsFixedArray()); // TODO(adamk): Make a map for this |
| + return reinterpret_cast<OrderedHashSet*>(obj); |
| + } |
| + |
| + bool Contains(Object* key); |
| + static Handle<OrderedHashSet> Add( |
| + Handle<OrderedHashSet> table, Handle<Object> key); |
| + static Handle<OrderedHashSet> Remove( |
| + Handle<OrderedHashSet> table, Handle<Object> key); |
| +}; |
| + |
| + |
| +class OrderedHashMap: public OrderedHashTable<OrderedHashMap, 2> { |
| + public: |
| + static OrderedHashMap* cast(Object* obj) { |
| + ASSERT(obj->IsFixedArray()); // TODO(adamk): Make a map for this |
| + return reinterpret_cast<OrderedHashMap*>(obj); |
| + } |
| + |
| + Object* Lookup(Object* key); |
| + static Handle<OrderedHashMap> Put( |
| + Handle<OrderedHashMap> table, |
| + Handle<Object> key, |
| + Handle<Object> value); |
| + |
| + private: |
| + Object* ValueAt(int entry) { |
| + return get(EntryToIndex(entry) + kValueOffset); |
| + } |
| + |
| + static const int kValueOffset = 1; |
| +}; |
| + |
| + |
| template <int entrysize> |
| class WeakHashTableShape : public BaseShape<Object*> { |
| public: |