| 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 KeyValueTrait> | 10 template <typename KeyValueTrait> |
| (...skipping 13 matching lines...) Expand all Loading... |
| 24 | 24 |
| 25 void Insert(typename KeyValueTrait::Pair kv); | 25 void Insert(typename KeyValueTrait::Pair kv); |
| 26 | 26 |
| 27 typename KeyValueTrait::Value Lookup(typename KeyValueTrait::Key key) 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 void Clear() { | 31 void Clear() { |
| 32 if (!IsEmpty()) { | 32 if (!IsEmpty()) { |
| 33 count_ = 0; | 33 count_ = 0; |
| 34 memset(array_, 0, sizeof(HashMapListElement) * array_size_); | 34 InitArray(array_, array_size_); |
| 35 memset(lists_, 0, sizeof(HashMapListElement) * lists_size_); | 35 InitArray(lists_, lists_size_); |
| 36 lists_[0].next = kNil; | 36 lists_[0].next = kNil; |
| 37 for (intptr_t i = 1; i < lists_size_; ++i) { | 37 for (intptr_t i = 1; i < lists_size_; ++i) { |
| 38 lists_[i].next = i - 1; | 38 lists_[i].next = i - 1; |
| 39 } | 39 } |
| 40 free_list_head_ = lists_size_ - 1; | 40 free_list_head_ = lists_size_ - 1; |
| 41 } | 41 } |
| 42 } | 42 } |
| 43 | 43 |
| 44 protected: | 44 protected: |
| 45 // A linked list of T values. Stored in arrays. | 45 // A linked list of T values. Stored in arrays. |
| 46 struct HashMapListElement { | 46 struct HashMapListElement { |
| 47 HashMapListElement() : kv(), next(kNil) { } |
| 47 typename KeyValueTrait::Pair kv; | 48 typename KeyValueTrait::Pair kv; |
| 48 intptr_t next; // Index in the array of the next list element. | 49 intptr_t next; // Index in the array of the next list element. |
| 49 }; | 50 }; |
| 50 static const intptr_t kNil = -1; // The end of a linked list | 51 static const intptr_t kNil = -1; // The end of a linked list |
| 51 | 52 |
| 53 static void InitArray(HashMapListElement* array, intptr_t size) { |
| 54 for (intptr_t i = 0; i < size; ++i) { |
| 55 array[i] = HashMapListElement(); |
| 56 } |
| 57 } |
| 58 |
| 52 // Must be a power of 2. | 59 // Must be a power of 2. |
| 53 static const intptr_t kInitialSize = 16; | 60 static const intptr_t kInitialSize = 16; |
| 54 | 61 |
| 55 void Resize(intptr_t new_size); | 62 void Resize(intptr_t new_size); |
| 56 void ResizeLists(intptr_t new_size); | 63 void ResizeLists(intptr_t new_size); |
| 57 uword Bound(uword value) const { return value & (array_size_ - 1); } | 64 uword Bound(uword value) const { return value & (array_size_ - 1); } |
| 58 | 65 |
| 59 intptr_t array_size_; | 66 intptr_t array_size_; |
| 60 intptr_t lists_size_; | 67 intptr_t lists_size_; |
| 61 intptr_t count_; // The number of values stored in the HashMap. | 68 intptr_t count_; // The number of values stored in the HashMap. |
| 62 HashMapListElement* array_; // Primary store - contains the first value | 69 HashMapListElement* array_; // Primary store - contains the first value |
| 63 // with a given hash. Colliding elements are stored in linked lists. | 70 // with a given hash. Colliding elements are stored in linked lists. |
| 64 HashMapListElement* lists_; // The linked lists containing hash collisions. | 71 HashMapListElement* lists_; // The linked lists containing hash collisions. |
| 65 intptr_t free_list_head_; // Unused elements in lists_ are on the free list. | 72 intptr_t free_list_head_; // Unused elements in lists_ are on the free list. |
| 66 }; | 73 }; |
| 67 | 74 |
| 68 | 75 |
| 69 template <typename KeyValueTrait> | 76 template <typename KeyValueTrait> |
| 70 typename KeyValueTrait::Value | 77 typename KeyValueTrait::Value |
| 71 DirectChainedHashMap<KeyValueTrait>:: | 78 DirectChainedHashMap<KeyValueTrait>:: |
| 72 Lookup(typename KeyValueTrait::Key key) const { | 79 Lookup(typename KeyValueTrait::Key key) const { |
| 73 const typename KeyValueTrait::Value kNoValue = | 80 const typename KeyValueTrait::Value kNoValue = |
| 74 static_cast<typename KeyValueTrait::Value>(0); | 81 KeyValueTrait::ValueOf(typename KeyValueTrait::Pair()); |
| 75 | 82 |
| 76 uword hash = static_cast<uword>(KeyValueTrait::Hashcode(key)); | 83 uword hash = static_cast<uword>(KeyValueTrait::Hashcode(key)); |
| 77 uword pos = Bound(hash); | 84 uword pos = Bound(hash); |
| 78 if (KeyValueTrait::ValueOf(array_[pos].kv) != kNoValue) { | 85 if (KeyValueTrait::ValueOf(array_[pos].kv) != kNoValue) { |
| 79 if (KeyValueTrait::IsKeyEqual(array_[pos].kv, key)) { | 86 if (KeyValueTrait::IsKeyEqual(array_[pos].kv, key)) { |
| 80 return KeyValueTrait::ValueOf(array_[pos].kv); | 87 return KeyValueTrait::ValueOf(array_[pos].kv); |
| 81 } | 88 } |
| 82 | 89 |
| 83 intptr_t next = array_[pos].next; | 90 intptr_t next = array_[pos].next; |
| 84 while (next != kNil) { | 91 while (next != kNil) { |
| (...skipping 20 matching lines...) Expand all Loading... |
| 105 Alloc<HashMapListElement>(other.lists_size_)), | 112 Alloc<HashMapListElement>(other.lists_size_)), |
| 106 free_list_head_(other.free_list_head_) { | 113 free_list_head_(other.free_list_head_) { |
| 107 memmove(array_, other.array_, array_size_ * sizeof(HashMapListElement)); | 114 memmove(array_, other.array_, array_size_ * sizeof(HashMapListElement)); |
| 108 memmove(lists_, other.lists_, lists_size_ * sizeof(HashMapListElement)); | 115 memmove(lists_, other.lists_, lists_size_ * sizeof(HashMapListElement)); |
| 109 } | 116 } |
| 110 | 117 |
| 111 | 118 |
| 112 template <typename KeyValueTrait> | 119 template <typename KeyValueTrait> |
| 113 void DirectChainedHashMap<KeyValueTrait>::Resize(intptr_t new_size) { | 120 void DirectChainedHashMap<KeyValueTrait>::Resize(intptr_t new_size) { |
| 114 const typename KeyValueTrait::Value kNoValue = | 121 const typename KeyValueTrait::Value kNoValue = |
| 115 static_cast<typename KeyValueTrait::Value>(0); | 122 KeyValueTrait::ValueOf(typename KeyValueTrait::Pair()); |
| 116 | 123 |
| 117 ASSERT(new_size > count_); | 124 ASSERT(new_size > count_); |
| 118 // Hashing the values into the new array has no more collisions than in the | 125 // Hashing the values into the new array has no more collisions than in the |
| 119 // old hash map, so we can use the existing lists_ array, if we are careful. | 126 // old hash map, so we can use the existing lists_ array, if we are careful. |
| 120 | 127 |
| 121 // Make sure we have at least one free element. | 128 // Make sure we have at least one free element. |
| 122 if (free_list_head_ == kNil) { | 129 if (free_list_head_ == kNil) { |
| 123 ResizeLists(lists_size_ << 1); | 130 ResizeLists(lists_size_ << 1); |
| 124 } | 131 } |
| 125 | 132 |
| 126 HashMapListElement* new_array = | 133 HashMapListElement* new_array = |
| 127 Isolate::Current()->current_zone()->Alloc<HashMapListElement>(new_size); | 134 Isolate::Current()->current_zone()->Alloc<HashMapListElement>(new_size); |
| 128 memset(new_array, 0, sizeof(HashMapListElement) * new_size); | 135 InitArray(new_array, new_size); |
| 129 | 136 |
| 130 HashMapListElement* old_array = array_; | 137 HashMapListElement* old_array = array_; |
| 131 intptr_t old_size = array_size_; | 138 intptr_t old_size = array_size_; |
| 132 | 139 |
| 133 intptr_t old_count = count_; | 140 intptr_t old_count = count_; |
| 134 count_ = 0; | 141 count_ = 0; |
| 135 array_size_ = new_size; | 142 array_size_ = new_size; |
| 136 array_ = new_array; | 143 array_ = new_array; |
| 137 | 144 |
| 138 if (old_array != NULL) { | 145 if (old_array != NULL) { |
| (...skipping 18 matching lines...) Expand all Loading... |
| 157 } | 164 } |
| 158 | 165 |
| 159 | 166 |
| 160 template <typename T> | 167 template <typename T> |
| 161 void DirectChainedHashMap<T>::ResizeLists(intptr_t new_size) { | 168 void DirectChainedHashMap<T>::ResizeLists(intptr_t new_size) { |
| 162 ASSERT(new_size > lists_size_); | 169 ASSERT(new_size > lists_size_); |
| 163 | 170 |
| 164 HashMapListElement* new_lists = | 171 HashMapListElement* new_lists = |
| 165 Isolate::Current()->current_zone()-> | 172 Isolate::Current()->current_zone()-> |
| 166 Alloc<HashMapListElement>(new_size); | 173 Alloc<HashMapListElement>(new_size); |
| 167 memset(new_lists, 0, sizeof(HashMapListElement) * new_size); | 174 InitArray(new_lists, new_size); |
| 168 | 175 |
| 169 HashMapListElement* old_lists = lists_; | 176 HashMapListElement* old_lists = lists_; |
| 170 intptr_t old_size = lists_size_; | 177 intptr_t old_size = lists_size_; |
| 171 | 178 |
| 172 lists_size_ = new_size; | 179 lists_size_ = new_size; |
| 173 lists_ = new_lists; | 180 lists_ = new_lists; |
| 174 | 181 |
| 175 if (old_lists != NULL) { | 182 if (old_lists != NULL) { |
| 176 memmove(lists_, old_lists, old_size * sizeof(HashMapListElement)); | 183 memmove(lists_, old_lists, old_size * sizeof(HashMapListElement)); |
| 177 } | 184 } |
| 178 for (intptr_t i = old_size; i < lists_size_; ++i) { | 185 for (intptr_t i = old_size; i < lists_size_; ++i) { |
| 179 lists_[i].next = free_list_head_; | 186 lists_[i].next = free_list_head_; |
| 180 free_list_head_ = i; | 187 free_list_head_ = i; |
| 181 } | 188 } |
| 182 } | 189 } |
| 183 | 190 |
| 184 | 191 |
| 185 template <typename KeyValueTrait> | 192 template <typename KeyValueTrait> |
| 186 void DirectChainedHashMap<KeyValueTrait>:: | 193 void DirectChainedHashMap<KeyValueTrait>:: |
| 187 Insert(typename KeyValueTrait::Pair kv) { | 194 Insert(typename KeyValueTrait::Pair kv) { |
| 188 const typename KeyValueTrait::Value kNoValue = | 195 const typename KeyValueTrait::Value kNoValue = |
| 189 static_cast<typename KeyValueTrait::Value>(0); | 196 KeyValueTrait::ValueOf(typename KeyValueTrait::Pair()); |
| 190 | 197 |
| 191 ASSERT(KeyValueTrait::ValueOf(kv) != kNoValue); | 198 ASSERT(KeyValueTrait::ValueOf(kv) != kNoValue); |
| 192 // Resizing when half of the hashtable is filled up. | 199 // Resizing when half of the hashtable is filled up. |
| 193 if (count_ >= array_size_ >> 1) Resize(array_size_ << 1); | 200 if (count_ >= array_size_ >> 1) Resize(array_size_ << 1); |
| 194 ASSERT(count_ < array_size_); | 201 ASSERT(count_ < array_size_); |
| 195 count_++; | 202 count_++; |
| 196 uword pos = Bound( | 203 uword pos = Bound( |
| 197 static_cast<uword>(KeyValueTrait::Hashcode(KeyValueTrait::KeyOf(kv)))); | 204 static_cast<uword>(KeyValueTrait::Hashcode(KeyValueTrait::KeyOf(kv)))); |
| 198 if (KeyValueTrait::ValueOf(array_[pos].kv) == kNoValue) { | 205 if (KeyValueTrait::ValueOf(array_[pos].kv) == kNoValue) { |
| 199 array_[pos].kv = kv; | 206 array_[pos].kv = kv; |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 234 } | 241 } |
| 235 | 242 |
| 236 static inline bool IsKeyEqual(Pair kv, Key key) { | 243 static inline bool IsKeyEqual(Pair kv, Key key) { |
| 237 return kv->Equals(key); | 244 return kv->Equals(key); |
| 238 } | 245 } |
| 239 }; | 246 }; |
| 240 | 247 |
| 241 } // namespace dart | 248 } // namespace dart |
| 242 | 249 |
| 243 #endif // VM_HASH_MAP_H_ | 250 #endif // VM_HASH_MAP_H_ |
| OLD | NEW |