| 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(KeyValueTrait::NoValue()), 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 = KeyValueTrait::NoValue(); |
| 74 static_cast<typename KeyValueTrait::Value>(0); | |
| 75 | 81 |
| 76 uword hash = static_cast<uword>(KeyValueTrait::Hashcode(key)); | 82 uword hash = static_cast<uword>(KeyValueTrait::Hashcode(key)); |
| 77 uword pos = Bound(hash); | 83 uword pos = Bound(hash); |
| 78 if (KeyValueTrait::ValueOf(array_[pos].kv) != kNoValue) { | 84 if (KeyValueTrait::ValueOf(array_[pos].kv) != kNoValue) { |
| 79 if (KeyValueTrait::IsKeyEqual(array_[pos].kv, key)) { | 85 if (KeyValueTrait::IsKeyEqual(array_[pos].kv, key)) { |
| 80 return KeyValueTrait::ValueOf(array_[pos].kv); | 86 return KeyValueTrait::ValueOf(array_[pos].kv); |
| 81 } | 87 } |
| 82 | 88 |
| 83 intptr_t next = array_[pos].next; | 89 intptr_t next = array_[pos].next; |
| 84 while (next != kNil) { | 90 while (next != kNil) { |
| (...skipping 19 matching lines...) Expand all Loading... |
| 104 lists_(Isolate::Current()->current_zone()-> | 110 lists_(Isolate::Current()->current_zone()-> |
| 105 Alloc<HashMapListElement>(other.lists_size_)), | 111 Alloc<HashMapListElement>(other.lists_size_)), |
| 106 free_list_head_(other.free_list_head_) { | 112 free_list_head_(other.free_list_head_) { |
| 107 memmove(array_, other.array_, array_size_ * sizeof(HashMapListElement)); | 113 memmove(array_, other.array_, array_size_ * sizeof(HashMapListElement)); |
| 108 memmove(lists_, other.lists_, lists_size_ * sizeof(HashMapListElement)); | 114 memmove(lists_, other.lists_, lists_size_ * sizeof(HashMapListElement)); |
| 109 } | 115 } |
| 110 | 116 |
| 111 | 117 |
| 112 template <typename KeyValueTrait> | 118 template <typename KeyValueTrait> |
| 113 void DirectChainedHashMap<KeyValueTrait>::Resize(intptr_t new_size) { | 119 void DirectChainedHashMap<KeyValueTrait>::Resize(intptr_t new_size) { |
| 114 const typename KeyValueTrait::Value kNoValue = | 120 const typename KeyValueTrait::Value kNoValue = KeyValueTrait::NoValue(); |
| 115 static_cast<typename KeyValueTrait::Value>(0); | |
| 116 | 121 |
| 117 ASSERT(new_size > count_); | 122 ASSERT(new_size > count_); |
| 118 // Hashing the values into the new array has no more collisions than in the | 123 // 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. | 124 // old hash map, so we can use the existing lists_ array, if we are careful. |
| 120 | 125 |
| 121 // Make sure we have at least one free element. | 126 // Make sure we have at least one free element. |
| 122 if (free_list_head_ == kNil) { | 127 if (free_list_head_ == kNil) { |
| 123 ResizeLists(lists_size_ << 1); | 128 ResizeLists(lists_size_ << 1); |
| 124 } | 129 } |
| 125 | 130 |
| 126 HashMapListElement* new_array = | 131 HashMapListElement* new_array = |
| 127 Isolate::Current()->current_zone()->Alloc<HashMapListElement>(new_size); | 132 Isolate::Current()->current_zone()->Alloc<HashMapListElement>(new_size); |
| 128 memset(new_array, 0, sizeof(HashMapListElement) * new_size); | 133 InitArray(new_array, new_size); |
| 129 | 134 |
| 130 HashMapListElement* old_array = array_; | 135 HashMapListElement* old_array = array_; |
| 131 intptr_t old_size = array_size_; | 136 intptr_t old_size = array_size_; |
| 132 | 137 |
| 133 intptr_t old_count = count_; | 138 intptr_t old_count = count_; |
| 134 count_ = 0; | 139 count_ = 0; |
| 135 array_size_ = new_size; | 140 array_size_ = new_size; |
| 136 array_ = new_array; | 141 array_ = new_array; |
| 137 | 142 |
| 138 if (old_array != NULL) { | 143 if (old_array != NULL) { |
| (...skipping 18 matching lines...) Expand all Loading... |
| 157 } | 162 } |
| 158 | 163 |
| 159 | 164 |
| 160 template <typename T> | 165 template <typename T> |
| 161 void DirectChainedHashMap<T>::ResizeLists(intptr_t new_size) { | 166 void DirectChainedHashMap<T>::ResizeLists(intptr_t new_size) { |
| 162 ASSERT(new_size > lists_size_); | 167 ASSERT(new_size > lists_size_); |
| 163 | 168 |
| 164 HashMapListElement* new_lists = | 169 HashMapListElement* new_lists = |
| 165 Isolate::Current()->current_zone()-> | 170 Isolate::Current()->current_zone()-> |
| 166 Alloc<HashMapListElement>(new_size); | 171 Alloc<HashMapListElement>(new_size); |
| 167 memset(new_lists, 0, sizeof(HashMapListElement) * new_size); | 172 InitArray(new_lists, new_size); |
| 168 | 173 |
| 169 HashMapListElement* old_lists = lists_; | 174 HashMapListElement* old_lists = lists_; |
| 170 intptr_t old_size = lists_size_; | 175 intptr_t old_size = lists_size_; |
| 171 | 176 |
| 172 lists_size_ = new_size; | 177 lists_size_ = new_size; |
| 173 lists_ = new_lists; | 178 lists_ = new_lists; |
| 174 | 179 |
| 175 if (old_lists != NULL) { | 180 if (old_lists != NULL) { |
| 176 memmove(lists_, old_lists, old_size * sizeof(HashMapListElement)); | 181 memmove(lists_, old_lists, old_size * sizeof(HashMapListElement)); |
| 177 } | 182 } |
| 178 for (intptr_t i = old_size; i < lists_size_; ++i) { | 183 for (intptr_t i = old_size; i < lists_size_; ++i) { |
| 179 lists_[i].next = free_list_head_; | 184 lists_[i].next = free_list_head_; |
| 180 free_list_head_ = i; | 185 free_list_head_ = i; |
| 181 } | 186 } |
| 182 } | 187 } |
| 183 | 188 |
| 184 | 189 |
| 185 template <typename KeyValueTrait> | 190 template <typename KeyValueTrait> |
| 186 void DirectChainedHashMap<KeyValueTrait>:: | 191 void DirectChainedHashMap<KeyValueTrait>:: |
| 187 Insert(typename KeyValueTrait::Pair kv) { | 192 Insert(typename KeyValueTrait::Pair kv) { |
| 188 const typename KeyValueTrait::Value kNoValue = | 193 const typename KeyValueTrait::Value kNoValue = KeyValueTrait::NoValue(); |
| 189 static_cast<typename KeyValueTrait::Value>(0); | |
| 190 | 194 |
| 191 ASSERT(KeyValueTrait::ValueOf(kv) != kNoValue); | 195 ASSERT(KeyValueTrait::ValueOf(kv) != kNoValue); |
| 192 // Resizing when half of the hashtable is filled up. | 196 // Resizing when half of the hashtable is filled up. |
| 193 if (count_ >= array_size_ >> 1) Resize(array_size_ << 1); | 197 if (count_ >= array_size_ >> 1) Resize(array_size_ << 1); |
| 194 ASSERT(count_ < array_size_); | 198 ASSERT(count_ < array_size_); |
| 195 count_++; | 199 count_++; |
| 196 uword pos = Bound( | 200 uword pos = Bound( |
| 197 static_cast<uword>(KeyValueTrait::Hashcode(KeyValueTrait::KeyOf(kv)))); | 201 static_cast<uword>(KeyValueTrait::Hashcode(KeyValueTrait::KeyOf(kv)))); |
| 198 if (KeyValueTrait::ValueOf(array_[pos].kv) == kNoValue) { | 202 if (KeyValueTrait::ValueOf(array_[pos].kv) == kNoValue) { |
| 199 array_[pos].kv = kv; | 203 array_[pos].kv = kv; |
| (...skipping 22 matching lines...) Expand all Loading... |
| 222 typedef T* Pair; | 226 typedef T* Pair; |
| 223 | 227 |
| 224 static Key KeyOf(Pair kv) { | 228 static Key KeyOf(Pair kv) { |
| 225 return kv; | 229 return kv; |
| 226 } | 230 } |
| 227 | 231 |
| 228 static Value ValueOf(Pair kv) { | 232 static Value ValueOf(Pair kv) { |
| 229 return kv; | 233 return kv; |
| 230 } | 234 } |
| 231 | 235 |
| 236 static Value NoValue() { return NULL; } |
| 237 |
| 232 static inline intptr_t Hashcode(Key key) { | 238 static inline intptr_t Hashcode(Key key) { |
| 233 return key->Hashcode(); | 239 return key->Hashcode(); |
| 234 } | 240 } |
| 235 | 241 |
| 236 static inline bool IsKeyEqual(Pair kv, Key key) { | 242 static inline bool IsKeyEqual(Pair kv, Key key) { |
| 237 return kv->Equals(key); | 243 return kv->Equals(key); |
| 238 } | 244 } |
| 239 }; | 245 }; |
| 240 | 246 |
| 241 } // namespace dart | 247 } // namespace dart |
| 242 | 248 |
| 243 #endif // VM_HASH_MAP_H_ | 249 #endif // VM_HASH_MAP_H_ |
| OLD | NEW |