map: fix misalignment (#9548)

pull/9555/head
ka-weihe 2021-04-01 10:39:00 +02:00 committed by GitHub
parent 8d5e310189
commit 1a76cb1c36
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 50 additions and 51 deletions

View File

@ -94,9 +94,7 @@ fn fast_string_eq(a string, b string) bool {
// DenseArray represents a dynamic array with very low growth factor
struct DenseArray {
key_bytes int
key_bytes_ int
value_bytes int
slot_bytes int // sum of 2 fields above
mut:
cap int
len int
@ -104,42 +102,34 @@ mut:
// array allocated (with `cap` bytes) on first deletion
// has non-zero element when key deleted
all_deleted &byte
data byteptr // array of interleaved key data and value data
values byteptr
keys byteptr
}
[inline]
fn new_dense_array(key_bytes int, value_bytes int) DenseArray {
mut key_bytes_ := key_bytes
mut value_bytes_ := value_bytes
$if gcboehm ? {
align, mask := $if x64 { 7, int(0xfffffff8) } $else { 3, int(0xfffffffc) }
key_bytes_ = (key_bytes + align) & mask
value_bytes_ = (value_bytes + align) & mask
}
slot_bytes := key_bytes_ + value_bytes_
cap := 8
return DenseArray{
key_bytes: key_bytes
key_bytes_: key_bytes_
value_bytes: value_bytes
slot_bytes: slot_bytes
cap: cap
len: 0
deletes: 0
all_deleted: 0
data: unsafe { malloc(cap * slot_bytes) }
keys: unsafe { malloc(cap * key_bytes) }
values: unsafe { malloc(cap * value_bytes) }
}
}
[inline]
fn (d &DenseArray) key(i int) voidptr {
return unsafe { d.data + i * d.slot_bytes }
return unsafe { d.keys + i * d.key_bytes }
}
// for cgen
[inline]
fn (d &DenseArray) value(i int) voidptr {
return unsafe { d.data + i * d.slot_bytes + d.key_bytes_ }
return unsafe { d.values + i * d.value_bytes }
}
[inline]
@ -152,11 +142,13 @@ fn (d &DenseArray) has_index(i int) bool {
[inline]
fn (mut d DenseArray) expand() int {
old_cap := d.cap
old_size := d.slot_bytes * old_cap
old_value_size := d.value_bytes * old_cap
old_key_size := d.key_bytes * old_cap
if d.cap == d.len {
d.cap += d.cap >> 3
unsafe {
d.data = realloc_data(d.data, old_size, d.slot_bytes * d.cap)
d.keys = realloc_data(d.keys, old_key_size, d.key_bytes * d.cap)
d.values = realloc_data(d.values, old_value_size, d.value_bytes * d.cap)
if d.deletes != 0 {
d.all_deleted = realloc_data(d.all_deleted, old_cap, d.cap)
C.memset(d.all_deleted + d.len, 0, d.cap - d.len)
@ -176,21 +168,28 @@ fn (mut d DenseArray) expand() int {
// Move all zeros to the end of the array and resize array
fn (mut d DenseArray) zeros_to_end() {
// TODO alloca?
mut tmp_buf := unsafe { malloc(d.slot_bytes) }
mut tmp_value := unsafe { malloc(d.value_bytes) }
mut tmp_key := unsafe { malloc(d.key_bytes) }
mut count := 0
for i in 0 .. d.len {
if d.has_index(i) {
// swap (TODO: optimize)
unsafe {
C.memcpy(tmp_buf, d.key(count), d.slot_bytes)
C.memcpy(d.key(count), d.key(i), d.slot_bytes)
C.memcpy(d.key(i), tmp_buf, d.slot_bytes)
// Swap keys
C.memcpy(tmp_key, d.key(count), d.key_bytes)
C.memcpy(d.key(count), d.key(i), d.key_bytes)
C.memcpy(d.key(i), tmp_key, d.key_bytes)
// Swap values
C.memcpy(tmp_value, d.value(count), d.value_bytes)
C.memcpy(d.value(count), d.value(i), d.value_bytes)
C.memcpy(d.value(i), tmp_value, d.value_bytes)
}
count++
}
}
unsafe {
free(tmp_buf)
free(tmp_value)
free(tmp_key)
d.deletes = 0
// TODO: reallocate instead as more deletes are likely
free(d.all_deleted)
@ -199,7 +198,8 @@ fn (mut d DenseArray) zeros_to_end() {
old_cap := d.cap
d.cap = if count < 8 { 8 } else { count }
unsafe {
d.data = realloc_data(d.data, d.slot_bytes * old_cap, d.slot_bytes * d.cap)
d.values = realloc_data(d.values, d.value_bytes * old_cap, d.value_bytes * d.cap)
d.keys = realloc_data(d.keys, d.key_bytes * old_cap, d.key_bytes * d.cap)
}
}
@ -214,8 +214,7 @@ type MapFreeFn = fn (voidptr)
// map is the internal representation of a V `map` type.
pub struct map {
// Number of bytes of a key
key_bytes int
key_bytes_ int
key_bytes int
// Number of bytes of a value
value_bytes int
mut:
@ -270,19 +269,19 @@ fn map_eq_string(a voidptr, b voidptr) bool {
}
fn map_eq_int_1(a voidptr, b voidptr) bool {
return unsafe { C.memcmp(a, b, 1) == 0 }
return unsafe { *&byte(a) == *&byte(b) }
}
fn map_eq_int_2(a voidptr, b voidptr) bool {
return unsafe { C.memcmp(a, b, 2) == 0 }
return unsafe { *&u16(a) == *&u16(b) }
}
fn map_eq_int_4(a voidptr, b voidptr) bool {
return unsafe { C.memcmp(a, b, 4) == 0 }
return unsafe { *&u32(a) == *&u32(b) }
}
fn map_eq_int_8(a voidptr, b voidptr) bool {
return unsafe { C.memcmp(a, b, 8) == 0 }
return unsafe { *&u64(a) == *&u64(b) }
}
fn map_clone_string(dest voidptr, pkey voidptr) {
@ -294,25 +293,25 @@ fn map_clone_string(dest voidptr, pkey voidptr) {
fn map_clone_int_1(dest voidptr, pkey voidptr) {
unsafe {
C.memcpy(dest, pkey, 1)
*&byte(dest) = *&byte(pkey)
}
}
fn map_clone_int_2(dest voidptr, pkey voidptr) {
unsafe {
C.memcpy(dest, pkey, 2)
*&u16(dest) = *&u16(pkey)
}
}
fn map_clone_int_4(dest voidptr, pkey voidptr) {
unsafe {
C.memcpy(dest, pkey, 4)
*&u32(dest) = *&u32(pkey)
}
}
fn map_clone_int_8(dest voidptr, pkey voidptr) {
unsafe {
C.memcpy(dest, pkey, 8)
*&u64(dest) = *&u64(pkey)
}
}
@ -329,14 +328,8 @@ fn new_map_2(key_bytes int, value_bytes int, hash_fn MapHashFn, key_eq_fn MapEqF
metasize := int(sizeof(u32) * (init_capicity + extra_metas_inc))
// for now assume anything bigger than a pointer is a string
has_string_keys := key_bytes > sizeof(voidptr)
mut key_bytes_ := key_bytes
$if gcboehm ? {
align, mask := $if x64 { 7, int(0xfffffff8) } $else { 3, int(0xfffffffc) }
key_bytes_ = (key_bytes + align) & mask
}
return map{
key_bytes: key_bytes
key_bytes_: key_bytes_
value_bytes: value_bytes
even_index: init_even_index
cached_hashbits: max_cached_hashbits
@ -457,7 +450,7 @@ fn (mut m map) set_1(key voidptr, value voidptr) {
pkey := unsafe { m.key_values.key(kv_index) }
if m.key_eq_fn(key, pkey) {
unsafe {
pval := byteptr(pkey) + m.key_bytes_
pval := m.key_values.value(kv_index)
C.memcpy(pval, value, m.value_bytes)
}
return
@ -468,8 +461,9 @@ fn (mut m map) set_1(key voidptr, value voidptr) {
kv_index := m.key_values.expand()
unsafe {
pkey := m.key_values.key(kv_index)
pvalue := m.key_values.value(kv_index)
m.clone_fn(pkey, key)
C.memcpy(byteptr(pkey) + m.key_bytes_, value, m.value_bytes)
C.memcpy(byteptr(pvalue), value, m.value_bytes)
}
m.meta_greater(index, meta, u32(kv_index))
m.len++
@ -548,7 +542,8 @@ fn (mut m map) get_and_set_1(key voidptr, zero voidptr) voidptr {
kv_index := int(unsafe { m.metas[index + 1] })
pkey := unsafe { m.key_values.key(kv_index) }
if m.key_eq_fn(key, pkey) {
return unsafe { byteptr(pkey) + m.key_values.key_bytes_ }
pval := unsafe { m.key_values.value(kv_index) }
return unsafe { byteptr(pval) }
}
}
index += 2
@ -574,7 +569,8 @@ fn (m &map) get_1(key voidptr, zero voidptr) voidptr {
kv_index := int(unsafe { m.metas[index + 1] })
pkey := unsafe { m.key_values.key(kv_index) }
if m.key_eq_fn(key, pkey) {
return unsafe { byteptr(pkey) + m.key_values.key_bytes_ }
pval := unsafe { m.key_values.value(kv_index) }
return unsafe { byteptr(pval) }
}
}
index += 2
@ -597,7 +593,8 @@ fn (m &map) get_1_check(key voidptr) voidptr {
kv_index := int(unsafe { m.metas[index + 1] })
pkey := unsafe { m.key_values.key(kv_index) }
if m.key_eq_fn(key, pkey) {
return unsafe { byteptr(pkey) + m.key_values.key_bytes_ }
pval := unsafe { m.key_values.value(kv_index) }
return unsafe { byteptr(pval) }
}
}
index += 2
@ -737,20 +734,20 @@ fn (m &map) keys_1() array {
fn (d &DenseArray) clone() DenseArray {
res := DenseArray{
key_bytes: d.key_bytes
key_bytes_: d.key_bytes_
value_bytes: d.value_bytes
slot_bytes: d.slot_bytes
cap: d.cap
len: d.len
deletes: d.deletes
all_deleted: 0
data: 0
values: 0
keys: 0
}
unsafe {
if d.deletes != 0 {
res.all_deleted = memdup(d.all_deleted, d.cap)
}
res.data = memdup(d.data, d.cap * d.slot_bytes)
res.keys = memdup(d.keys, d.cap * d.key_bytes)
res.values = memdup(d.values, d.cap * d.value_bytes)
}
return res
}
@ -761,7 +758,6 @@ pub fn (m &map) clone() map {
metasize := int(sizeof(u32) * (m.even_index + 2 + m.extra_metas))
res := map{
key_bytes: m.key_bytes
key_bytes_: m.key_bytes_
value_bytes: m.value_bytes
even_index: m.even_index
cached_hashbits: m.cached_hashbits
@ -813,5 +809,8 @@ pub fn (m &map) free() {
}
unsafe { free(m.key_values.all_deleted) }
}
unsafe { free(m.key_values.data) }
unsafe {
free(m.key_values.keys)
free(m.key_values.values)
}
}