v8  3.11.10(node0.8.26)
V8 is Google's open source JavaScript engine
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
hashmap.h
Go to the documentation of this file.
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 
28 #ifndef V8_HASHMAP_H_
29 #define V8_HASHMAP_H_
30 
31 #include "allocation.h"
32 #include "checks.h"
33 #include "utils.h"
34 
35 namespace v8 {
36 namespace internal {
37 
38 template<class AllocationPolicy>
40  public:
41  typedef bool (*MatchFun) (void* key1, void* key2);
42 
43  // The default capacity. This is used by the call sites which want
44  // to pass in a non-default AllocationPolicy but want to use the
45  // default value of capacity specified by the implementation.
46  static const uint32_t kDefaultHashMapCapacity = 8;
47 
48  // initial_capacity is the size of the initial hash map;
49  // it must be a power of 2 (and thus must not be 0).
52  AllocationPolicy allocator = AllocationPolicy());
53 
55 
56  // HashMap entries are (key, value, hash) triplets.
57  // Some clients may not need to use the value slot
58  // (e.g. implementers of sets, where the key is the value).
59  struct Entry {
60  void* key;
61  void* value;
62  uint32_t hash; // the full hash value for key
63  };
64 
65  // If an entry with matching key is found, Lookup()
66  // returns that entry. If no matching entry is found,
67  // but insert is set, a new entry is inserted with
68  // corresponding key, key hash, and NULL value.
69  // Otherwise, NULL is returned.
70  Entry* Lookup(void* key, uint32_t hash, bool insert,
71  AllocationPolicy allocator = AllocationPolicy());
72 
73  // Removes the entry with matching key.
74  // It returns the value of the deleted entry
75  // or null if there is no value for such key.
76  void* Remove(void* key, uint32_t hash);
77 
78  // Empties the hash map (occupancy() == 0).
79  void Clear();
80 
81  // The number of (non-empty) entries in the table.
82  uint32_t occupancy() const { return occupancy_; }
83 
84  // The capacity of the table. The implementation
85  // makes sure that occupancy is at most 80% of
86  // the table capacity.
87  uint32_t capacity() const { return capacity_; }
88 
89  // Iteration
90  //
91  // for (Entry* p = map.Start(); p != NULL; p = map.Next(p)) {
92  // ...
93  // }
94  //
95  // If entries are inserted during iteration, the effect of
96  // calling Next() is undefined.
97  Entry* Start() const;
98  Entry* Next(Entry* p) const;
99 
100  private:
101  MatchFun match_;
102  Entry* map_;
103  uint32_t capacity_;
104  uint32_t occupancy_;
105 
106  Entry* map_end() const { return map_ + capacity_; }
107  Entry* Probe(void* key, uint32_t hash);
108  void Initialize(uint32_t capacity, AllocationPolicy allocator);
109  void Resize(AllocationPolicy allocator);
110 };
111 
113 
114 template<class AllocationPolicy>
116  MatchFun match, uint32_t initial_capacity, AllocationPolicy allocator) {
117  match_ = match;
118  Initialize(initial_capacity, allocator);
119 }
120 
121 
122 template<class AllocationPolicy>
124  AllocationPolicy::Delete(map_);
125 }
126 
127 
128 template<class AllocationPolicy>
131  void* key, uint32_t hash, bool insert, AllocationPolicy allocator) {
132  // Find a matching entry.
133  Entry* p = Probe(key, hash);
134  if (p->key != NULL) {
135  return p;
136  }
137 
138  // No entry found; insert one if necessary.
139  if (insert) {
140  p->key = key;
141  p->value = NULL;
142  p->hash = hash;
143  occupancy_++;
144 
145  // Grow the map if we reached >= 80% occupancy.
146  if (occupancy_ + occupancy_/4 >= capacity_) {
147  Resize(allocator);
148  p = Probe(key, hash);
149  }
150 
151  return p;
152  }
153 
154  // No entry found and none inserted.
155  return NULL;
156 }
157 
158 
159 template<class AllocationPolicy>
160 void* TemplateHashMapImpl<AllocationPolicy>::Remove(void* key, uint32_t hash) {
161  // Lookup the entry for the key to remove.
162  Entry* p = Probe(key, hash);
163  if (p->key == NULL) {
164  // Key not found nothing to remove.
165  return NULL;
166  }
167 
168  void* value = p->value;
169  // To remove an entry we need to ensure that it does not create an empty
170  // entry that will cause the search for another entry to stop too soon. If all
171  // the entries between the entry to remove and the next empty slot have their
172  // initial position inside this interval, clearing the entry to remove will
173  // not break the search. If, while searching for the next empty entry, an
174  // entry is encountered which does not have its initial position between the
175  // entry to remove and the position looked at, then this entry can be moved to
176  // the place of the entry to remove without breaking the search for it. The
177  // entry made vacant by this move is now the entry to remove and the process
178  // starts over.
179  // Algorithm from http://en.wikipedia.org/wiki/Open_addressing.
180 
181  // This guarantees loop termination as there is at least one empty entry so
182  // eventually the removed entry will have an empty entry after it.
183  ASSERT(occupancy_ < capacity_);
184 
185  // p is the candidate entry to clear. q is used to scan forwards.
186  Entry* q = p; // Start at the entry to remove.
187  while (true) {
188  // Move q to the next entry.
189  q = q + 1;
190  if (q == map_end()) {
191  q = map_;
192  }
193 
194  // All entries between p and q have their initial position between p and q
195  // and the entry p can be cleared without breaking the search for these
196  // entries.
197  if (q->key == NULL) {
198  break;
199  }
200 
201  // Find the initial position for the entry at position q.
202  Entry* r = map_ + (q->hash & (capacity_ - 1));
203 
204  // If the entry at position q has its initial position outside the range
205  // between p and q it can be moved forward to position p and will still be
206  // found. There is now a new candidate entry for clearing.
207  if ((q > p && (r <= p || r > q)) ||
208  (q < p && (r <= p && r > q))) {
209  *p = *q;
210  p = q;
211  }
212  }
213 
214  // Clear the entry which is allowed to en emptied.
215  p->key = NULL;
216  occupancy_--;
217  return value;
218 }
219 
220 
221 template<class AllocationPolicy>
223  // Mark all entries as empty.
224  const Entry* end = map_end();
225  for (Entry* p = map_; p < end; p++) {
226  p->key = NULL;
227  }
228  occupancy_ = 0;
229 }
230 
231 
232 template<class AllocationPolicy>
235  return Next(map_ - 1);
236 }
237 
238 
239 template<class AllocationPolicy>
242  const Entry* end = map_end();
243  ASSERT(map_ - 1 <= p && p < end);
244  for (p++; p < end; p++) {
245  if (p->key != NULL) {
246  return p;
247  }
248  }
249  return NULL;
250 }
251 
252 
253 template<class AllocationPolicy>
255  TemplateHashMapImpl<AllocationPolicy>::Probe(void* key, uint32_t hash) {
256  ASSERT(key != NULL);
257 
258  ASSERT(IsPowerOf2(capacity_));
259  Entry* p = map_ + (hash & (capacity_ - 1));
260  const Entry* end = map_end();
261  ASSERT(map_ <= p && p < end);
262 
263  ASSERT(occupancy_ < capacity_); // Guarantees loop termination.
264  while (p->key != NULL && (hash != p->hash || !match_(key, p->key))) {
265  p++;
266  if (p >= end) {
267  p = map_;
268  }
269  }
270 
271  return p;
272 }
273 
274 
275 template<class AllocationPolicy>
276 void TemplateHashMapImpl<AllocationPolicy>::Initialize(
277  uint32_t capacity, AllocationPolicy allocator) {
278  ASSERT(IsPowerOf2(capacity));
279  map_ = reinterpret_cast<Entry*>(allocator.New(capacity * sizeof(Entry)));
280  if (map_ == NULL) {
281  v8::internal::FatalProcessOutOfMemory("HashMap::Initialize");
282  return;
283  }
284  capacity_ = capacity;
285  Clear();
286 }
287 
288 
289 template<class AllocationPolicy>
290 void TemplateHashMapImpl<AllocationPolicy>::Resize(AllocationPolicy allocator) {
291  Entry* map = map_;
292  uint32_t n = occupancy_;
293 
294  // Allocate larger map.
295  Initialize(capacity_ * 2, allocator);
296 
297  // Rehash all current entries.
298  for (Entry* p = map; n > 0; p++) {
299  if (p->key != NULL) {
300  Lookup(p->key, p->hash, true, allocator)->value = p->value;
301  n--;
302  }
303  }
304 
305  // Delete old map.
306  AllocationPolicy::Delete(map);
307 }
308 
309 
310 // A hash map for pointer keys and values with an STL-like interface.
311 template<class Key, class Value, class AllocationPolicy>
312 class TemplateHashMap: private TemplateHashMapImpl<AllocationPolicy> {
313  public:
314  STATIC_ASSERT(sizeof(Key*) == sizeof(void*)); // NOLINT
315  STATIC_ASSERT(sizeof(Value*) == sizeof(void*)); // NOLINT
316  struct value_type {
317  Key* first;
319  };
320 
321  class Iterator {
322  public:
324  entry_ = map_->Next(entry_);
325  return *this;
326  }
327 
328  value_type* operator->() { return reinterpret_cast<value_type*>(entry_); }
329  bool operator!=(const Iterator& other) { return entry_ != other.entry_; }
330 
331  private:
334  map_(map), entry_(entry) { }
335 
338 
339  friend class TemplateHashMap;
340  };
341 
344  AllocationPolicy allocator = AllocationPolicy())
345  : TemplateHashMapImpl<AllocationPolicy>(
346  match,
347  TemplateHashMapImpl<AllocationPolicy>::kDefaultHashMapCapacity,
348  allocator) { }
349 
350  Iterator begin() const { return Iterator(this, this->Start()); }
351  Iterator end() const { return Iterator(this, NULL); }
352  Iterator find(Key* key, bool insert = false,
353  AllocationPolicy allocator = AllocationPolicy()) {
354  return Iterator(this, this->Lookup(key, key->Hash(), insert, allocator));
355  }
356 };
357 
358 } } // namespace v8::internal
359 
360 #endif // V8_HASHMAP_H_
Iterator end() const
Definition: hashmap.h:351
Definition: v8.h:863
Definition: hashmap.h:59
bool operator!=(const Iterator &other)
Definition: hashmap.h:329
Iterator find(Key *key, bool insert=false, AllocationPolicy allocator=AllocationPolicy())
Definition: hashmap.h:352
#define ASSERT(condition)
Definition: checks.h:270
uint32_t hash
Definition: hashmap.h:62
TemplateHashMap(typename TemplateHashMapImpl< AllocationPolicy >::MatchFun match, AllocationPolicy allocator=AllocationPolicy())
Definition: hashmap.h:342
Iterator begin() const
Definition: hashmap.h:350
uint32_t occupancy() const
Definition: hashmap.h:82
Entry * Lookup(void *key, uint32_t hash, bool insert, AllocationPolicy allocator=AllocationPolicy())
Definition: hashmap.h:130
void * key
Definition: hashmap.h:60
STATIC_ASSERT(sizeof(Key *)==sizeof(void *))
bool IsPowerOf2(T x)
Definition: utils.h:50
void FatalProcessOutOfMemory(const char *message)
void * Remove(void *key, uint32_t hash)
Definition: hashmap.h:160
TemplateHashMapImpl(MatchFun match, uint32_t capacity=kDefaultHashMapCapacity, AllocationPolicy allocator=AllocationPolicy())
Definition: hashmap.h:115
TemplateHashMapImpl< FreeStoreAllocationPolicy > HashMap
Definition: hashmap.h:112
activate correct semantics for inheriting readonliness enable harmony semantics for typeof enable harmony enable harmony proxies enable all harmony harmony_scoping harmony_proxies harmony_scoping tracks arrays with only smi values automatically unbox arrays of doubles use crankshaft use hydrogen range analysis use hydrogen global value numbering use function inlining maximum number of AST nodes considered for a single inlining loop invariant code motion print statistics for hydrogen trace generated IR for specified phases trace register allocator trace range analysis trace representation types environment for every instruction put a break point before deoptimizing polymorphic inlining perform array bounds checks elimination trace on stack replacement optimize closures functions with arguments object optimize functions containing for in loops profiler considers IC stability primitive functions trigger their own optimization re try self optimization if it failed insert an interrupt check at function exit execution budget before interrupt is triggered call count before self optimization self_optimization count_based_interrupts weighted_back_edges trace_opt emit comments in code disassembly enable use of SSE3 instructions if available enable use of CMOV instruction if available enable use of SAHF instruction if enable use of VFP3 instructions if available this implies enabling ARMv7 enable use of ARMv7 instructions if enable use of MIPS FPU instructions if NULL
Definition: flags.cc:274
uint32_t capacity() const
Definition: hashmap.h:87
bool(* MatchFun)(void *key1, void *key2)
Definition: hashmap.h:41
static const uint32_t kDefaultHashMapCapacity
Definition: hashmap.h:46
void * value
Definition: hashmap.h:61
Entry * Next(Entry *p) const
Definition: hashmap.h:241