v2 / vlib / builtin / map.v
917 lines · 855 sloc · 24.66 KB · e2e5cf8db56f3562c7baa735061690be936bdf3e
Raw
1// Copyright (c) 2019-2024 Alexander Medvednikov. All rights reserved.
2// Use of this source code is governed by an MIT license
3// that can be found in the LICENSE file.
4module builtin
5
6/*
7This is a highly optimized hashmap implementation. It has several traits that
8in combination makes it very fast and memory efficient. Here is a short expl-
9anation of each trait. After reading this you should have a basic understand-
10ing of how it functions:
11
121. Hash-function: Wyhash. Wyhash is the fastest hash-function for short keys
13passing SMHasher, so it was an obvious choice.
14
152. Open addressing: Robin Hood Hashing. With this method, a hash-collision is
16resolved by probing. As opposed to linear probing, Robin Hood hashing has a
17simple but clever twist: As new keys are inserted, old keys are shifted arou-
18nd in a way such that all keys stay reasonably close to the slot they origin-
19ally hash to. A new key may displace a key already inserted if its probe cou-
20nt is larger than that of the key at the current position.
21
223. Memory layout: key-value pairs are stored in a `DenseArray`. This is a dy-
23namic array with a very low volume of unused memory, at the cost of more rea-
24llocations when inserting elements. It also preserves the order of the key-v-
25alues. This array is named `key_values`. Instead of probing a new key-value,
26this map probes two 32-bit numbers collectively. The first number has its 8
27most significant bits reserved for the probe-count and the remaining 24 bits
28are cached bits from the hash which are utilized for faster re-hashing. This
29number is often referred to as `meta`. The other 32-bit number is the index
30at which the key-value was pushed to in `key_values`. Both of these numbers
31are stored in a sparse array `metas`. The `meta`s and `kv_index`s are stored
32at even and odd indices, respectively:
33
34metas = [meta, kv_index, 0, 0, meta, kv_index, 0, 0, meta, kv_index, ...]
35key_values = [kv, kv, kv, ...]
36
374. The size of metas is a power of two. This enables the use of bitwise AND
38to convert the 64-bit hash to a bucket/index that doesn't overflow metas. If
39the size is power of two you can use "hash & (SIZE - 1)" instead of "hash %
40SIZE". Modulo is extremely expensive so using '&' is a big performance impro-
41vement. The general concern with this approach is that you only make use of
42the lower bits of the hash which can cause more collisions. This is solved by
43using a well-dispersed hash-function.
44
455. The hashmap keeps track of the highest probe_count. The trick is to alloc-
46ate `extra_metas` > max(probe_count), so you never have to do any bounds-che-
47cking since the extra meta memory ensures that a meta will never go beyond
48the last index.
49
506. Cached rehashing. When the `load_factor` of the map exceeds the `max_load_
51factor` the size of metas is doubled and all the key-values are "rehashed" to
52find the index for their meta's in the new array. Instead of rehashing compl-
53etely, it simply uses the cached-hashbits stored in the meta, resulting in
54much faster rehashing.
55*/
56// Number of bits from the hash stored for each entry
57const hashbits = 24
58// Number of bits from the hash stored for rehashing
59const max_cached_hashbits = 16
60// Initial log-number of buckets in the hashtable
61const init_log_capicity = 5
62// Initial number of buckets in the hashtable
63const init_capicity = 1 << init_log_capicity
64// Maximum load-factor (len / capacity)
65const max_load_factor = 0.8
66// Initial highest even index in metas
67const init_even_index = init_capicity - 2
68// Used for incrementing `extra_metas` when max
69// probe count is too high, to avoid overflow
70const extra_metas_inc = 4
71// Bitmask to select all the hashbits
72const hash_mask = u32(0x00FFFFFF)
73// Used for incrementing the probe-count
74const probe_inc = u32(0x01000000)
75
76// DenseArray represents a dynamic array with very low growth factor
77struct DenseArray {
78 key_bytes int
79 value_bytes int
80mut:
81 cap int
82 len int
83 deletes u32 // count
84 // array allocated (with `cap` bytes) on first deletion
85 // has non-zero element when key deleted
86 all_deleted &u8 = unsafe { nil }
87 keys &u8 = unsafe { nil }
88 values &u8 = unsafe { nil }
89}
90
91@[inline]
92fn new_dense_array(key_bytes int, value_bytes int) DenseArray {
93 cap := 8
94 return DenseArray{
95 key_bytes: key_bytes
96 value_bytes: value_bytes
97 cap: cap
98 len: 0
99 deletes: 0
100 all_deleted: unsafe { nil }
101 keys: unsafe { malloc(__at_least_one(u64(cap) * u64(key_bytes))) }
102 values: unsafe { malloc(__at_least_one(u64(cap) * u64(value_bytes))) }
103 }
104}
105
106@[inline]
107fn (d &DenseArray) key(i int) voidptr {
108 return unsafe { voidptr(d.keys + i * d.key_bytes) }
109}
110
111// for cgen
112@[inline]
113fn (d &DenseArray) value(i int) voidptr {
114 return unsafe { voidptr(d.values + i * d.value_bytes) }
115}
116
117@[inline]
118fn (d &DenseArray) has_index(i int) bool {
119 return d.deletes == 0 || unsafe { d.all_deleted[i] } == 0
120}
121
122@[inline]
123fn (mut d DenseArray) trim_deleted_tail() {
124 if d.deletes == 0 {
125 return
126 }
127 for d.len > 0 && unsafe { d.all_deleted[d.len - 1] } != 0 {
128 unsafe {
129 d.all_deleted[d.len - 1] = 0
130 }
131 d.deletes--
132 d.len--
133 }
134 if d.deletes == 0 {
135 unsafe {
136 free(d.all_deleted)
137 d.all_deleted = nil
138 }
139 }
140}
141
142// Make space to append an element and return index
143// The growth-factor is roughly 1.125 `(x + (x >> 3))`
144@[inline]
145fn (mut d DenseArray) expand() int {
146 old_cap := d.cap
147 old_key_size := d.key_bytes * old_cap
148 old_value_size := d.value_bytes * old_cap
149 if d.cap == d.len {
150 d.cap += d.cap >> 3
151 unsafe {
152 d.keys = realloc_data(d.keys, old_key_size, d.key_bytes * d.cap)
153 d.values = realloc_data(d.values, old_value_size, d.value_bytes * d.cap)
154 if d.deletes != 0 {
155 d.all_deleted = realloc_data(d.all_deleted, old_cap, d.cap)
156 vmemset(voidptr(d.all_deleted + d.len), 0, d.cap - d.len)
157 }
158 }
159 }
160 push_index := d.len
161 unsafe {
162 if d.deletes != 0 {
163 d.all_deleted[push_index] = 0
164 }
165 }
166 d.len++
167 return push_index
168}
169
170type MapHashFn = fn (voidptr) u64
171
172type MapEqFn = fn (voidptr, voidptr) bool
173
174type MapCloneFn = fn (voidptr, voidptr)
175
176type MapFreeFn = fn (voidptr)
177
178// map is the internal representation of a V `map` type.
179pub struct map {
180 // Number of bytes of a key
181 key_bytes int
182 // Number of bytes of a value
183 value_bytes int
184mut:
185 // Highest even index in the hashtable
186 even_index u32
187 // Number of cached hashbits left for rehashing
188 cached_hashbits u8
189 // Used for right-shifting out used hashbits
190 shift u8
191 // Array storing key-values (ordered)
192 key_values DenseArray
193 // Pointer to meta-data:
194 // - Odd indices store kv_index.
195 // - Even indices store probe_count and hashbits.
196 metas &u32
197 // Extra metas that allows for no ranging when incrementing
198 // index in the hashmap
199 extra_metas u32
200 has_string_keys bool
201 hash_fn MapHashFn
202 key_eq_fn MapEqFn
203 clone_fn MapCloneFn
204 free_fn MapFreeFn
205pub mut:
206 // Number of key-values currently in the hashmap
207 len int
208}
209
210@[inline]
211fn map_eq_string(a voidptr, b voidptr) bool {
212 return fast_string_eq(*unsafe { &string(a) }, *unsafe { &string(b) })
213}
214
215@[inline]
216fn map_eq_int_1(a voidptr, b voidptr) bool {
217 return unsafe { *&u8(a) == *&u8(b) }
218}
219
220@[inline]
221fn map_eq_int_2(a voidptr, b voidptr) bool {
222 return unsafe { *&u16(a) == *&u16(b) }
223}
224
225@[inline]
226fn map_eq_int_4(a voidptr, b voidptr) bool {
227 return unsafe { *&u32(a) == *&u32(b) }
228}
229
230@[inline]
231fn map_eq_int_8(a voidptr, b voidptr) bool {
232 return unsafe { *&u64(a) == *&u64(b) }
233}
234
235// map_map_eq compares two maps for equality.
236// Returns true if both maps have the same keys and associated values.
237fn map_map_eq(a map, b map) bool {
238 if a.len != b.len {
239 return false
240 }
241 for i := 0; i < a.key_values.len; i++ {
242 if !a.key_values.has_index(i) {
243 continue
244 }
245 k := a.key_values.key(i)
246 if !b.exists(k) {
247 return false
248 }
249 va := a.key_values.value(i)
250 vb := b.get(k, va)
251 if unsafe { vmemcmp(va, vb, a.value_bytes) } != 0 {
252 return false
253 }
254 }
255 return true
256}
257
258@[inline]
259fn map_clone_string(dest voidptr, pkey voidptr) {
260 unsafe {
261 s := *&string(pkey)
262 cloned := s.clone()
263 // Use memcpy for native backend compatibility
264 // (*&string(dest)) = cloned doesn't reliably store full struct
265 vmemcpy(dest, voidptr(&cloned), sizeof(string))
266 }
267}
268
269@[inline]
270fn map_clone_int_1(dest voidptr, pkey voidptr) {
271 unsafe {
272 *&u8(dest) = *&u8(pkey)
273 }
274}
275
276@[inline]
277fn map_clone_int_2(dest voidptr, pkey voidptr) {
278 unsafe {
279 *&u16(dest) = *&u16(pkey)
280 }
281}
282
283@[inline]
284fn map_clone_int_4(dest voidptr, pkey voidptr) {
285 unsafe {
286 *&u32(dest) = *&u32(pkey)
287 }
288}
289
290@[inline]
291fn map_clone_int_8(dest voidptr, pkey voidptr) {
292 unsafe {
293 *&u64(dest) = *&u64(pkey)
294 }
295}
296
297@[inline]
298fn map_free_string(pkey voidptr) {
299 unsafe {
300 (*&string(pkey)).free()
301 }
302}
303
304@[inline]
305fn map_free_nop(_ voidptr) {
306}
307
308fn new_map(key_bytes int, value_bytes int, hash_fn MapHashFn, key_eq_fn MapEqFn, clone_fn MapCloneFn, free_fn MapFreeFn) map {
309 metasize := int(sizeof(u32) * (init_capicity + extra_metas_inc))
310 // for now assume anything bigger than a pointer is a string
311 has_string_keys := key_bytes > int(sizeof(voidptr))
312 return map{
313 key_bytes: key_bytes
314 value_bytes: value_bytes
315 even_index: init_even_index
316 cached_hashbits: max_cached_hashbits
317 shift: init_log_capicity
318 key_values: new_dense_array(key_bytes, value_bytes)
319 metas: unsafe { &u32(vcalloc_noscan(metasize)) }
320 extra_metas: extra_metas_inc
321 len: 0
322 has_string_keys: has_string_keys
323 hash_fn: hash_fn
324 key_eq_fn: key_eq_fn
325 clone_fn: clone_fn
326 free_fn: free_fn
327 }
328}
329
330fn new_map_init(hash_fn MapHashFn, key_eq_fn MapEqFn, clone_fn MapCloneFn, free_fn MapFreeFn, n int, key_bytes int,
331 value_bytes int, keys voidptr, values voidptr) map {
332 mut out := new_map(key_bytes, value_bytes, hash_fn, key_eq_fn, clone_fn, free_fn)
333 // TODO: pre-allocate n slots
334 mut pkey := &u8(keys)
335 mut pval := &u8(values)
336 for _ in 0 .. n {
337 unsafe {
338 out.set(pkey, pval)
339 pkey = pkey + key_bytes
340 pval = pval + value_bytes
341 }
342 }
343 return out
344}
345
346fn new_map_update_init(update &map, n int, key_bytes int, value_bytes int, keys voidptr, values voidptr) map {
347 mut out := unsafe { update.clone() }
348 mut pkey := &u8(keys)
349 mut pval := &u8(values)
350 for _ in 0 .. n {
351 unsafe {
352 out.set(pkey, pval)
353 pkey = pkey + key_bytes
354 pval = pval + value_bytes
355 }
356 }
357 return out
358}
359
360// move moves the map to a new location in memory.
361// It does this by copying to a new location, then setting the
362// old location to all `0` with `vmemset`
363pub fn (mut m map) move() map {
364 r := *m
365 unsafe {
366 vmemset(m, 0, int(sizeof(map)))
367 }
368 return r
369}
370
371// clear clears the map without deallocating the allocated data.
372// It does it by setting the map length to `0`
373// Example: mut m := {'abc': 'xyz', 'def': 'aaa'}; m.clear(); assert m.len == 0
374pub fn (mut m map) clear() {
375 unsafe {
376 if m.key_values.all_deleted != 0 {
377 free(m.key_values.all_deleted)
378 m.key_values.all_deleted = nil
379 }
380 vmemset(m.key_values.keys, 0, m.key_values.key_bytes * m.key_values.cap)
381 vmemset(m.metas, 0, sizeof(u32) * (m.even_index + 2 + m.extra_metas))
382 }
383 m.key_values.len = 0
384 m.key_values.deletes = 0
385 m.even_index = init_even_index
386 m.cached_hashbits = max_cached_hashbits
387 m.shift = init_log_capicity
388 m.len = 0
389}
390
391@[inline]
392fn (m &map) key_to_index(pkey voidptr) (u32, u32) {
393 if voidptr(m.hash_fn) == unsafe { nil } {
394 unsafe {
395 p := &u64(m)
396 prev2 := (&u64(usize(m) - usize(16)))[0]
397 prev1 := (&u64(usize(m) - usize(8)))[0]
398 panic('map.hash_fn is nil map_ptr=${usize(m)} key_bytes=${m.key_bytes} value_bytes=${m.value_bytes} even_index=${m.even_index} shift=${m.shift} metas=${usize(m.metas)} prev2=${prev2} prev1=${prev1} w0=${p[0]} w1=${p[1]} w2=${p[2]} w3=${p[3]} w4=${p[4]} w5=${p[5]} w6=${p[6]} w7=${p[7]} hash_fn=${usize(voidptr(m.hash_fn))}')
399 }
400 }
401 hash := m.hash_fn(pkey)
402 index := hash & m.even_index
403 meta := ((hash >> m.shift) & hash_mask) | probe_inc
404 return u32(index), u32(meta)
405}
406
407@[inline]
408fn (m &map) meta_less(_index u32, _metas u32) (u32, u32) {
409 mut index := _index
410 mut meta := _metas
411 for meta < unsafe { m.metas[index] } {
412 index += 2
413 meta += probe_inc
414 }
415 return index, meta
416}
417
418@[inline]
419fn (mut m map) meta_greater(_index u32, _metas u32, kvi u32) {
420 mut meta := _metas
421 mut index := _index
422 mut kv_index := kvi
423 for unsafe { m.metas[index] } != 0 {
424 if meta > unsafe { m.metas[index] } {
425 unsafe {
426 tmp_meta := m.metas[index]
427 m.metas[index] = meta
428 meta = tmp_meta
429 tmp_index := m.metas[index + 1]
430 m.metas[index + 1] = kv_index
431 kv_index = tmp_index
432 }
433 }
434 index += 2
435 meta += probe_inc
436 // Grow metas if probing is approaching the buffer boundary
437 if index + 2 >= m.even_index + 2 + m.extra_metas {
438 m.ensure_extra_metas_grow()
439 }
440 }
441 unsafe {
442 m.metas[index] = meta
443 m.metas[index + 1] = kv_index
444 }
445 probe_count := (meta >> hashbits) - 1
446 m.ensure_extra_metas(probe_count)
447}
448
449fn (mut m map) ensure_extra_metas_grow() {
450 size_of_u32 := sizeof(u32)
451 old_mem_size := (m.even_index + 2 + m.extra_metas)
452 m.extra_metas += extra_metas_inc
453 mem_size := (m.even_index + 2 + m.extra_metas)
454 unsafe {
455 x := realloc_data(byteptr(m.metas), int(size_of_u32 * old_mem_size),
456 int(size_of_u32 * mem_size))
457 m.metas = &u32(x)
458 vmemset(byteptr(m.metas) + (mem_size - extra_metas_inc) * size_of_u32, 0,
459 int(sizeof(u32) * extra_metas_inc))
460 }
461}
462
463@[inline]
464fn (mut m map) ensure_extra_metas(probe_count u32) {
465 if (probe_count << 1) == m.extra_metas {
466 size_of_u32 := sizeof(u32)
467 old_mem_size := (m.even_index + 2 + m.extra_metas)
468 m.extra_metas += extra_metas_inc
469 mem_size := (m.even_index + 2 + m.extra_metas)
470 unsafe {
471 x := realloc_data(byteptr(m.metas), int(size_of_u32 * old_mem_size),
472 int(size_of_u32 * mem_size))
473 m.metas = &u32(x)
474 vmemset(byteptr(m.metas) + (mem_size - extra_metas_inc) * size_of_u32, 0,
475 int(sizeof(u32) * extra_metas_inc))
476 }
477 // Should almost never happen
478 if probe_count == 252 {
479 panic('Probe overflow')
480 }
481 }
482}
483
484// Insert new element to the map. The element is inserted if its key is
485// not equivalent to the key of any other element already in the container.
486// If the key already exists, its value is changed to the value of the new element.
487fn (mut m map) set(key voidptr, value voidptr) {
488 // Integer-based load factor check: equivalent to (2*len)/even_index > 0.8
489 // which simplifies to 5*len > 2*even_index (avoids float ops broken in ARM64 backend)
490 if u32(5) * u32(m.len) > u32(2) * m.even_index {
491 m.expand()
492 }
493 mut index, mut meta := m.key_to_index(key)
494 index, meta = m.meta_less(index, meta)
495 // While we might have a match
496 for meta == unsafe { m.metas[index] } {
497 kv_index := int(unsafe { m.metas[index + 1] })
498 pkey := unsafe { m.key_values.key(kv_index) }
499 if m.key_eq_fn(key, pkey) {
500 unsafe {
501 pval := m.key_values.value(kv_index)
502 vmemcpy(pval, value, m.value_bytes)
503 }
504 return
505 }
506 index += 2
507 meta += probe_inc
508 }
509 kv_index := m.key_values.expand()
510 unsafe {
511 pkey := m.key_values.key(kv_index)
512 pvalue := m.key_values.value(kv_index)
513 m.clone_fn(pkey, key)
514 vmemcpy(pvalue, value, m.value_bytes)
515 }
516 m.meta_greater(index, meta, u32(kv_index))
517 m.len++
518}
519
520// Doubles the size of the hashmap
521fn (mut m map) expand() {
522 old_cap := m.even_index
523 m.even_index = ((m.even_index + 2) << 1) - 2
524 // Check if any hashbits are left
525 if m.cached_hashbits == 0 {
526 m.shift += max_cached_hashbits
527 m.cached_hashbits = max_cached_hashbits
528 m.rehash()
529 } else {
530 m.cached_rehash(old_cap)
531 m.cached_hashbits--
532 }
533}
534
535// rehash reconstructs the hash table.
536// All the elements in the container are rearranged according
537// to their hash value into the newly sized key-value container.
538// Rehashes are performed when the load_factor is going to surpass
539// the max_load_factor in an operation.
540fn (mut m map) rehash() {
541 meta_bytes := sizeof(u32) * (m.even_index + 2 + m.extra_metas)
542 m.reserve_metas(meta_bytes)
543}
544
545fn (mut m map) reserve_metas(meta_bytes u32) {
546 unsafe {
547 // TODO: use realloc_data here too
548 x := v_realloc(byteptr(m.metas), int(meta_bytes))
549 m.metas = &u32(x)
550 vmemset(m.metas, 0, int(meta_bytes))
551 }
552 for i := 0; i < m.key_values.len; i++ {
553 if !m.key_values.has_index(i) {
554 continue
555 }
556 pkey := unsafe { m.key_values.key(i) }
557 mut index, mut meta := m.key_to_index(pkey)
558 index, meta = m.meta_less(index, meta)
559 m.meta_greater(index, meta, u32(i))
560 }
561}
562
563// reserve ensures that the map can store at least `n` entries without rehashing.
564pub fn (mut m map) reserve(n u32) {
565 for u64(n) * 5 > u64(m.even_index) * 2 {
566 m.expand()
567 }
568}
569
570// cached_rehashd works like rehash. However, instead of rehashing the
571// key completely, it uses the bits cached in `metas`.
572fn (mut m map) cached_rehash(old_cap u32) {
573 old_metas := m.metas
574 metasize := int(sizeof(u32) * (m.even_index + 2 + m.extra_metas))
575 m.metas = unsafe { &u32(vcalloc(metasize)) }
576 old_extra_metas := m.extra_metas
577 for i := u32(0); i <= old_cap + old_extra_metas; i += 2 {
578 if unsafe { old_metas[i] } == 0 {
579 continue
580 }
581 old_meta := unsafe { old_metas[i] }
582 old_probe_count := ((old_meta >> hashbits) - 1) << 1
583 old_index := (i - old_probe_count) & (m.even_index >> 1)
584 mut index := (old_index | (old_meta << m.shift)) & m.even_index
585 mut meta := (old_meta & hash_mask) | probe_inc
586 kv_index := unsafe { old_metas[i + 1] }
587 index, meta = m.meta_less(index, meta)
588 m.meta_greater(index, meta, kv_index)
589 }
590 unsafe { free(old_metas) }
591}
592
593// get_and_set is used for assignment operators. If the argument-key
594// does not exist in the map, it's added to the map along with the zero/default value.
595// If the key exists, its respective value is returned.
596fn (mut m map) get_and_set(key voidptr, zero voidptr) voidptr {
597 for {
598 mut index, mut meta := m.key_to_index(key)
599 for {
600 if meta == unsafe { m.metas[index] } {
601 kv_index := int(unsafe { m.metas[index + 1] })
602 pkey := unsafe { m.key_values.key(kv_index) }
603 if m.key_eq_fn(key, pkey) {
604 pval := unsafe { m.key_values.value(kv_index) }
605 return unsafe { &u8(pval) }
606 }
607 }
608 index += 2
609 meta += probe_inc
610 if meta > unsafe { m.metas[index] } {
611 break
612 }
613 }
614 // Key not found, insert key with zero-value
615 m.set(key, zero)
616 }
617 return unsafe { nil }
618}
619
620// If `key` matches the key of an element in the container,
621// the method returns a reference to its mapped value.
622// If not, a zero/default value is returned.
623fn (m &map) get(key voidptr, zero voidptr) voidptr {
624 if m.len == 0 {
625 return zero
626 }
627 mut index, mut meta := m.key_to_index(key)
628 for {
629 if meta == unsafe { m.metas[index] } {
630 kv_index := int(unsafe { m.metas[index + 1] })
631 pkey := unsafe { m.key_values.key(kv_index) }
632 if m.key_eq_fn(key, pkey) {
633 pval := unsafe { m.key_values.value(kv_index) }
634 return unsafe { &u8(pval) }
635 }
636 }
637 index += 2
638 meta += probe_inc
639 if meta > unsafe { m.metas[index] } {
640 break
641 }
642 }
643 return zero
644}
645
646// If `key` matches the key of an element in the container,
647// the method returns a reference to its mapped value.
648// If not, a zero pointer is returned.
649// This is used in `x := m['key'] or { ... }`
650fn (m &map) get_check(key voidptr) voidptr {
651 if m.len == 0 {
652 return 0
653 }
654 mut index, mut meta := m.key_to_index(key)
655 for {
656 if meta == unsafe { m.metas[index] } {
657 kv_index := int(unsafe { m.metas[index + 1] })
658 pkey := unsafe { m.key_values.key(kv_index) }
659 if m.key_eq_fn(key, pkey) {
660 pval := unsafe { m.key_values.value(kv_index) }
661 return unsafe { &u8(pval) }
662 }
663 }
664 index += 2
665 meta += probe_inc
666 if meta > unsafe { m.metas[index] } {
667 break
668 }
669 }
670 return 0
671}
672
673// Checks whether a particular key exists in the map.
674fn (m &map) exists(key voidptr) bool {
675 if m.len == 0 {
676 return false
677 }
678 mut index, mut meta := m.key_to_index(key)
679 for {
680 if meta == unsafe { m.metas[index] } {
681 kv_index := int(unsafe { m.metas[index + 1] })
682 pkey := unsafe { m.key_values.key(kv_index) }
683 if m.key_eq_fn(key, pkey) {
684 return true
685 }
686 }
687 index += 2
688 meta += probe_inc
689 if meta > unsafe { m.metas[index] } {
690 break
691 }
692 }
693 return false
694}
695
696@[inline]
697fn (mut d DenseArray) delete(i int) {
698 if i == d.len - 1 {
699 d.len--
700 d.trim_deleted_tail()
701 return
702 }
703 if d.deletes == 0 {
704 d.all_deleted = vcalloc(d.cap) // sets to 0
705 }
706 d.deletes++
707 unsafe {
708 d.all_deleted[i] = 1
709 }
710}
711
712// delete removes the mapping of a particular key from the map.
713@[unsafe]
714pub fn (mut m map) delete(key voidptr) {
715 mut index, mut meta := m.key_to_index(key)
716 index, meta = m.meta_less(index, meta)
717 // Perform backwards shifting
718 for meta == unsafe { m.metas[index] } {
719 kv_index := int(unsafe { m.metas[index + 1] })
720 pkey := unsafe { m.key_values.key(kv_index) }
721 if m.key_eq_fn(key, pkey) {
722 for (unsafe { m.metas[index + 2] } >> hashbits) > 1 {
723 unsafe {
724 m.metas[index] = m.metas[index + 2] - probe_inc
725 m.metas[index + 1] = m.metas[index + 3]
726 }
727 index += 2
728 }
729 m.len--
730 m.key_values.delete(kv_index)
731 unsafe {
732 m.metas[index] = 0
733 m.free_fn(pkey)
734 // Mark key as deleted
735 vmemset(pkey, 0, m.key_bytes)
736 }
737 if m.key_values.len <= 32 {
738 return
739 }
740 // Clean up key_values if too many have been deleted
741 if m.key_values.deletes >= (m.key_values.len >> 1) {
742 m.key_values.zeros_to_end()
743 m.rehash()
744 }
745 return
746 }
747 index += 2
748 meta += probe_inc
749 }
750}
751
752// keys returns all keys in the map.
753pub fn (m &map) keys() array {
754 mut keys := __new_array(m.len, 0, m.key_bytes)
755 mut item := unsafe { &u8(keys.data) }
756 if m.key_values.deletes == 0 {
757 for i := 0; i < m.key_values.len; i++ {
758 unsafe {
759 pkey := m.key_values.key(i)
760 m.clone_fn(item, pkey)
761 item = item + m.key_bytes
762 }
763 }
764 return keys
765 }
766 for i := 0; i < m.key_values.len; i++ {
767 if !m.key_values.has_index(i) {
768 continue
769 }
770 unsafe {
771 pkey := m.key_values.key(i)
772 m.clone_fn(item, pkey)
773 item = item + m.key_bytes
774 }
775 }
776 return keys
777}
778
779// values returns all values in the map.
780pub fn (m &map) values() array {
781 mut values := __new_array(m.len, 0, m.value_bytes)
782 mut item := unsafe { &u8(values.data) }
783
784 if m.key_values.deletes == 0 {
785 unsafe {
786 vmemcpy(item, m.key_values.values, m.value_bytes * m.key_values.len)
787 }
788 return values
789 }
790
791 for i := 0; i < m.key_values.len; i++ {
792 if !m.key_values.has_index(i) {
793 continue
794 }
795 unsafe {
796 pvalue := m.key_values.value(i)
797 vmemcpy(item, pvalue, m.value_bytes)
798 item = item + m.value_bytes
799 }
800 }
801 return values
802}
803
804// warning: only copies keys, does not clone
805@[unsafe]
806fn (d &DenseArray) clone() DenseArray {
807 res := DenseArray{
808 key_bytes: d.key_bytes
809 value_bytes: d.value_bytes
810 cap: d.cap
811 len: d.len
812 deletes: d.deletes
813 all_deleted: unsafe { nil }
814 values: unsafe { nil }
815 keys: unsafe { nil }
816 }
817 unsafe {
818 if d.deletes != 0 {
819 res.all_deleted = memdup(d.all_deleted, d.cap)
820 }
821 res.keys = memdup(d.keys, d.cap * d.key_bytes)
822 res.values = memdup(d.values, d.cap * d.value_bytes)
823 }
824 return res
825}
826
827// clone returns a clone of the `map`.
828@[unsafe]
829pub fn (m &map) clone() map {
830 metasize := int(sizeof(u32) * (m.even_index + 2 + m.extra_metas))
831 res := map{
832 key_bytes: m.key_bytes
833 value_bytes: m.value_bytes
834 even_index: m.even_index
835 cached_hashbits: m.cached_hashbits
836 shift: m.shift
837 key_values: unsafe { m.key_values.clone() }
838 metas: unsafe { &u32(malloc_noscan(metasize)) }
839 extra_metas: m.extra_metas
840 len: m.len
841 has_string_keys: m.has_string_keys
842 hash_fn: m.hash_fn
843 key_eq_fn: m.key_eq_fn
844 clone_fn: m.clone_fn
845 free_fn: m.free_fn
846 }
847 unsafe { vmemcpy(res.metas, m.metas, metasize) }
848 if !m.has_string_keys {
849 return res
850 }
851 // clone keys
852 for i in 0 .. m.key_values.len {
853 if !m.key_values.has_index(i) {
854 continue
855 }
856 m.clone_fn(res.key_values.key(i), m.key_values.key(i))
857 }
858 return res
859}
860
861// free releases all memory resources occupied by the `map`.
862@[unsafe]
863pub fn (m &map) free() {
864 unsafe { free(m.metas) }
865 unsafe {
866 m.metas = nil
867 }
868 if m.key_values.deletes == 0 {
869 for i := 0; i < m.key_values.len; i++ {
870 unsafe {
871 pkey := m.key_values.key(i)
872 m.free_fn(pkey)
873 vmemset(pkey, 0, m.key_bytes)
874 }
875 }
876 } else {
877 for i := 0; i < m.key_values.len; i++ {
878 if !m.key_values.has_index(i) {
879 continue
880 }
881 unsafe {
882 pkey := m.key_values.key(i)
883 m.free_fn(pkey)
884 vmemset(pkey, 0, m.key_bytes)
885 }
886 }
887 }
888 unsafe {
889 if m.key_values.all_deleted != nil {
890 free(m.key_values.all_deleted)
891 m.key_values.all_deleted = nil
892 }
893 if m.key_values.keys != nil {
894 free(m.key_values.keys)
895 m.key_values.keys = nil
896 }
897 if m.key_values.values != nil {
898 free(m.key_values.values)
899 m.key_values.values = nil
900 }
901 // TODO: the next lines assume that callback functions are static and independent from each particular
902 // map instance. Closures may invalidate that assumption, so revisit when RC for closures works.
903 m.hash_fn = nil
904 m.key_eq_fn = nil
905 m.clone_fn = nil
906 m.free_fn = nil
907 m.key_values.cap = 0
908 m.key_values.len = 0
909 m.key_values.deletes = 0
910 m.even_index = 0
911 m.cached_hashbits = 0
912 m.shift = 0
913 m.extra_metas = 0
914 m.has_string_keys = false
915 m.len = 0
916 }
917}
918