| 1 | module builtin |
| 2 | |
| 3 | fn C.wyhash(&u8, u64, u64, &u64) u64 |
| 4 | |
| 5 | fn C.wyhash64(u64, u64) u64 |
| 6 | |
| 7 | // fast_string_eq is intended to be fast when |
| 8 | // the strings are very likely to be equal |
| 9 | // TODO: add branch prediction hints |
| 10 | @[inline] |
| 11 | fn fast_string_eq(a string, b string) bool { |
| 12 | if a.len != b.len { |
| 13 | return false |
| 14 | } |
| 15 | unsafe { |
| 16 | return C.memcmp(a.str, b.str, b.len) == 0 |
| 17 | } |
| 18 | } |
| 19 | |
| 20 | fn map_hash_string(pkey voidptr) u64 { |
| 21 | key := *unsafe { &string(pkey) } |
| 22 | // XTODO remove voidptr cast once virtual C.consts can be declared |
| 23 | return C.wyhash(key.str, u64(key.len), 0, &u64(voidptr(C._wyp))) |
| 24 | } |
| 25 | |
| 26 | fn map_hash_int_1(pkey voidptr) u64 { |
| 27 | return C.wyhash64(*unsafe { &u8(pkey) }, 0) |
| 28 | } |
| 29 | |
| 30 | fn map_hash_int_2(pkey voidptr) u64 { |
| 31 | return C.wyhash64(*unsafe { &u16(pkey) }, 0) |
| 32 | } |
| 33 | |
| 34 | fn map_hash_int_4(pkey voidptr) u64 { |
| 35 | return C.wyhash64(*unsafe { &u32(pkey) }, 0) |
| 36 | } |
| 37 | |
| 38 | fn map_hash_int_8(pkey voidptr) u64 { |
| 39 | return C.wyhash64(*unsafe { &u64(pkey) }, 0) |
| 40 | } |
| 41 | |
| 42 | fn map_enum_fn(kind int, esize int) voidptr { |
| 43 | if kind !in [1, 2, 3] { |
| 44 | panic('map_enum_fn: invalid kind') |
| 45 | } |
| 46 | if esize > 8 || esize < 0 { |
| 47 | panic('map_enum_fn: invalid esize') |
| 48 | } |
| 49 | if kind == 1 { |
| 50 | if esize > 4 { |
| 51 | return voidptr(map_hash_int_8) |
| 52 | } |
| 53 | if esize > 2 { |
| 54 | return voidptr(map_hash_int_4) |
| 55 | } |
| 56 | if esize > 1 { |
| 57 | return voidptr(map_hash_int_2) |
| 58 | } |
| 59 | if esize > 0 { |
| 60 | return voidptr(map_hash_int_1) |
| 61 | } |
| 62 | } |
| 63 | if kind == 2 { |
| 64 | if esize > 4 { |
| 65 | return voidptr(map_eq_int_8) |
| 66 | } |
| 67 | if esize > 2 { |
| 68 | return voidptr(map_eq_int_4) |
| 69 | } |
| 70 | if esize > 1 { |
| 71 | return voidptr(map_eq_int_2) |
| 72 | } |
| 73 | if esize > 0 { |
| 74 | return voidptr(map_eq_int_1) |
| 75 | } |
| 76 | } |
| 77 | if kind == 3 { |
| 78 | if esize > 4 { |
| 79 | return voidptr(map_clone_int_8) |
| 80 | } |
| 81 | if esize > 2 { |
| 82 | return voidptr(map_clone_int_4) |
| 83 | } |
| 84 | if esize > 1 { |
| 85 | return voidptr(map_clone_int_2) |
| 86 | } |
| 87 | if esize > 0 { |
| 88 | return voidptr(map_clone_int_1) |
| 89 | } |
| 90 | } |
| 91 | return unsafe { nil } |
| 92 | } |
| 93 | |
| 94 | // Move all zeros to the end of the array and resize array |
| 95 | fn (mut d DenseArray) zeros_to_end() { |
| 96 | // TODO: alloca? |
| 97 | mut tmp_value := unsafe { malloc(d.value_bytes) } |
| 98 | mut tmp_key := unsafe { malloc(d.key_bytes) } |
| 99 | mut count := 0 |
| 100 | for i in 0 .. d.len { |
| 101 | if d.has_index(i) { |
| 102 | // swap (TODO: optimize) |
| 103 | unsafe { |
| 104 | if count != i { |
| 105 | // Swap keys |
| 106 | C.memcpy(tmp_key, d.key(count), d.key_bytes) |
| 107 | C.memcpy(d.key(count), d.key(i), d.key_bytes) |
| 108 | C.memcpy(d.key(i), tmp_key, d.key_bytes) |
| 109 | // Swap values |
| 110 | C.memcpy(tmp_value, d.value(count), d.value_bytes) |
| 111 | C.memcpy(d.value(count), d.value(i), d.value_bytes) |
| 112 | C.memcpy(d.value(i), tmp_value, d.value_bytes) |
| 113 | } |
| 114 | } |
| 115 | count++ |
| 116 | } |
| 117 | } |
| 118 | unsafe { |
| 119 | free(tmp_value) |
| 120 | free(tmp_key) |
| 121 | d.deletes = 0 |
| 122 | // TODO: reallocate instead as more deletes are likely |
| 123 | free(d.all_deleted) |
| 124 | d.all_deleted = nil |
| 125 | } |
| 126 | d.len = count |
| 127 | old_cap := d.cap |
| 128 | if count < 8 { |
| 129 | d.cap = 8 |
| 130 | } else { |
| 131 | d.cap = count |
| 132 | } |
| 133 | unsafe { |
| 134 | d.values = realloc_data(d.values, d.value_bytes * old_cap, d.value_bytes * d.cap) |
| 135 | d.keys = realloc_data(d.keys, d.key_bytes * old_cap, d.key_bytes * d.cap) |
| 136 | } |
| 137 | } |
| 138 | |