Index: runtime/vm/hash_map.h |
diff --git a/runtime/vm/hash_map.h b/runtime/vm/hash_map.h |
index f2caa9e627d2ff68033af10773c7a9c544b3ba09..372ff7f38c94607ea90ca4e63ad7c66323e7479c 100644 |
--- a/runtime/vm/hash_map.h |
+++ b/runtime/vm/hash_map.h |
@@ -5,28 +5,39 @@ |
#ifndef VM_HASH_MAP_H_ |
#define VM_HASH_MAP_H_ |
+#include "vm/growable_array.h" // For Malloc, EmptyBase |
#include "vm/zone.h" |
namespace dart { |
-template <typename KeyValueTrait> |
-class DirectChainedHashMap: public ValueObject { |
+template<typename KeyValueTrait, typename B, typename Allocator = Zone> |
+class BaseDirectChainedHashMap : public B { |
public: |
- DirectChainedHashMap() : array_size_(0), |
- lists_size_(0), |
- count_(0), |
- array_(NULL), |
- lists_(NULL), |
- free_list_head_(kNil) { |
+ explicit BaseDirectChainedHashMap(Allocator* allocator) |
+ : array_size_(0), |
+ lists_size_(0), |
+ count_(0), |
+ array_(NULL), |
+ lists_(NULL), |
+ free_list_head_(kNil), |
+ allocator_(allocator) { |
ResizeLists(kInitialSize); |
Resize(kInitialSize); |
} |
- DirectChainedHashMap(const DirectChainedHashMap& other); |
+ BaseDirectChainedHashMap(const BaseDirectChainedHashMap& other); |
+ |
+ ~BaseDirectChainedHashMap() { |
+ allocator_->template Free<HashMapListElement>(array_, array_size_); |
+ allocator_->template Free<HashMapListElement>(lists_, lists_size_); |
+ } |
void Insert(typename KeyValueTrait::Pair kv); |
- typename KeyValueTrait::Value Lookup(typename KeyValueTrait::Key key) const; |
+ typename KeyValueTrait::Value LookupValue( |
+ typename KeyValueTrait::Key key) const; |
+ |
+ typename KeyValueTrait::Pair* Lookup(typename KeyValueTrait::Key key) const; |
bool IsEmpty() const { return count_ == 0; } |
@@ -43,6 +54,29 @@ class DirectChainedHashMap: public ValueObject { |
} |
} |
+ class Iterator { |
+ public: |
+ typename KeyValueTrait::Pair* Next(); |
+ |
+ void Reset() { |
+ array_index_ = 0; |
+ list_index_ = kNil; |
+ } |
+ |
+ private: |
+ explicit Iterator(const BaseDirectChainedHashMap& map) |
+ : map_(map), array_index_(0), list_index_(kNil) {} |
+ |
+ const BaseDirectChainedHashMap& map_; |
+ intptr_t array_index_; |
+ intptr_t list_index_; |
+ |
+ template<typename T, typename Bs, typename A> |
+ friend class BaseDirectChainedHashMap; |
+ }; |
+ |
+ Iterator GetIterator() const { return Iterator(*this); } |
+ |
protected: |
// A linked list of T values. Stored in arrays. |
struct HashMapListElement { |
@@ -72,12 +106,31 @@ class DirectChainedHashMap: public ValueObject { |
// with a given hash. Colliding elements are stored in linked lists. |
HashMapListElement* lists_; // The linked lists containing hash collisions. |
intptr_t free_list_head_; // Unused elements in lists_ are on the free list. |
+ Allocator* allocator_; |
}; |
-template <typename KeyValueTrait> |
-typename KeyValueTrait::Value |
- DirectChainedHashMap<KeyValueTrait>:: |
+template<typename KeyValueTrait, typename B, typename Allocator> |
+BaseDirectChainedHashMap<KeyValueTrait, B, Allocator>:: |
+ BaseDirectChainedHashMap(const BaseDirectChainedHashMap& other) |
+ : B(), |
+ array_size_(other.array_size_), |
+ lists_size_(other.lists_size_), |
+ count_(other.count_), |
+ array_(other.allocator_->template Alloc<HashMapListElement>( |
+ other.array_size_)), |
+ lists_(other.allocator_->template Alloc<HashMapListElement>( |
+ other.lists_size_)), |
+ free_list_head_(other.free_list_head_), |
+ allocator_(other.allocator_) { |
+ memmove(array_, other.array_, array_size_ * sizeof(HashMapListElement)); |
+ memmove(lists_, other.lists_, lists_size_ * sizeof(HashMapListElement)); |
+} |
+ |
+ |
+template<typename KeyValueTrait, typename B, typename Allocator> |
+typename KeyValueTrait::Pair* |
+ BaseDirectChainedHashMap<KeyValueTrait, B, Allocator>:: |
Lookup(typename KeyValueTrait::Key key) const { |
const typename KeyValueTrait::Value kNoValue = |
KeyValueTrait::ValueOf(typename KeyValueTrait::Pair()); |
@@ -86,40 +139,69 @@ typename KeyValueTrait::Value |
uword pos = Bound(hash); |
if (KeyValueTrait::ValueOf(array_[pos].kv) != kNoValue) { |
if (KeyValueTrait::IsKeyEqual(array_[pos].kv, key)) { |
- return KeyValueTrait::ValueOf(array_[pos].kv); |
+ return &array_[pos].kv; |
} |
intptr_t next = array_[pos].next; |
while (next != kNil) { |
if (KeyValueTrait::IsKeyEqual(lists_[next].kv, key)) { |
- return KeyValueTrait::ValueOf(lists_[next].kv); |
+ return &lists_[next].kv; |
} |
next = lists_[next].next; |
} |
} |
- return kNoValue; |
+ return NULL; |
} |
-template <typename KeyValueTrait> |
-DirectChainedHashMap<KeyValueTrait>:: |
- DirectChainedHashMap(const DirectChainedHashMap& other) |
- : ValueObject(), |
- array_size_(other.array_size_), |
- lists_size_(other.lists_size_), |
- count_(other.count_), |
- array_(Thread::Current()->zone()-> |
- Alloc<HashMapListElement>(other.array_size_)), |
- lists_(Thread::Current()->zone()-> |
- Alloc<HashMapListElement>(other.lists_size_)), |
- free_list_head_(other.free_list_head_) { |
- memmove(array_, other.array_, array_size_ * sizeof(HashMapListElement)); |
- memmove(lists_, other.lists_, lists_size_ * sizeof(HashMapListElement)); |
+template<typename KeyValueTrait, typename B, typename Allocator> |
+typename KeyValueTrait::Value |
+ BaseDirectChainedHashMap<KeyValueTrait, B, Allocator>:: |
+ LookupValue(typename KeyValueTrait::Key key) const { |
+ const typename KeyValueTrait::Value kNoValue = |
+ KeyValueTrait::ValueOf(typename KeyValueTrait::Pair()); |
+ typename KeyValueTrait::Pair* pair = Lookup(key); |
+ return (pair == NULL) ? kNoValue : KeyValueTrait::ValueOf(*pair); |
} |
-template <typename KeyValueTrait> |
-void DirectChainedHashMap<KeyValueTrait>::Resize(intptr_t new_size) { |
+template<typename KeyValueTrait, typename B, typename Allocator> |
+typename KeyValueTrait::Pair* |
+ BaseDirectChainedHashMap<KeyValueTrait, B, Allocator>::Iterator::Next() { |
+ const typename KeyValueTrait::Pair kNoPair = typename KeyValueTrait::Pair(); |
+ |
+ if (array_index_ < map_.array_size_) { |
+ // If we're not in the middle of a list, find the next array slot. |
+ if (list_index_ == kNil) { |
+ while ((map_.array_[array_index_].kv == kNoPair) && |
+ (array_index_ < map_.array_size_)) { |
+ array_index_++; |
+ } |
+ if (array_index_ < map_.array_size_) { |
+ // When we're done with the list, we'll continue with the next array |
+ // slot. |
+ const intptr_t old_array_index = array_index_; |
+ array_index_++; |
+ list_index_ = map_.array_[old_array_index].next; |
+ return &map_.array_[old_array_index].kv; |
+ } else { |
+ return NULL; |
+ } |
+ } |
+ |
+ // Otherwise, return the current lists_ entry, advancing list_index_. |
+ intptr_t current = list_index_; |
+ list_index_ = map_.lists_[current].next; |
+ return &map_.lists_[current].kv; |
+ } |
+ |
+ return NULL; |
+} |
+ |
+ |
+template<typename KeyValueTrait, typename B, typename Allocator> |
+void BaseDirectChainedHashMap<KeyValueTrait, B, Allocator>::Resize( |
+ intptr_t new_size) { |
const typename KeyValueTrait::Value kNoValue = |
KeyValueTrait::ValueOf(typename KeyValueTrait::Pair()); |
@@ -133,7 +215,7 @@ void DirectChainedHashMap<KeyValueTrait>::Resize(intptr_t new_size) { |
} |
HashMapListElement* new_array = |
- Thread::Current()->zone()->Alloc<HashMapListElement>(new_size); |
+ allocator_->template Alloc<HashMapListElement>(new_size); |
InitArray(new_array, new_size); |
HashMapListElement* old_array = array_; |
@@ -163,16 +245,17 @@ void DirectChainedHashMap<KeyValueTrait>::Resize(intptr_t new_size) { |
} |
USE(old_count); |
ASSERT(count_ == old_count); |
+ allocator_->template Free<HashMapListElement>(old_array, old_size); |
} |
-template <typename T> |
-void DirectChainedHashMap<T>::ResizeLists(intptr_t new_size) { |
+template<typename KeyValueTrait, typename B, typename Allocator> |
+void BaseDirectChainedHashMap<KeyValueTrait, B, Allocator>::ResizeLists( |
+ intptr_t new_size) { |
ASSERT(new_size > lists_size_); |
HashMapListElement* new_lists = |
- Thread::Current()->zone()-> |
- Alloc<HashMapListElement>(new_size); |
+ allocator_->template Alloc<HashMapListElement>(new_size); |
InitArray(new_lists, new_size); |
HashMapListElement* old_lists = lists_; |
@@ -188,11 +271,12 @@ void DirectChainedHashMap<T>::ResizeLists(intptr_t new_size) { |
lists_[i].next = free_list_head_; |
free_list_head_ = i; |
} |
+ allocator_->template Free<HashMapListElement>(old_lists, old_size); |
} |
-template <typename KeyValueTrait> |
-void DirectChainedHashMap<KeyValueTrait>:: |
+template<typename KeyValueTrait, typename B, typename Allocator> |
+void BaseDirectChainedHashMap<KeyValueTrait, B, Allocator>:: |
Insert(typename KeyValueTrait::Pair kv) { |
const typename KeyValueTrait::Value kNoValue = |
KeyValueTrait::ValueOf(typename KeyValueTrait::Pair()); |
@@ -223,6 +307,24 @@ void DirectChainedHashMap<KeyValueTrait>:: |
} |
+template<typename KeyValueTrait> |
+class DirectChainedHashMap |
+ : public BaseDirectChainedHashMap<KeyValueTrait, ValueObject> { |
+ public: |
+ DirectChainedHashMap() : BaseDirectChainedHashMap<KeyValueTrait, ValueObject>( |
+ ASSERT_NOTNULL(Thread::Current()->zone())) {} |
+}; |
+ |
+ |
+template<typename KeyValueTrait> |
+class MallocDirectChainedHashMap |
+ : public BaseDirectChainedHashMap<KeyValueTrait, EmptyBase, Malloc> { |
+ public: |
+ MallocDirectChainedHashMap() |
+ : BaseDirectChainedHashMap<KeyValueTrait, EmptyBase, Malloc>(NULL) {} |
+}; |
+ |
+ |
template<typename T> |
class PointerKeyValueTrait { |
public: |
@@ -247,6 +349,20 @@ class PointerKeyValueTrait { |
} |
}; |
+ |
+template<typename T> |
+class NumbersKeyValueTrait { |
+ public: |
+ typedef T Value; |
+ typedef intptr_t Key; |
+ typedef T Pair; |
+ |
+ static intptr_t KeyOf(Pair kv) { return kv.first(); } |
+ static T ValueOf(Pair kv) { return kv; } |
+ static inline intptr_t Hashcode(Key key) { return key; } |
+ static inline bool IsKeyEqual(Pair kv, Key key) { return kv.first() == key; } |
+}; |
+ |
} // namespace dart |
#endif // VM_HASH_MAP_H_ |