180 lines
6.1 KiB
C
180 lines
6.1 KiB
C
|
/* Copyright (C) 2017 Free Software Foundation, Inc.
|
||
|
|
||
|
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; }
|
||
|
|
||
|
private:
|
||
|
T *m_array;
|
||
|
size_type m_size;
|
||
|
};
|
||
|
|
||
|
} /* namespace gdb */
|
||
|
|
||
|
#endif
|