Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(273)

Side by Side Diff: runtime/bin/hashmap.cc

Issue 9186035: Use hash map for event handler file descriptor map (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Minor fixes Created 8 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 #include "bin/builtin.h"
6 #include "bin/hashmap.h"
7 #include "bin/utils.h"
8
9 HashMap::HashMap(MatchFun match,
10 uint32_t initial_capacity) {
11 match_ = match;
12 Initialize(initial_capacity);
13 }
14
15
16 HashMap::~HashMap() {
17 free(map_);
18 }
19
20
21 HashMap::Entry* HashMap::Lookup(void* key, uint32_t hash, bool insert) {
22 // Find a matching entry.
23 Entry* p = Probe(key, hash);
24 if (p->key != NULL) {
25 return p;
26 }
27
28 // No entry found; insert one if necessary.
29 if (insert) {
30 p->key = key;
31 p->value = NULL;
32 p->hash = hash;
33 occupancy_++;
34
35 // Grow the map if we reached >= 80% occupancy.
36 if (occupancy_ + occupancy_/4 >= capacity_) {
Mads Ager (chromium) 2012/01/13 13:33:16 occupancy_ + (occupancy_ / 4)
Søren Gjesse 2012/01/13 14:51:23 Done.
37 Resize();
38 p = Probe(key, hash);
39 }
40
41 return p;
42 }
43
44 // No entry found and none inserted.
45 return NULL;
46 }
47
48
49 void HashMap::Remove(void* key, uint32_t hash) {
50 // Lookup the entry for the key to remove.
51 Entry* p = Probe(key, hash);
52 if (p->key == NULL) {
53 // Key not found nothing to remove.
54 return;
55 }
56
57 // To remove an entry we need to ensure that it does not create an empty
58 // entry that will cause the search for another entry to stop too soon. If all
59 // the entries between the entry to remove and the next empty slot have their
60 // initial position inside this interval, clearing the entry to remove will
61 // not break the search. If, while searching for the next empty entry, an
62 // entry is encountered which does not have its initial position between the
63 // entry to remove and the position looked at, then this entry can be moved to
64 // the place of the entry to remove without breaking the search for it. The
65 // entry made vacant by this move is now the entry to remove and the process
66 // starts over.
67 // Algorithm from http://en.wikipedia.org/wiki/Open_addressing.
68
69 // This guarantees loop termination as there is at least one empty entry so
70 // eventually the removed entry will have an empty entry after it.
71 ASSERT(occupancy_ < capacity_);
72
73 // p is the candidate entry to clear. q is used to scan forwards.
74 Entry* q = p; // Start at the entry to remove.
75 while (true) {
76 // Move q to the next entry.
77 q = q + 1;
78 if (q == map_end()) {
79 q = map_;
80 }
81
82 // All entries between p and q have their initial position between p and q
83 // and the entry p can be cleared without breaking the search for these
84 // entries.
85 if (q->key == NULL) {
86 break;
87 }
88
89 // Find the initial position for the entry at position q.
90 Entry* r = map_ + (q->hash & (capacity_ - 1));
91
92 // If the entry at position q has its initial position outside the range
93 // between p and q it can be moved forward to position p and will still be
94 // found. There is now a new candidate entry for clearing.
95 if ((q > p && (r <= p || r > q)) ||
96 (q < p && (r <= p && r > q))) {
97 *p = *q;
98 p = q;
99 }
100 }
101
102 // Clear the entry which is allowed to en emptied.
103 p->key = NULL;
104 occupancy_--;
105 }
106
107
108 void HashMap::Clear() {
109 // Mark all entries as empty.
110 const Entry* end = map_end();
111 for (Entry* p = map_; p < end; p++) {
112 p->key = NULL;
113 }
114 occupancy_ = 0;
115 }
116
117
118 HashMap::Entry* HashMap::Start() const {
119 return Next(map_ - 1);
120 }
121
122
123 HashMap::Entry* HashMap::Next(Entry* p) const {
124 const Entry* end = map_end();
125 ASSERT(map_ - 1 <= p && p < end);
126 for (p++; p < end; p++) {
127 if (p->key != NULL) {
128 return p;
129 }
130 }
131 return NULL;
132 }
133
134
135 HashMap::Entry* HashMap::Probe(void* key, uint32_t hash) {
136 ASSERT(key != NULL);
137
138 ASSERT(IsPowerOf2(capacity_));
139 Entry* p = map_ + (hash & (capacity_ - 1));
140 const Entry* end = map_end();
141 ASSERT(map_ <= p && p < end);
142
143 ASSERT(occupancy_ < capacity_); // Guarantees loop termination.
144 while (p->key != NULL && (hash != p->hash || !match_(key, p->key))) {
145 p++;
146 if (p >= end) {
147 p = map_;
148 }
149 }
150
151 return p;
152 }
153
154
155 void HashMap::Initialize(uint32_t capacity) {
156 ASSERT(IsPowerOf2(capacity));
157 map_ = reinterpret_cast<Entry*>(malloc(capacity * sizeof(Entry)));
158 if (map_ == NULL) {
159 // TODO(sgjesse): Handle out of memeory.
160 abort();
161 return;
162 }
163 capacity_ = capacity;
164 Clear();
165 }
166
167
168 void HashMap::Resize() {
169 Entry* map = map_;
170 uint32_t n = occupancy_;
171
172 // Allocate larger map.
173 Initialize(capacity_ * 2);
174
175 // Rehash all current entries.
176 for (Entry* p = map; n > 0; p++) {
177 if (p->key != NULL) {
178 Lookup(p->key, p->hash, true)->value = p->value;
179 n--;
180 }
181 }
182
183 // Delete old map.
184 free(map);
185 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698