| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #ifndef VM_HASH_MAP_H_ | 5 #ifndef VM_HASH_MAP_H_ |
| 6 #define VM_HASH_MAP_H_ | 6 #define VM_HASH_MAP_H_ |
| 7 | 7 |
| 8 namespace dart { | 8 namespace dart { |
| 9 | 9 |
| 10 template <typename T> | 10 template <typename KeyValueTrait> |
| 11 class DirectChainedHashMap: public ValueObject { | 11 class DirectChainedHashMap: public ValueObject { |
| 12 public: | 12 public: |
| 13 DirectChainedHashMap() : array_size_(0), | 13 DirectChainedHashMap() : array_size_(0), |
| 14 lists_size_(0), | 14 lists_size_(0), |
| 15 count_(0), | 15 count_(0), |
| 16 array_(NULL), | 16 array_(NULL), |
| 17 lists_(NULL), | 17 lists_(NULL), |
| 18 free_list_head_(kNil) { | 18 free_list_head_(kNil) { |
| 19 ResizeLists(kInitialSize); | 19 ResizeLists(kInitialSize); |
| 20 Resize(kInitialSize); | 20 Resize(kInitialSize); |
| 21 } | 21 } |
| 22 | 22 |
| 23 DirectChainedHashMap(const DirectChainedHashMap& other); | 23 DirectChainedHashMap(const DirectChainedHashMap& other); |
| 24 | 24 |
| 25 void Insert(T value); | 25 void Insert(typename KeyValueTrait::Pair kv); |
| 26 | 26 |
| 27 T Lookup(T value) const; | 27 typename KeyValueTrait::Value Lookup(typename KeyValueTrait::Key key) const; |
| 28 | 28 |
| 29 bool IsEmpty() const { return count_ == 0; } | 29 bool IsEmpty() const { return count_ == 0; } |
| 30 | 30 |
| 31 private: | 31 private: |
| 32 // A linked list of T values. Stored in arrays. | 32 // A linked list of T values. Stored in arrays. |
| 33 struct HashMapListElement { | 33 struct HashMapListElement { |
| 34 T value; | 34 typename KeyValueTrait::Pair kv; |
| 35 intptr_t next; // Index in the array of the next list element. | 35 intptr_t next; // Index in the array of the next list element. |
| 36 }; | 36 }; |
| 37 static const intptr_t kNil = -1; // The end of a linked list | 37 static const intptr_t kNil = -1; // The end of a linked list |
| 38 | 38 |
| 39 // Must be a power of 2. | 39 // Must be a power of 2. |
| 40 static const intptr_t kInitialSize = 16; | 40 static const intptr_t kInitialSize = 16; |
| 41 | 41 |
| 42 void Resize(intptr_t new_size); | 42 void Resize(intptr_t new_size); |
| 43 void ResizeLists(intptr_t new_size); | 43 void ResizeLists(intptr_t new_size); |
| 44 uword Bound(uword value) const { return value & (array_size_ - 1); } | 44 uword Bound(uword value) const { return value & (array_size_ - 1); } |
| 45 | 45 |
| 46 intptr_t array_size_; | 46 intptr_t array_size_; |
| 47 intptr_t lists_size_; | 47 intptr_t lists_size_; |
| 48 intptr_t count_; // The number of values stored in the HashMap. | 48 intptr_t count_; // The number of values stored in the HashMap. |
| 49 HashMapListElement* array_; // Primary store - contains the first value | 49 HashMapListElement* array_; // Primary store - contains the first value |
| 50 // with a given hash. Colliding elements are stored in linked lists. | 50 // with a given hash. Colliding elements are stored in linked lists. |
| 51 HashMapListElement* lists_; // The linked lists containing hash collisions. | 51 HashMapListElement* lists_; // The linked lists containing hash collisions. |
| 52 intptr_t free_list_head_; // Unused elements in lists_ are on the free list. | 52 intptr_t free_list_head_; // Unused elements in lists_ are on the free list. |
| 53 }; | 53 }; |
| 54 | 54 |
| 55 | 55 |
| 56 template <typename T> | 56 template <typename KeyValueTrait> |
| 57 T DirectChainedHashMap<T>::Lookup(T value) const { | 57 typename KeyValueTrait::Value |
| 58 uword hash = static_cast<uword>(value->Hashcode()); | 58 DirectChainedHashMap<KeyValueTrait>:: |
| 59 Lookup(typename KeyValueTrait::Key key) const { |
| 60 uword hash = static_cast<uword>(KeyValueTrait::Hashcode(key)); |
| 59 uword pos = Bound(hash); | 61 uword pos = Bound(hash); |
| 60 if (array_[pos].value != NULL) { | 62 if (KeyValueTrait::ValueOf(array_[pos].kv) != NULL) { |
| 61 if (array_[pos].value->Equals(value)) return array_[pos].value; | 63 if (KeyValueTrait::IsKeyEqual(array_[pos].kv, key)) { |
| 64 return KeyValueTrait::ValueOf(array_[pos].kv); |
| 65 } |
| 66 |
| 62 intptr_t next = array_[pos].next; | 67 intptr_t next = array_[pos].next; |
| 63 while (next != kNil) { | 68 while (next != kNil) { |
| 64 if (lists_[next].value->Equals(value)) return lists_[next].value; | 69 if (KeyValueTrait::IsKeyEqual(lists_[next].kv, key)) { |
| 70 return KeyValueTrait::ValueOf(lists_[next].kv); |
| 71 } |
| 65 next = lists_[next].next; | 72 next = lists_[next].next; |
| 66 } | 73 } |
| 67 } | 74 } |
| 68 return NULL; | 75 return NULL; |
| 69 } | 76 } |
| 70 | 77 |
| 71 | 78 |
| 72 template <typename T> | 79 template <typename KeyValueTrait> |
| 73 DirectChainedHashMap<T>::DirectChainedHashMap(const DirectChainedHashMap& other) | 80 DirectChainedHashMap<KeyValueTrait>:: |
| 81 DirectChainedHashMap(const DirectChainedHashMap& other) |
| 74 : ValueObject(), | 82 : ValueObject(), |
| 75 array_size_(other.array_size_), | 83 array_size_(other.array_size_), |
| 76 lists_size_(other.lists_size_), | 84 lists_size_(other.lists_size_), |
| 77 count_(other.count_), | 85 count_(other.count_), |
| 78 array_(Isolate::Current()->current_zone()-> | 86 array_(Isolate::Current()->current_zone()-> |
| 79 Alloc<HashMapListElement>(other.array_size_)), | 87 Alloc<HashMapListElement>(other.array_size_)), |
| 80 lists_(Isolate::Current()->current_zone()-> | 88 lists_(Isolate::Current()->current_zone()-> |
| 81 Alloc<HashMapListElement>(other.lists_size_)), | 89 Alloc<HashMapListElement>(other.lists_size_)), |
| 82 free_list_head_(other.free_list_head_) { | 90 free_list_head_(other.free_list_head_) { |
| 83 memmove(array_, other.array_, array_size_ * sizeof(HashMapListElement)); | 91 memmove(array_, other.array_, array_size_ * sizeof(HashMapListElement)); |
| 84 memmove(lists_, other.lists_, lists_size_ * sizeof(HashMapListElement)); | 92 memmove(lists_, other.lists_, lists_size_ * sizeof(HashMapListElement)); |
| 85 } | 93 } |
| 86 | 94 |
| 87 | 95 |
| 88 template <typename T> | 96 template <typename KeyValueTrait> |
| 89 void DirectChainedHashMap<T>::Resize(intptr_t new_size) { | 97 void DirectChainedHashMap<KeyValueTrait>::Resize(intptr_t new_size) { |
| 90 ASSERT(new_size > count_); | 98 ASSERT(new_size > count_); |
| 91 // Hashing the values into the new array has no more collisions than in the | 99 // Hashing the values into the new array has no more collisions than in the |
| 92 // old hash map, so we can use the existing lists_ array, if we are careful. | 100 // old hash map, so we can use the existing lists_ array, if we are careful. |
| 93 | 101 |
| 94 // Make sure we have at least one free element. | 102 // Make sure we have at least one free element. |
| 95 if (free_list_head_ == kNil) { | 103 if (free_list_head_ == kNil) { |
| 96 ResizeLists(lists_size_ << 1); | 104 ResizeLists(lists_size_ << 1); |
| 97 } | 105 } |
| 98 | 106 |
| 99 HashMapListElement* new_array = | 107 HashMapListElement* new_array = |
| 100 Isolate::Current()->current_zone()->Alloc<HashMapListElement>(new_size); | 108 Isolate::Current()->current_zone()->Alloc<HashMapListElement>(new_size); |
| 101 memset(new_array, 0, sizeof(HashMapListElement) * new_size); | 109 memset(new_array, 0, sizeof(HashMapListElement) * new_size); |
| 102 | 110 |
| 103 HashMapListElement* old_array = array_; | 111 HashMapListElement* old_array = array_; |
| 104 intptr_t old_size = array_size_; | 112 intptr_t old_size = array_size_; |
| 105 | 113 |
| 106 intptr_t old_count = count_; | 114 intptr_t old_count = count_; |
| 107 count_ = 0; | 115 count_ = 0; |
| 108 array_size_ = new_size; | 116 array_size_ = new_size; |
| 109 array_ = new_array; | 117 array_ = new_array; |
| 110 | 118 |
| 111 if (old_array != NULL) { | 119 if (old_array != NULL) { |
| 112 // Iterate over all the elements in lists, rehashing them. | 120 // Iterate over all the elements in lists, rehashing them. |
| 113 for (intptr_t i = 0; i < old_size; ++i) { | 121 for (intptr_t i = 0; i < old_size; ++i) { |
| 114 if (old_array[i].value != NULL) { | 122 if (KeyValueTrait::ValueOf(old_array[i].kv) != NULL) { |
| 115 intptr_t current = old_array[i].next; | 123 intptr_t current = old_array[i].next; |
| 116 while (current != kNil) { | 124 while (current != kNil) { |
| 117 Insert(lists_[current].value); | 125 Insert(lists_[current].kv); |
| 118 intptr_t next = lists_[current].next; | 126 intptr_t next = lists_[current].next; |
| 119 lists_[current].next = free_list_head_; | 127 lists_[current].next = free_list_head_; |
| 120 free_list_head_ = current; | 128 free_list_head_ = current; |
| 121 current = next; | 129 current = next; |
| 122 } | 130 } |
| 123 // Rehash the directly stored value. | 131 // Rehash the directly stored value. |
| 124 Insert(old_array[i].value); | 132 Insert(old_array[i].kv); |
| 125 } | 133 } |
| 126 } | 134 } |
| 127 } | 135 } |
| 128 USE(old_count); | 136 USE(old_count); |
| 129 ASSERT(count_ == old_count); | 137 ASSERT(count_ == old_count); |
| 130 } | 138 } |
| 131 | 139 |
| 132 | 140 |
| 133 template <typename T> | 141 template <typename T> |
| 134 void DirectChainedHashMap<T>::ResizeLists(intptr_t new_size) { | 142 void DirectChainedHashMap<T>::ResizeLists(intptr_t new_size) { |
| (...skipping 13 matching lines...) Expand all Loading... |
| 148 if (old_lists != NULL) { | 156 if (old_lists != NULL) { |
| 149 memmove(lists_, old_lists, old_size * sizeof(HashMapListElement)); | 157 memmove(lists_, old_lists, old_size * sizeof(HashMapListElement)); |
| 150 } | 158 } |
| 151 for (intptr_t i = old_size; i < lists_size_; ++i) { | 159 for (intptr_t i = old_size; i < lists_size_; ++i) { |
| 152 lists_[i].next = free_list_head_; | 160 lists_[i].next = free_list_head_; |
| 153 free_list_head_ = i; | 161 free_list_head_ = i; |
| 154 } | 162 } |
| 155 } | 163 } |
| 156 | 164 |
| 157 | 165 |
| 158 template <typename T> | 166 template <typename KeyValueTrait> |
| 159 void DirectChainedHashMap<T>::Insert(T value) { | 167 void DirectChainedHashMap<KeyValueTrait>:: |
| 160 ASSERT(value != NULL); | 168 Insert(typename KeyValueTrait::Pair kv) { |
| 169 ASSERT(KeyValueTrait::ValueOf(kv) != NULL); |
| 161 // Resizing when half of the hashtable is filled up. | 170 // Resizing when half of the hashtable is filled up. |
| 162 if (count_ >= array_size_ >> 1) Resize(array_size_ << 1); | 171 if (count_ >= array_size_ >> 1) Resize(array_size_ << 1); |
| 163 ASSERT(count_ < array_size_); | 172 ASSERT(count_ < array_size_); |
| 164 count_++; | 173 count_++; |
| 165 uword pos = Bound(static_cast<uword>(value->Hashcode())); | 174 uword pos = Bound( |
| 166 if (array_[pos].value == NULL) { | 175 static_cast<uword>(KeyValueTrait::Hashcode(KeyValueTrait::KeyOf(kv)))); |
| 167 array_[pos].value = value; | 176 if (KeyValueTrait::ValueOf(array_[pos].kv) == NULL) { |
| 177 array_[pos].kv = kv; |
| 168 array_[pos].next = kNil; | 178 array_[pos].next = kNil; |
| 169 } else { | 179 } else { |
| 170 if (free_list_head_ == kNil) { | 180 if (free_list_head_ == kNil) { |
| 171 ResizeLists(lists_size_ << 1); | 181 ResizeLists(lists_size_ << 1); |
| 172 } | 182 } |
| 173 intptr_t new_element_pos = free_list_head_; | 183 intptr_t new_element_pos = free_list_head_; |
| 174 ASSERT(new_element_pos != kNil); | 184 ASSERT(new_element_pos != kNil); |
| 175 free_list_head_ = lists_[free_list_head_].next; | 185 free_list_head_ = lists_[free_list_head_].next; |
| 176 lists_[new_element_pos].value = value; | 186 lists_[new_element_pos].kv = kv; |
| 177 lists_[new_element_pos].next = array_[pos].next; | 187 lists_[new_element_pos].next = array_[pos].next; |
| 178 ASSERT(array_[pos].next == kNil || lists_[array_[pos].next].value != NULL); | 188 ASSERT(array_[pos].next == kNil || |
| 189 KeyValueTrait::ValueOf(lists_[array_[pos].next].kv) != NULL); |
| 179 array_[pos].next = new_element_pos; | 190 array_[pos].next = new_element_pos; |
| 180 } | 191 } |
| 181 } | 192 } |
| 182 | 193 |
| 194 |
| 195 template<typename T> |
| 196 class PointerKeyValueTrait { |
| 197 public: |
| 198 typedef T* Value; |
| 199 typedef T* Key; |
| 200 typedef T* Pair; |
| 201 |
| 202 static Key KeyOf(Pair kv) { |
| 203 return kv; |
| 204 } |
| 205 |
| 206 static Value ValueOf(Pair kv) { |
| 207 return kv; |
| 208 } |
| 209 |
| 210 static inline intptr_t Hashcode(Key key) { |
| 211 return key->Hashcode(); |
| 212 } |
| 213 |
| 214 static inline bool IsKeyEqual(Pair kv, Key key) { |
| 215 return kv->Equals(key); |
| 216 } |
| 217 }; |
| 218 |
| 183 } // namespace dart | 219 } // namespace dart |
| 184 | 220 |
| 185 #endif // VM_HASH_MAP_H_ | 221 #endif // VM_HASH_MAP_H_ |
| OLD | NEW |