blob: 126f7392411128a79dd18e16f615b5b7a535de45 [file] [log] [blame]
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001// Copyright 2008 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// 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#include "v8.h"
29
30#include "hashmap.h"
31
32namespace v8 { namespace internal {
33
34
35static inline bool IsPowerOf2(uint32_t x) {
36 ASSERT(x != 0);
37 return (x & (x - 1)) == 0;
38}
39
40
41Allocator HashMap::DefaultAllocator;
42
43
44HashMap::HashMap() {
45 allocator_ = NULL;
46 match_ = NULL;
47}
48
49
50HashMap::HashMap(MatchFun match,
51 Allocator* allocator,
52 uint32_t initial_capacity) {
53 allocator_ = allocator;
54 match_ = match;
55 Initialize(initial_capacity);
56}
57
58
59HashMap::~HashMap() {
60 if (allocator_) {
61 allocator_->Delete(map_);
62 }
63}
64
65
66HashMap::Entry* HashMap::Lookup(void* key, uint32_t hash, bool insert) {
67 // Find a matching entry.
68 Entry* p = Probe(key, hash);
69 if (p->key != NULL) {
70 return p;
71 }
72
73 // No entry found; insert one if necessary.
74 if (insert) {
75 p->key = key;
76 p->value = NULL;
77 p->hash = hash;
78 occupancy_++;
79
80 // Grow the map if we reached >= 80% occupancy.
81 if (occupancy_ + occupancy_/4 >= capacity_) {
82 Resize();
83 p = Probe(key, hash);
84 }
85
86 return p;
87 }
88
89 // No entry found and none inserted.
90 return NULL;
91}
92
93
94void HashMap::Clear() {
95 // Mark all entries as empty.
96 const Entry* end = map_end();
97 for (Entry* p = map_; p < end; p++) {
98 p->key = NULL;
99 }
100 occupancy_ = 0;
101}
102
103
104HashMap::Entry* HashMap::Start() const {
105 return Next(map_ - 1);
106}
107
108
109HashMap::Entry* HashMap::Next(Entry* p) const {
110 const Entry* end = map_end();
111 ASSERT(map_ - 1 <= p && p < end);
112 for (p++; p < end; p++) {
113 if (p->key != NULL) {
114 return p;
115 }
116 }
117 return NULL;
118}
119
120
121HashMap::Entry* HashMap::Probe(void* key, uint32_t hash) {
122 ASSERT(key != NULL);
123
124 ASSERT(IsPowerOf2(capacity_));
125 Entry* p = map_ + (hash & (capacity_ - 1));
126 const Entry* end = map_end();
127 ASSERT(map_ <= p && p < end);
128
129 ASSERT(occupancy_ < capacity_); // guarantees loop termination
130 while (p->key != NULL && (hash != p->hash || !match_(key, p->key))) {
131 p++;
132 if (p >= end) {
133 p = map_;
134 }
135 }
136
137 return p;
138}
139
140
141void HashMap::Initialize(uint32_t capacity) {
142 ASSERT(IsPowerOf2(capacity));
143 map_ = reinterpret_cast<Entry*>(allocator_->New(capacity * sizeof(Entry)));
144 if (map_ == NULL) V8::FatalProcessOutOfMemory("HashMap::Initialize");
145 capacity_ = capacity;
146 Clear();
147}
148
149
150void HashMap::Resize() {
151 Entry* map = map_;
152 uint32_t n = occupancy_;
153
154 // Allocate larger map.
155 Initialize(capacity_ * 2);
156
157 // Rehash all current entries.
158 for (Entry* p = map; n > 0; p++) {
159 if (p->key != NULL) {
160 Lookup(p->key, p->hash, true)->value = p->value;
161 n--;
162 }
163 }
164
165 // Delete old map.
166 allocator_->Delete(map);
167}
168
169
170} } // namespace v8::internal