authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-07-03 03:49:03+00:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-07-03 03:50:35+00:00
log22f0a103c39f84140ee1fbfe2bffed5fcec19a26
treecf015b59b782b34cf3b9a03c079c717a567a7233
parentdf2c27eb486383a291dfe1db3dfda51f830f59c5

stage1 HashMap: linear scan for < 16 entries


1 files changed, 49 insertions(+), 9 deletions(-)

src/hash_map.hpp+49-9
...@@ -45,6 +45,26 @@ public:...@@ -45,6 +45,26 @@ public:
45 void put(const K &key, const V &value) {45 void put(const K &key, const V &value) {
46 _modification_count += 1;46 _modification_count += 1;
4747
48 // This allows us to take a pointer to an entry in `internal_put` which
49 // will not become a dead pointer when the array list is appended.
50 _entries.ensure_capacity(_entries.length + 1);
51
52 if (_index_bytes == nullptr) {
53 if (_entries.length < 16) {
54 _entries.append({HashFunction(key), 0, key, value});
55 return;
56 } else {
57 _indexes_len = 32;
58 _index_bytes = heap::c_allocator.allocate<uint8_t>(_indexes_len);
59 _max_distance_from_start_index = 0;
60 for (size_t i = 0; i < _entries.length; i += 1) {
61 Entry *entry = &_entries.items[i];
62 put_index(entry, i, _index_bytes);
63 }
64 return internal_put(key, value, _index_bytes);
65 }
66 }
67
48 // if we would get too full (60%), double the indexes size68 // if we would get too full (60%), double the indexes size
49 if ((_entries.length + 1) * 5 >= _indexes_len * 3) {69 if ((_entries.length + 1) * 5 >= _indexes_len * 3) {
50 heap::c_allocator.deallocate(_index_bytes,70 heap::c_allocator.deallocate(_index_bytes,
...@@ -73,10 +93,6 @@ public:...@@ -73,10 +93,6 @@ public:
73 }93 }
74 }94 }
7595
76 // This allows us to take a pointer to an entry in `internal_put` which
77 // will not become a dead pointer when the array list is appended.
78 _entries.ensure_capacity(_entries.length + 1);
79
80 switch (capacity_index_size(_indexes_len)) {96 switch (capacity_index_size(_indexes_len)) {
81 case 1: return internal_put(key, value, (uint8_t*)_index_bytes);97 case 1: return internal_put(key, value, (uint8_t*)_index_bytes);
82 case 2: return internal_put(key, value, (uint16_t*)_index_bytes);98 case 2: return internal_put(key, value, (uint16_t*)_index_bytes);
...@@ -114,6 +130,16 @@ public:...@@ -114,6 +130,16 @@ public:
114130
115 bool maybe_remove(const K &key) {131 bool maybe_remove(const K &key) {
116 _modification_count += 1;132 _modification_count += 1;
133 if (_index_bytes == nullptr) {
134 uint32_t hash = HashFunction(key);
135 for (size_t i = 0; i < _entries.length; i += 1) {
136 if (_entries.items[i].hash == hash && EqualFn(_entries.items[i].key, key)) {
137 _entries.swap_remove(i);
138 return true;
139 }
140 }
141 return false;
142 }
117 switch (capacity_index_size(_indexes_len)) {143 switch (capacity_index_size(_indexes_len)) {
118 case 1: return internal_remove(key, (uint8_t*)_index_bytes);144 case 1: return internal_remove(key, (uint8_t*)_index_bytes);
119 case 2: return internal_remove(key, (uint16_t*)_index_bytes);145 case 2: return internal_remove(key, (uint16_t*)_index_bytes);
...@@ -170,11 +196,16 @@ private:...@@ -170,11 +196,16 @@ private:
170 void init_capacity(size_t capacity) {196 void init_capacity(size_t capacity) {
171 _entries = {};197 _entries = {};
172 _entries.ensure_capacity(capacity);198 _entries.ensure_capacity(capacity);
173 // So that at capacity it will only be 60% full.199 _indexes_len = 0;
174 _indexes_len = capacity * 5 / 3;200 if (capacity >= 16) {
175 size_t sz = capacity_index_size(_indexes_len);201 // So that at capacity it will only be 60% full.
176 // This zero initializes _index_bytes which sets them all to empty.202 _indexes_len = capacity * 5 / 3;
177 _index_bytes = heap::c_allocator.allocate<uint8_t>(_indexes_len * sz);203 size_t sz = capacity_index_size(_indexes_len);
204 // This zero initializes _index_bytes which sets them all to empty.
205 _index_bytes = heap::c_allocator.allocate<uint8_t>(_indexes_len * sz);
206 } else {
207 _index_bytes = nullptr;
208 }
178209
179 _max_distance_from_start_index = 0;210 _max_distance_from_start_index = 0;
180 _modification_count = 0;211 _modification_count = 0;
...@@ -290,6 +321,15 @@ private:...@@ -290,6 +321,15 @@ private:
290 }321 }
291322
292 Entry *internal_get(const K &key) const {323 Entry *internal_get(const K &key) const {
324 if (_index_bytes == nullptr) {
325 uint32_t hash = HashFunction(key);
326 for (size_t i = 0; i < _entries.length; i += 1) {
327 if (_entries.items[i].hash == hash && EqualFn(_entries.items[i].key, key)) {
328 return &_entries.items[i];
329 }
330 }
331 return nullptr;
332 }
293 switch (capacity_index_size(_indexes_len)) {333 switch (capacity_index_size(_indexes_len)) {
294 case 1: return internal_get2(key, (uint8_t*)_index_bytes);334 case 1: return internal_get2(key, (uint8_t*)_index_bytes);
295 case 2: return internal_get2(key, (uint16_t*)_index_bytes);335 case 2: return internal_get2(key, (uint16_t*)_index_bytes);