From 4bea35b028b05bbd491a2d4b68d31b52c121d0ba Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Wed, 9 Mar 2022 22:30:51 +0000 Subject: [PATCH] vlib/arrays: fix `copy` to not use memcpy for array, map, string (#13703) --- vlib/arrays/arrays.v | 20 +++++++++++++++++++- vlib/arrays/arrays_test.v | 12 ++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/vlib/arrays/arrays.v b/vlib/arrays/arrays.v index 3a9eaeb778..1fffd5fd42 100644 --- a/vlib/arrays/arrays.v +++ b/vlib/arrays/arrays.v @@ -546,9 +546,27 @@ fn swap_nonoverlapping(x_ &T, y_ &T, count int) { // Returns the number of elements copied. pub fn copy(mut dst []T, src []T) int { min := if dst.len < src.len { dst.len } else { src.len } - if min > 0 { + if min <= 0 { + return 0 + } + if can_copy_bits() { blen := min * int(sizeof(T)) unsafe { vmemmove(&T(dst.data), src.data, blen) } + } else { + for i in 0 .. min { + dst[i] = src[i] + } } 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() bool { + // references, C pointers, integers, floats, runes + if T.name[0] in [`&`, `b`, `c`, `f`, `i`, `r`, `u`, `v`] { + return true + } + return false +} diff --git a/vlib/arrays/arrays_test.v b/vlib/arrays/arrays_test.v index 0245e8d4e6..1d88fcf4c4 100644 --- a/vlib/arrays/arrays_test.v +++ b/vlib/arrays/arrays_test.v @@ -281,3 +281,15 @@ fn test_copy() { assert copy(mut b, [8, 9]) == 2 assert b == [8, 9, 3, 7] } + +fn test_can_copy_bits() { + assert can_copy_bits() + assert can_copy_bits() + assert can_copy_bits() + assert can_copy_bits<&byte>() + // autofree needs to intercept assign + assert !can_copy_bits() + assert !can_copy_bits<[]int>() + // map not copyable + assert !can_copy_bits() +}