2021-01-01 16:03:39 +08:00
|
|
|
|
/* Copyright (C) 2017-2021 Free Software Foundation, Inc.
|
2017-09-05 00:10:12 +08:00
|
|
|
|
|
|
|
|
|
This file is part of GDB.
|
|
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
|
the Free Software Foundation; either version 3 of the License, or
|
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
|
|
|
|
|
|
|
|
|
#ifndef COMMON_ARRAY_VIEW_H
|
|
|
|
|
#define COMMON_ARRAY_VIEW_H
|
|
|
|
|
|
|
|
|
|
#include "traits.h"
|
|
|
|
|
#include <type_traits>
|
|
|
|
|
|
|
|
|
|
/* An array_view is an abstraction that provides a non-owning view
|
|
|
|
|
over a sequence of contiguous objects.
|
|
|
|
|
|
|
|
|
|
A way to put it is that array_view is to std::vector (and
|
|
|
|
|
std::array and built-in arrays with rank==1) like std::string_view
|
|
|
|
|
is to std::string.
|
|
|
|
|
|
|
|
|
|
The main intent of array_view is to use it as function input
|
|
|
|
|
parameter type, making it possible to pass in any sequence of
|
|
|
|
|
contiguous objects, irrespective of whether the objects live on the
|
|
|
|
|
stack or heap and what actual container owns them. Implicit
|
|
|
|
|
construction from the element type is supported too, making it easy
|
|
|
|
|
to call functions that expect an array of elements when you only
|
|
|
|
|
have one element (usually on the stack). For example:
|
|
|
|
|
|
|
|
|
|
struct A { .... };
|
|
|
|
|
void function (gdb::array_view<A> as);
|
|
|
|
|
|
|
|
|
|
std::vector<A> std_vec = ...;
|
|
|
|
|
std::array<A, N> std_array = ...;
|
|
|
|
|
A array[] = {...};
|
|
|
|
|
A elem;
|
|
|
|
|
|
|
|
|
|
function (std_vec);
|
|
|
|
|
function (std_array);
|
|
|
|
|
function (array);
|
|
|
|
|
function (elem);
|
|
|
|
|
|
|
|
|
|
Views can be either mutable or const. A const view is simply
|
|
|
|
|
created by specifying a const T as array_view template parameter,
|
|
|
|
|
in which case operator[] of non-const array_view objects ends up
|
|
|
|
|
returning const references. Making the array_view itself const is
|
|
|
|
|
analogous to making a pointer itself be const. I.e., disables
|
|
|
|
|
re-seating the view/pointer.
|
|
|
|
|
|
|
|
|
|
Since array_view objects are small (pointer plus size), and
|
|
|
|
|
designed to be trivially copyable, they should generally be passed
|
|
|
|
|
around by value.
|
|
|
|
|
|
|
|
|
|
You can find unit tests covering the whole API in
|
|
|
|
|
unittests/array-view-selftests.c. */
|
|
|
|
|
|
|
|
|
|
namespace gdb {
|
|
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
|
class array_view
|
|
|
|
|
{
|
|
|
|
|
/* True iff decayed T is the same as decayed U. E.g., we want to
|
|
|
|
|
say that 'T&' is the same as 'const T'. */
|
|
|
|
|
template <typename U>
|
|
|
|
|
using IsDecayedT = typename std::is_same<typename std::decay<T>::type,
|
|
|
|
|
typename std::decay<U>::type>;
|
|
|
|
|
|
|
|
|
|
/* True iff decayed T is the same as decayed U, and 'U *' is
|
|
|
|
|
implicitly convertible to 'T *'. This is a requirement for
|
|
|
|
|
several methods. */
|
|
|
|
|
template <typename U>
|
|
|
|
|
using DecayedConvertible = gdb::And<IsDecayedT<U>,
|
|
|
|
|
std::is_convertible<U *, T *>>;
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
using value_type = T;
|
|
|
|
|
using reference = T &;
|
|
|
|
|
using const_reference = const T &;
|
|
|
|
|
using size_type = size_t;
|
|
|
|
|
|
|
|
|
|
/* Default construction creates an empty view. */
|
|
|
|
|
constexpr array_view () noexcept
|
|
|
|
|
: m_array (nullptr), m_size (0)
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
/* Create an array view over a single object of the type of an
|
|
|
|
|
array_view element. The created view as size==1. This is
|
|
|
|
|
templated on U to allow constructing a array_view<const T> over a
|
|
|
|
|
(non-const) T. The "convertible" requirement makes sure that you
|
|
|
|
|
can't create an array_view<T> over a const T. */
|
|
|
|
|
template<typename U,
|
|
|
|
|
typename = Requires<DecayedConvertible<U>>>
|
|
|
|
|
constexpr array_view (U &elem) noexcept
|
|
|
|
|
: m_array (&elem), m_size (1)
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
/* Same as above, for rvalue references. */
|
|
|
|
|
template<typename U,
|
|
|
|
|
typename = Requires<DecayedConvertible<U>>>
|
|
|
|
|
constexpr array_view (U &&elem) noexcept
|
|
|
|
|
: m_array (&elem), m_size (1)
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
/* Create an array view from a pointer to an array and an element
|
|
|
|
|
count. */
|
|
|
|
|
template<typename U,
|
|
|
|
|
typename = Requires<DecayedConvertible<U>>>
|
|
|
|
|
constexpr array_view (U *array, size_t size) noexcept
|
|
|
|
|
: m_array (array), m_size (size)
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
/* Create an array view from a range. This is templated on both U
|
|
|
|
|
an V to allow passing in a mix of 'const T *' and 'T *'. */
|
|
|
|
|
template<typename U, typename V,
|
|
|
|
|
typename = Requires<DecayedConvertible<U>>,
|
|
|
|
|
typename = Requires<DecayedConvertible<V>>>
|
|
|
|
|
constexpr array_view (U *begin, V *end) noexcept
|
|
|
|
|
: m_array (begin), m_size (end - begin)
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
/* Create an array view from an array. */
|
|
|
|
|
template<typename U, size_t Size,
|
|
|
|
|
typename = Requires<DecayedConvertible<U>>>
|
|
|
|
|
constexpr array_view (U (&array)[Size]) noexcept
|
|
|
|
|
: m_array (array), m_size (Size)
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
/* Create an array view from a contiguous container. E.g.,
|
|
|
|
|
std::vector and std::array. */
|
|
|
|
|
template<typename Container,
|
|
|
|
|
typename = Requires<gdb::Not<IsDecayedT<Container>>>,
|
|
|
|
|
typename
|
|
|
|
|
= Requires<std::is_convertible
|
|
|
|
|
<decltype (std::declval<Container> ().data ()),
|
|
|
|
|
T *>>,
|
|
|
|
|
typename
|
|
|
|
|
= Requires<std::is_convertible
|
|
|
|
|
<decltype (std::declval<Container> ().size ()),
|
|
|
|
|
size_type>>>
|
|
|
|
|
constexpr array_view (Container &&c) noexcept
|
|
|
|
|
: m_array (c.data ()), m_size (c.size ())
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
/* Observer methods. Some of these can't be constexpr until we
|
|
|
|
|
require C++14. */
|
|
|
|
|
/*constexpr14*/ T *data () noexcept { return m_array; }
|
|
|
|
|
constexpr const T *data () const noexcept { return m_array; }
|
|
|
|
|
|
|
|
|
|
/*constexpr14*/ T *begin () noexcept { return m_array; }
|
|
|
|
|
constexpr const T *begin () const noexcept { return m_array; }
|
|
|
|
|
|
|
|
|
|
/*constexpr14*/ T *end () noexcept { return m_array + m_size; }
|
|
|
|
|
constexpr const T *end () const noexcept { return m_array + m_size; }
|
|
|
|
|
|
|
|
|
|
/*constexpr14*/ reference operator[] (size_t index) noexcept
|
|
|
|
|
{ return m_array[index]; }
|
|
|
|
|
constexpr const_reference operator[] (size_t index) const noexcept
|
|
|
|
|
{ return m_array[index]; }
|
|
|
|
|
|
|
|
|
|
constexpr size_type size () const noexcept { return m_size; }
|
|
|
|
|
constexpr bool empty () const noexcept { return m_size == 0; }
|
|
|
|
|
|
invoke_xmethod & array_view
This replaces more pointer+length with gdb::array_view. This time,
around invoke_xmethod, and then propagating the fallout around, which
inevitably leaks to the overload resolution code.
There are several places in the code that want to grab a slice of an
array, by advancing the array pointer, and decreasing the length
pointer. This patch introduces a pair of new
gdb::array_view::slice(...) methods to make that convenient and clear.
Unit test included.
gdb/ChangeLog:
2018-11-21 Pedro Alves <palves@redhat.com>
* common/array-view.h (array_view::splice(size_type, size_t)): New.
(array_view::splice(size_type)): New.
* eval.c (eval_call, evaluate_funcall): Adjust to use array_view.
* extension.c (xmethod_worker::get_arg_types): Adjust to return an
std::vector.
(xmethod_worker::get_result_type): Adjust to use gdb::array_view.
* extension.h: Include "common/array-view.h".
(xmethod_worker::invoke): Adjust to use gdb::array_view.
(xmethod_worker::get_arg_types): Adjust to return an std::vector.
(xmethod_worker::get_result_type): Adjust to use gdb::array_view.
(xmethod_worker::do_get_arg_types): Adjust to use std::vector.
(xmethod_worker::do_get_result_type): Adjust to use
gdb::array_view.
* gdbtypes.c (rank_function): Adjust to use gdb::array_view.
* gdbtypes.h: Include "common/array-view.h".
(rank_function): Adjust to use gdb::array_view.
* python/py-xmethods.c (python_xmethod_worker::invoke)
(python_xmethod_worker::do_get_arg_types)
(python_xmethod_worker::do_get_result_type)
(python_xmethod_worker::invoke): Adjust to new interfaces.
* valarith.c (value_user_defined_cpp_op, value_user_defined_op)
(value_x_binop, value_x_unop): Adjust to use gdb::array_view.
* valops.c (find_overload_match, find_oload_champ_namespace)
(find_oload_champ_namespace_loop, find_oload_champ): Adjust to use
gdb:array_view and the new xmethod_worker interfaces.
* value.c (result_type_of_xmethod, call_xmethod): Adjust to use
gdb::array_view.
* value.h (find_overload_match, result_type_of_xmethod)
(call_xmethod): Adjust to use gdb::array_view.
* unittests/array-view-selftests.c: Add slicing tests.
2018-11-21 19:55:12 +08:00
|
|
|
|
/* Slice an array view. */
|
|
|
|
|
|
|
|
|
|
/* Return a new array view over SIZE elements starting at START. */
|
|
|
|
|
constexpr array_view<T> slice (size_type start, size_type size) const noexcept
|
|
|
|
|
{ return {m_array + start, size}; }
|
|
|
|
|
|
|
|
|
|
/* Return a new array view over all the elements after START,
|
|
|
|
|
inclusive. */
|
|
|
|
|
constexpr array_view<T> slice (size_type start) const noexcept
|
|
|
|
|
{ return {m_array + start, size () - start}; }
|
|
|
|
|
|
2017-09-05 00:10:12 +08:00
|
|
|
|
private:
|
|
|
|
|
T *m_array;
|
|
|
|
|
size_type m_size;
|
|
|
|
|
};
|
|
|
|
|
|
2018-04-10 03:45:39 +08:00
|
|
|
|
/* 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. */
|
|
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
|
bool
|
|
|
|
|
operator== (const gdb::array_view<T> &lhs, const gdb::array_view<T> &rhs)
|
|
|
|
|
{
|
|
|
|
|
if (lhs.size () != rhs.size ())
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < lhs.size (); i++)
|
|
|
|
|
if (!(lhs[i] == rhs[i]))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Compare two array_views for inequality. */
|
|
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
|
bool
|
|
|
|
|
operator!= (const gdb::array_view<T> &lhs, const gdb::array_view<T> &rhs)
|
|
|
|
|
{
|
|
|
|
|
return !(lhs == rhs);
|
|
|
|
|
}
|
|
|
|
|
|
Use gdb:array_view in call_function_by_hand & friends
This replaces a few uses of pointer+length with gdb::array_view, in
call_function_by_hand and related code.
Unfortunately, due to -Wnarrowing, there are places where we can't
brace-initialize an gdb::array_view without an ugly-ish cast. To
avoid the cast, this patch introduces a gdb::make_array_view function.
Unit tests included.
This patch in isolation may not look so interesting, due to
gdb::make_array_view uses, but I think it's still worth it. Some of
the gdb::make_array_view calls disappear down the series, and others
could be eliminated with more (non-trivial) gdb::array_view
detangling/conversion (e.g. code around eval_call). See this as a "we
have to start somewhere" patch.
gdb/ChangeLog:
2018-11-21 Pedro Alves <palves@redhat.com>
* ada-lang.c (ada_evaluate_subexp): Adjust to pass an array_view.
* common/array-view.h (make_array_view): New.
* compile/compile-object-run.c (compile_object_run): Adjust to
pass an array_view.
* elfread.c (elf_gnu_ifunc_resolve_addr): Adjust.
* eval.c (eval_call): Adjust to pass an array_view.
(evaluate_subexp_standard): Adjust to pass an array_view.
* gcore.c (call_target_sbrk): Adjust to pass an array_view.
* guile/scm-value.c (gdbscm_value_call): Likewise.
* infcall.c (push_dummy_code): Replace pointer + size parameters
with an array_view parameter.
(call_function_by_hand, call_function_by_hand_dummy): Likewise and
adjust.
* infcall.h: Include "common/array-view.h".
(call_function_by_hand, call_function_by_hand_dummy): Replace
pointer + size parameters with an array_view parameter.
* linux-fork.c (inferior_call_waitpid): Adjust to use array_view.
* linux-tdep.c (linux_infcall_mmap): Likewise.
* objc-lang.c (lookup_objc_class, lookup_child_selector)
(value_nsstring, print_object_command): Likewise.
* python/py-value.c (valpy_call): Likewise.
* rust-lang.c (rust_evaluate_funcall): Likewise.
* spu-tdep.c (flush_ea_cache): Likewise.
* valarith.c (value_x_binop, value_x_unop): Likewise.
* valops.c (value_allocate_space_in_inferior): Likewise.
* unittests/array-view-selftests.c (run_tests): Add
gdb::make_array_view test.
2018-11-21 19:55:11 +08:00
|
|
|
|
/* Create an array view from a pointer to an array and an element
|
|
|
|
|
count.
|
|
|
|
|
|
|
|
|
|
This is useful as alternative to constructing an array_view using
|
|
|
|
|
brace initialization when the size variable you have handy is of
|
|
|
|
|
signed type, since otherwise without an explicit cast the code
|
|
|
|
|
would be ill-formed.
|
|
|
|
|
|
|
|
|
|
For example, with:
|
|
|
|
|
|
|
|
|
|
extern void foo (int, int, gdb::array_view<value *>);
|
|
|
|
|
|
|
|
|
|
value *args[2];
|
|
|
|
|
int nargs;
|
|
|
|
|
foo (1, 2, {values, nargs});
|
|
|
|
|
|
|
|
|
|
You'd get:
|
|
|
|
|
|
|
|
|
|
source.c:10: error: narrowing conversion of ‘nargs’ from ‘int’ to
|
|
|
|
|
‘size_t {aka long unsigned int}’ inside { } [-Werror=narrowing]
|
|
|
|
|
|
|
|
|
|
You could fix it by writing the somewhat distracting explicit cast:
|
|
|
|
|
|
|
|
|
|
foo (1, 2, {values, (size_t) nargs});
|
|
|
|
|
|
|
|
|
|
Or by instantiating an array_view explicitly:
|
|
|
|
|
|
|
|
|
|
foo (1, 2, gdb::array_view<value *>(values, nargs));
|
|
|
|
|
|
|
|
|
|
Or, better, using make_array_view, which has the advantage of
|
|
|
|
|
inferring the arrav_view element's type:
|
|
|
|
|
|
|
|
|
|
foo (1, 2, gdb::make_array_view (values, nargs));
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
template<typename U>
|
|
|
|
|
constexpr inline array_view<U>
|
|
|
|
|
make_array_view (U *array, size_t size) noexcept
|
|
|
|
|
{
|
|
|
|
|
return {array, size};
|
|
|
|
|
}
|
|
|
|
|
|
2017-09-05 00:10:12 +08:00
|
|
|
|
} /* namespace gdb */
|
|
|
|
|
|
|
|
|
|
#endif
|