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 T> |
Florian Schneider
2012/10/30 15:31:39
s/T/KeyValueTrait/
Vyacheslav Egorov (Google)
2012/10/30 16:22:35
Done.
| |
73 DirectChainedHashMap<T>::DirectChainedHashMap(const DirectChainedHashMap& other) | 80 DirectChainedHashMap<T>::DirectChainedHashMap(const DirectChainedHashMap& other) |
74 : ValueObject(), | 81 : ValueObject(), |
75 array_size_(other.array_size_), | 82 array_size_(other.array_size_), |
76 lists_size_(other.lists_size_), | 83 lists_size_(other.lists_size_), |
77 count_(other.count_), | 84 count_(other.count_), |
78 array_(Isolate::Current()->current_zone()-> | 85 array_(Isolate::Current()->current_zone()-> |
79 Alloc<HashMapListElement>(other.array_size_)), | 86 Alloc<HashMapListElement>(other.array_size_)), |
80 lists_(Isolate::Current()->current_zone()-> | 87 lists_(Isolate::Current()->current_zone()-> |
81 Alloc<HashMapListElement>(other.lists_size_)), | 88 Alloc<HashMapListElement>(other.lists_size_)), |
82 free_list_head_(other.free_list_head_) { | 89 free_list_head_(other.free_list_head_) { |
83 memmove(array_, other.array_, array_size_ * sizeof(HashMapListElement)); | 90 memmove(array_, other.array_, array_size_ * sizeof(HashMapListElement)); |
84 memmove(lists_, other.lists_, lists_size_ * sizeof(HashMapListElement)); | 91 memmove(lists_, other.lists_, lists_size_ * sizeof(HashMapListElement)); |
85 } | 92 } |
86 | 93 |
87 | 94 |
88 template <typename T> | 95 template <typename KeyValueTrait> |
89 void DirectChainedHashMap<T>::Resize(intptr_t new_size) { | 96 void DirectChainedHashMap<KeyValueTrait>::Resize(intptr_t new_size) { |
90 ASSERT(new_size > count_); | 97 ASSERT(new_size > count_); |
91 // Hashing the values into the new array has no more collisions than in the | 98 // 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. | 99 // old hash map, so we can use the existing lists_ array, if we are careful. |
93 | 100 |
94 // Make sure we have at least one free element. | 101 // Make sure we have at least one free element. |
95 if (free_list_head_ == kNil) { | 102 if (free_list_head_ == kNil) { |
96 ResizeLists(lists_size_ << 1); | 103 ResizeLists(lists_size_ << 1); |
97 } | 104 } |
98 | 105 |
99 HashMapListElement* new_array = | 106 HashMapListElement* new_array = |
100 Isolate::Current()->current_zone()->Alloc<HashMapListElement>(new_size); | 107 Isolate::Current()->current_zone()->Alloc<HashMapListElement>(new_size); |
101 memset(new_array, 0, sizeof(HashMapListElement) * new_size); | 108 memset(new_array, 0, sizeof(HashMapListElement) * new_size); |
102 | 109 |
103 HashMapListElement* old_array = array_; | 110 HashMapListElement* old_array = array_; |
104 intptr_t old_size = array_size_; | 111 intptr_t old_size = array_size_; |
105 | 112 |
106 intptr_t old_count = count_; | 113 intptr_t old_count = count_; |
107 count_ = 0; | 114 count_ = 0; |
108 array_size_ = new_size; | 115 array_size_ = new_size; |
109 array_ = new_array; | 116 array_ = new_array; |
110 | 117 |
111 if (old_array != NULL) { | 118 if (old_array != NULL) { |
112 // Iterate over all the elements in lists, rehashing them. | 119 // Iterate over all the elements in lists, rehashing them. |
113 for (intptr_t i = 0; i < old_size; ++i) { | 120 for (intptr_t i = 0; i < old_size; ++i) { |
114 if (old_array[i].value != NULL) { | 121 if (KeyValueTrait::ValueOf(old_array[i].kv) != NULL) { |
115 intptr_t current = old_array[i].next; | 122 intptr_t current = old_array[i].next; |
116 while (current != kNil) { | 123 while (current != kNil) { |
117 Insert(lists_[current].value); | 124 Insert(lists_[current].kv); |
118 intptr_t next = lists_[current].next; | 125 intptr_t next = lists_[current].next; |
119 lists_[current].next = free_list_head_; | 126 lists_[current].next = free_list_head_; |
120 free_list_head_ = current; | 127 free_list_head_ = current; |
121 current = next; | 128 current = next; |
122 } | 129 } |
123 // Rehash the directly stored value. | 130 // Rehash the directly stored value. |
124 Insert(old_array[i].value); | 131 Insert(old_array[i].kv); |
125 } | 132 } |
126 } | 133 } |
127 } | 134 } |
128 USE(old_count); | 135 USE(old_count); |
129 ASSERT(count_ == old_count); | 136 ASSERT(count_ == old_count); |
130 } | 137 } |
131 | 138 |
132 | 139 |
133 template <typename T> | 140 template <typename T> |
134 void DirectChainedHashMap<T>::ResizeLists(intptr_t new_size) { | 141 void DirectChainedHashMap<T>::ResizeLists(intptr_t new_size) { |
(...skipping 13 matching lines...) Expand all Loading... | |
148 if (old_lists != NULL) { | 155 if (old_lists != NULL) { |
149 memmove(lists_, old_lists, old_size * sizeof(HashMapListElement)); | 156 memmove(lists_, old_lists, old_size * sizeof(HashMapListElement)); |
150 } | 157 } |
151 for (intptr_t i = old_size; i < lists_size_; ++i) { | 158 for (intptr_t i = old_size; i < lists_size_; ++i) { |
152 lists_[i].next = free_list_head_; | 159 lists_[i].next = free_list_head_; |
153 free_list_head_ = i; | 160 free_list_head_ = i; |
154 } | 161 } |
155 } | 162 } |
156 | 163 |
157 | 164 |
158 template <typename T> | 165 template <typename KeyValueTrait> |
159 void DirectChainedHashMap<T>::Insert(T value) { | 166 void DirectChainedHashMap<KeyValueTrait>:: |
160 ASSERT(value != NULL); | 167 Insert(typename KeyValueTrait::Pair kv) { |
168 ASSERT(KeyValueTrait::ValueOf(kv) != NULL); | |
161 // Resizing when half of the hashtable is filled up. | 169 // Resizing when half of the hashtable is filled up. |
162 if (count_ >= array_size_ >> 1) Resize(array_size_ << 1); | 170 if (count_ >= array_size_ >> 1) Resize(array_size_ << 1); |
163 ASSERT(count_ < array_size_); | 171 ASSERT(count_ < array_size_); |
164 count_++; | 172 count_++; |
165 uword pos = Bound(static_cast<uword>(value->Hashcode())); | 173 uword pos = Bound( |
166 if (array_[pos].value == NULL) { | 174 static_cast<uword>(KeyValueTrait::Hashcode(KeyValueTrait::KeyOf(kv)))); |
167 array_[pos].value = value; | 175 if (KeyValueTrait::ValueOf(array_[pos].kv) == NULL) { |
176 array_[pos].kv = kv; | |
168 array_[pos].next = kNil; | 177 array_[pos].next = kNil; |
169 } else { | 178 } else { |
170 if (free_list_head_ == kNil) { | 179 if (free_list_head_ == kNil) { |
171 ResizeLists(lists_size_ << 1); | 180 ResizeLists(lists_size_ << 1); |
172 } | 181 } |
173 intptr_t new_element_pos = free_list_head_; | 182 intptr_t new_element_pos = free_list_head_; |
174 ASSERT(new_element_pos != kNil); | 183 ASSERT(new_element_pos != kNil); |
175 free_list_head_ = lists_[free_list_head_].next; | 184 free_list_head_ = lists_[free_list_head_].next; |
176 lists_[new_element_pos].value = value; | 185 lists_[new_element_pos].kv = kv; |
177 lists_[new_element_pos].next = array_[pos].next; | 186 lists_[new_element_pos].next = array_[pos].next; |
178 ASSERT(array_[pos].next == kNil || lists_[array_[pos].next].value != NULL); | 187 ASSERT(array_[pos].next == kNil || |
188 KeyValueTrait::ValueOf(lists_[array_[pos].next].kv) != NULL); | |
179 array_[pos].next = new_element_pos; | 189 array_[pos].next = new_element_pos; |
180 } | 190 } |
181 } | 191 } |
182 | 192 |
193 | |
194 template<typename T> | |
195 class PointerKeyValueTrait { | |
196 public: | |
197 typedef T* Value; | |
198 typedef T* Key; | |
199 typedef T* Pair; | |
200 | |
201 static Key KeyOf(Pair p) { | |
202 return p; | |
203 } | |
204 | |
205 static Value ValueOf(Pair p) { | |
Florian Schneider
2012/10/30 15:31:39
for naming consistency use either "Pair kv" or "Pa
Vyacheslav Egorov (Google)
2012/10/30 16:22:35
Done.
| |
206 return p; | |
207 } | |
208 | |
209 static inline intptr_t Hashcode(Key key) { | |
210 return key->Hashcode(); | |
211 } | |
212 | |
213 static inline intptr_t IsKeyEqual(Pair kv, Key key) { | |
Florian Schneider
2012/10/30 15:31:39
bool IsKeyEqual?
Vyacheslav Egorov (Google)
2012/10/30 16:22:35
Done.
| |
214 return kv->Equals(key); | |
215 } | |
216 }; | |
217 | |
183 } // namespace dart | 218 } // namespace dart |
184 | 219 |
185 #endif // VM_HASH_MAP_H_ | 220 #endif // VM_HASH_MAP_H_ |
OLD | NEW |