write_memory_with_notification (to_addr, buffer, len);
val = value_copy (toval);
- memcpy (value_contents_raw (val).data (),
- value_contents (fromval).data (),
- TYPE_LENGTH (type));
+ copy (value_contents (fromval), value_contents_raw (val));
deprecated_set_value_type (val, type);
return val;
actual_type = ada_check_typedef (value_type (actual));
val = allocate_value (actual_type);
- memcpy ((char *) value_contents_raw (val).data (),
- (char *) value_contents (actual).data (),
- TYPE_LENGTH (actual_type));
+ copy (value_contents (actual), value_contents_raw (val));
actual = ensure_lval (val);
}
result = value_addr (actual);
{
struct type *elt_type = TYPE_TARGET_TYPE (type);
LONGEST lo, hi;
- struct value *res;
LONGEST i;
/* Verify that both val and type are arrays of scalars, and
if (!get_array_bounds (type, &lo, &hi))
error (_("unable to determine array bounds"));
- res = allocate_value (type);
+ value *res = allocate_value (type);
+ gdb::array_view<gdb_byte> res_contents = value_contents_writeable (res);
/* Promote each array element. */
for (i = 0; i < hi - lo + 1; i++)
{
struct value *elt = value_cast (elt_type, value_subscript (val, lo + i));
+ int elt_len = TYPE_LENGTH (elt_type);
- memcpy ((value_contents_writeable (res).data ()
- + (i * TYPE_LENGTH (elt_type))),
- value_contents_all (elt).data (), TYPE_LENGTH (elt_type));
+ copy (value_contents_all (elt), res_contents.slice (elt_len * i, elt_len));
}
return res;
if (gdbarch_byte_order (arch) == BFD_ENDIAN_BIG)
subobj_offset += n - max;
- memcpy (value_contents_raw (retval).data (),
- value_contents_all (val).data () + subobj_offset, len);
+ copy (value_contents_all (val).slice (subobj_offset, len),
+ value_contents_raw (retval));
}
break;
}
}
+template <typename T>
+void
+run_copy_test ()
+{
+ /* Test non-overlapping copy. */
+ {
+ const std::vector<T> src_v = {1, 2, 3, 4};
+ std::vector<T> dest_v (4, -1);
+
+ SELF_CHECK (dest_v != src_v);
+ copy (gdb::array_view<const T> (src_v), gdb::array_view<T> (dest_v));
+ SELF_CHECK (dest_v == src_v);
+ }
+
+ /* Test overlapping copy, where the source is before the destination. */
+ {
+ std::vector<T> vec = {1, 2, 3, 4, 5, 6, 7, 8};
+ gdb::array_view<T> v = vec;
+
+ copy (v.slice (1, 4),
+ v.slice (2, 4));
+
+ std::vector<T> expected = {1, 2, 2, 3, 4, 5, 7, 8};
+ SELF_CHECK (vec == expected);
+ }
+
+ /* Test overlapping copy, where the source is after the destination. */
+ {
+ std::vector<T> vec = {1, 2, 3, 4, 5, 6, 7, 8};
+ gdb::array_view<T> v = vec;
+
+ copy (v.slice (2, 4),
+ v.slice (1, 4));
+
+ std::vector<T> expected = {1, 3, 4, 5, 6, 6, 7, 8};
+ SELF_CHECK (vec == expected);
+ }
+
+ /* Test overlapping copy, where the source is the same as the destination. */
+ {
+ std::vector<T> vec = {1, 2, 3, 4, 5, 6, 7, 8};
+ gdb::array_view<T> v = vec;
+
+ copy (v.slice (2, 4),
+ v.slice (2, 4));
+
+ std::vector<T> expected = {1, 2, 3, 4, 5, 6, 7, 8};
+ SELF_CHECK (vec == expected);
+ }
+}
+
+/* Class with a non-trivial copy assignment operator, used to test the
+ array_view copy function. */
+struct foo
+{
+ /* Can be implicitly constructed from an int, such that we can use the same
+ templated test function to test against array_view<int> and
+ array_view<foo>. */
+ foo (int n)
+ : n (n)
+ {}
+
+ /* Needed to avoid -Wdeprecated-copy-with-user-provided-copy error with
+ Clang. */
+ foo (const foo &other) = default;
+
+ void operator= (const foo &other)
+ {
+ this->n = other.n;
+ this->n_assign_op_called++;
+ }
+
+ bool operator==(const foo &other) const
+ {
+ return this->n == other.n;
+ }
+
+ int n;
+
+ /* Number of times the assignment operator has been called. */
+ static int n_assign_op_called;
+};
+
+int foo::n_assign_op_called = 0;
+
+/* Test the array_view copy free function. */
+
+static void
+run_copy_tests ()
+{
+ /* Test with a trivial type. */
+ run_copy_test<int> ();
+
+ /* Test with a non-trivial type. */
+ foo::n_assign_op_called = 0;
+ run_copy_test<foo> ();
+
+ /* Make sure that for the non-trivial type foo, the assignment operator was
+ called an amount of times that makes sense. */
+ SELF_CHECK (foo::n_assign_op_called == 12);
+}
+
} /* namespace array_view_tests */
} /* namespace selftests */
{
selftests::register_test ("array_view",
selftests::array_view_tests::run_tests);
+ selftests::register_test ("array_view-copy",
+ selftests::array_view_tests::run_copy_tests);
}
{
/* Widen the scalar to a vector. */
struct type *eltype, *scalar_type;
- struct value *val, *elval;
+ struct value *elval;
LONGEST low_bound, high_bound;
int i;
&& !value_equal (elval, scalar_value))
error (_("conversion of scalar to vector involves truncation"));
- val = allocate_value (vector_type);
+ value *val = allocate_value (vector_type);
+ gdb::array_view<gdb_byte> val_contents = value_contents_writeable (val);
+ int elt_len = TYPE_LENGTH (eltype);
+
for (i = 0; i < high_bound - low_bound + 1; i++)
/* Duplicate the contents of elval into the destination vector. */
- memcpy (value_contents_writeable (val).data () + (i * TYPE_LENGTH (eltype)),
- value_contents_all (elval).data (), TYPE_LENGTH (eltype));
+ copy (value_contents_all (elval),
+ val_contents.slice (i * elt_len, elt_len));
return val;
}
static struct value *
vector_binop (struct value *val1, struct value *val2, enum exp_opcode op)
{
- struct value *val, *tmp, *mark;
struct type *type1, *type2, *eltype1, *eltype2;
int t1_is_vec, t2_is_vec, elsize, i;
LONGEST low_bound1, high_bound1, low_bound2, high_bound2;
|| low_bound1 != low_bound2 || high_bound1 != high_bound2)
error (_("Cannot perform operation on vectors with different types"));
- val = allocate_value (type1);
- mark = value_mark ();
+ value *val = allocate_value (type1);
+ gdb::array_view<gdb_byte> val_contents = value_contents_writeable (val);
+ value *mark = value_mark ();
for (i = 0; i < high_bound1 - low_bound1 + 1; i++)
{
- tmp = value_binop (value_subscript (val1, i),
- value_subscript (val2, i), op);
- memcpy (value_contents_writeable (val).data () + i * elsize,
- value_contents_all (tmp).data (),
- elsize);
+ value *tmp = value_binop (value_subscript (val1, i),
+ value_subscript (val2, i), op);
+ copy (value_contents_all (tmp),
+ val_contents.slice (i * elsize, elsize));
}
value_free_to_mark (mark);
return value_binop (value_zero (type, not_lval), arg1, BINOP_SUB);
else if (type->code () == TYPE_CODE_ARRAY && type->is_vector ())
{
- struct value *tmp, *val = allocate_value (type);
+ struct value *val = allocate_value (type);
struct type *eltype = check_typedef (TYPE_TARGET_TYPE (type));
int i;
LONGEST low_bound, high_bound;
if (!get_array_bounds (type, &low_bound, &high_bound))
error (_("Could not determine the vector bounds"));
+ gdb::array_view<gdb_byte> val_contents = value_contents_writeable (val);
+ int elt_len = TYPE_LENGTH (eltype);
+
for (i = 0; i < high_bound - low_bound + 1; i++)
{
- tmp = value_neg (value_subscript (arg1, i));
- memcpy ((value_contents_writeable (val).data ()
- + i * TYPE_LENGTH (eltype)),
- value_contents_all (tmp).data (), TYPE_LENGTH (eltype));
+ value *tmp = value_neg (value_subscript (arg1, i));
+ copy (value_contents_all (tmp),
+ val_contents.slice (i * elt_len, elt_len));
}
return val;
}
val = value_from_longest (type, ~value_as_long (arg1));
else if (type->code () == TYPE_CODE_ARRAY && type->is_vector ())
{
- struct value *tmp;
struct type *eltype = check_typedef (TYPE_TARGET_TYPE (type));
int i;
LONGEST low_bound, high_bound;
error (_("Could not determine the vector bounds"));
val = allocate_value (type);
+ gdb::array_view<gdb_byte> val_contents = value_contents_writeable (val);
+ int elt_len = TYPE_LENGTH (eltype);
+
for (i = 0; i < high_bound - low_bound + 1; i++)
{
- tmp = value_complement (value_subscript (arg1, i));
- memcpy ((value_contents_writeable (val).data ()
- + i * TYPE_LENGTH (eltype)),
- value_contents_all (tmp).data (), TYPE_LENGTH (eltype));
+ value *tmp = value_complement (value_subscript (arg1, i));
+ copy (value_contents_all (tmp),
+ val_contents.slice (i * elt_len, elt_len));
}
}
else if (type->code () == TYPE_CODE_COMPLEX)
struct type *eltype = check_typedef (TYPE_TARGET_TYPE (type1));
int i;
LONGEST low_bound, high_bound;
- struct value *tmp;
if (!get_array_bounds (type1, &low_bound, &high_bound))
error (_("Could not determine the vector bounds"));
val = allocate_value (type);
+ gdb::array_view<gdb_byte> val_contents = value_contents_writeable (val);
+ int elt_len = TYPE_LENGTH (eltype);
+
for (i = 0; i < high_bound - low_bound + 1; i++)
{
- tmp = value_one (eltype);
- memcpy ((value_contents_writeable (val).data ()
- + i * TYPE_LENGTH (eltype)),
- value_contents_all (tmp).data (), TYPE_LENGTH (eltype));
+ value *tmp = value_one (eltype);
+ copy (value_contents_all (tmp),
+ val_contents.slice (i * elt_len, elt_len));
}
}
else
implies the returned value is not lazy, even if TOVAL was. */
val = value_copy (toval);
set_value_lazy (val, 0);
- memcpy (value_contents_raw (val).data (), value_contents (fromval).data (),
- TYPE_LENGTH (type));
+ copy (value_contents (fromval), value_contents_raw (val));
/* We copy over the enclosing type and pointed-to offset from FROMVAL
in the case of pointer types. For object types, the enclosing type
arg1 = value_cast (real_type, arg1);
arg2 = value_cast (real_type, arg2);
- memcpy (value_contents_raw (val).data (),
- value_contents (arg1).data (), TYPE_LENGTH (real_type));
- memcpy (value_contents_raw (val).data () + TYPE_LENGTH (real_type),
- value_contents (arg2).data (), TYPE_LENGTH (real_type));
+ int len = TYPE_LENGTH (real_type);
+
+ copy (value_contents (arg1),
+ value_contents_raw (val).slice (0, len));
+ copy (value_contents (arg2),
+ value_contents_raw (val).slice (len, len));
+
return val;
}
struct type *val_real_type = TYPE_TARGET_TYPE (value_type (val));
struct value *re_val = allocate_value (val_real_type);
struct value *im_val = allocate_value (val_real_type);
+ int len = TYPE_LENGTH (val_real_type);
- memcpy (value_contents_raw (re_val).data (),
- value_contents (val).data (), TYPE_LENGTH (val_real_type));
- memcpy (value_contents_raw (im_val).data (),
- value_contents (val).data () + TYPE_LENGTH (val_real_type),
- TYPE_LENGTH (val_real_type));
+ copy (value_contents (val).slice (0, len),
+ value_contents_raw (re_val));
+ copy (value_contents (val).slice (len, len),
+ value_contents_raw (im_val));
return value_literal_complex (re_val, im_val, type);
}
TARGET_CHAR_BIT * length));
/* Copy the data. */
- memcpy (value_contents_all_raw (dst).data () + dst_offset * unit_size,
- value_contents_all_raw (src).data () + src_offset * unit_size,
- length * unit_size);
+ gdb::array_view<gdb_byte> dst_contents
+ = value_contents_all_raw (dst).slice (dst_offset * unit_size,
+ length * unit_size);
+ gdb::array_view<const gdb_byte> src_contents
+ = value_contents_all_raw (src).slice (src_offset * unit_size,
+ length * unit_size);
+ copy (src_contents, dst_contents);
/* Copy the meta-data, adjusted. */
src_bit_offset = src_offset * unit_size * HOST_CHAR_BIT;
val->stack = arg->stack;
val->is_zero = arg->is_zero;
val->initialized = arg->initialized;
+
if (!value_lazy (val))
- {
- memcpy (value_contents_all_raw (val).data (),
- value_contents_all_raw (arg).data (),
- TYPE_LENGTH (value_enclosing_type (arg)));
+ copy (value_contents_all_raw (arg),
+ value_contents_all_raw (val));
- }
val->unavailable = arg->unavailable;
val->optimized_out = arg->optimized_out;
val->parent = arg->parent;
struct type *enc_type = value_enclosing_type (arg);
struct value *val = allocate_value (enc_type);
- memcpy (value_contents_all_raw (val).data (),
- value_contents_all (arg).data (),
- TYPE_LENGTH (enc_type));
+ copy (value_contents_all (arg), value_contents_all_raw (val));
val->type = arg->type;
set_value_embedded_offset (val, value_embedded_offset (arg));
set_value_pointed_to_offset (val, value_pointed_to_offset (arg));
#define COMMON_ARRAY_VIEW_H
#include "traits.h"
+#include <algorithm>
#include <type_traits>
/* An array_view is an abstraction that provides a non-owning view
size_type m_size;
};
+/* Copy the contents referenced by the array view SRC to the array view DEST.
+
+ The two array views must have the same length. */
+
+template <typename U, typename T>
+void copy (gdb::array_view<U> src, gdb::array_view<T> dest)
+{
+ gdb_assert (dest.size () == src.size ());
+ if (dest.data () < src.data ())
+ std::copy (src.begin (), src.end (), dest.begin ());
+ else if (dest.data () > src.data ())
+ std::copy_backward (src.begin (), src.end (), dest.end ());
+}
+
/* Compare LHS and RHS for (deep) equality. That is, whether LHS and
RHS have the same sizes, and whether each pair of elements of LHS
and RHS at the same position compares equal. */