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 |