vlib/arrays: fix `copy` to not use memcpy for array, map, string (#13703)
parent
de2fc87995
commit
4bea35b028
|
@ -546,9 +546,27 @@ fn swap_nonoverlapping<T>(x_ &T, y_ &T, count int) {
|
||||||
// Returns the number of elements copied.
|
// Returns the number of elements copied.
|
||||||
pub fn copy<T>(mut dst []T, src []T) int {
|
pub fn copy<T>(mut dst []T, src []T) int {
|
||||||
min := if dst.len < src.len { dst.len } else { src.len }
|
min := if dst.len < src.len { dst.len } else { src.len }
|
||||||
if min > 0 {
|
if min <= 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
if can_copy_bits<T>() {
|
||||||
blen := min * int(sizeof(T))
|
blen := min * int(sizeof(T))
|
||||||
unsafe { vmemmove(&T(dst.data), src.data, blen) }
|
unsafe { vmemmove(&T(dst.data), src.data, blen) }
|
||||||
|
} else {
|
||||||
|
for i in 0 .. min {
|
||||||
|
dst[i] = src[i]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return min
|
return min
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// determines if T can be copied using `memcpy`
|
||||||
|
// false if autofree needs to intervene
|
||||||
|
// false if type is not copyable e.g. map
|
||||||
|
fn can_copy_bits<T>() bool {
|
||||||
|
// references, C pointers, integers, floats, runes
|
||||||
|
if T.name[0] in [`&`, `b`, `c`, `f`, `i`, `r`, `u`, `v`] {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
|
@ -281,3 +281,15 @@ fn test_copy() {
|
||||||
assert copy(mut b, [8, 9]) == 2
|
assert copy(mut b, [8, 9]) == 2
|
||||||
assert b == [8, 9, 3, 7]
|
assert b == [8, 9, 3, 7]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn test_can_copy_bits() {
|
||||||
|
assert can_copy_bits<byte>()
|
||||||
|
assert can_copy_bits<int>()
|
||||||
|
assert can_copy_bits<voidptr>()
|
||||||
|
assert can_copy_bits<&byte>()
|
||||||
|
// autofree needs to intercept assign
|
||||||
|
assert !can_copy_bits<string>()
|
||||||
|
assert !can_copy_bits<[]int>()
|
||||||
|
// map not copyable
|
||||||
|
assert !can_copy_bits<map[string]int>()
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue