forked from OSchip/llvm-project
223 lines
7.0 KiB
C
223 lines
7.0 KiB
C
|
//===--- span- The span class -----------------------------------*- C++ -*-===//
|
||
|
//
|
||
|
// The LLVM Compiler Infrastructure
|
||
|
//
|
||
|
// This file is distributed under the University of Illinois Open Source
|
||
|
// License. See LICENSE.TXT for details.
|
||
|
//
|
||
|
//===----------------------------------------------------------------------===//
|
||
|
|
||
|
#ifndef ACXXEL_SPAN_H
|
||
|
#define ACXXEL_SPAN_H
|
||
|
|
||
|
#include <array>
|
||
|
#include <cstddef>
|
||
|
#include <exception>
|
||
|
#include <iterator>
|
||
|
#include <type_traits>
|
||
|
|
||
|
namespace acxxel {
|
||
|
|
||
|
/// Value used to indicate slicing to the end of the span.
|
||
|
static constexpr std::ptrdiff_t dynamic_extent = -1; // NOLINT
|
||
|
|
||
|
class SpanBase {};
|
||
|
|
||
|
/// Implementation of the proposed C++17 std::span class.
|
||
|
///
|
||
|
/// Based on the paper:
|
||
|
/// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0122r1.pdf
|
||
|
template <typename ElementType> class Span : public SpanBase {
|
||
|
public:
|
||
|
/// \name constants and types
|
||
|
/// \{
|
||
|
|
||
|
using element_type = ElementType;
|
||
|
using index_type = std::ptrdiff_t;
|
||
|
using pointer = element_type *;
|
||
|
using reference = element_type &;
|
||
|
using iterator = element_type *;
|
||
|
using const_iterator = const element_type *;
|
||
|
using value_type = typename std::remove_const<element_type>::type;
|
||
|
|
||
|
/// \}
|
||
|
|
||
|
/// \name constructors, copy, assignment, and destructor.
|
||
|
/// \{
|
||
|
|
||
|
/// Constructs an empty span with null pointer data.
|
||
|
Span() : Data(nullptr), Size(0) {}
|
||
|
|
||
|
/// Constructs an empty span with null pointer data.
|
||
|
// Intentionally implicit.
|
||
|
Span(std::nullptr_t) : Data(nullptr), Size(0) {}
|
||
|
|
||
|
/// Constructs a span from a pointer and element count.
|
||
|
Span(pointer Ptr, index_type Count) : Data(Ptr), Size(Count) {
|
||
|
if (Count < 0 || (!Ptr && Count))
|
||
|
std::terminate();
|
||
|
}
|
||
|
|
||
|
/// Constructs a span from a pointer to the fist element in the range and a
|
||
|
/// pointer to one past the last element in the range.
|
||
|
Span(pointer FirstElem, pointer LastElem)
|
||
|
: Data(FirstElem), Size(std::distance(FirstElem, LastElem)) {
|
||
|
if (Size < 0)
|
||
|
std::terminate();
|
||
|
}
|
||
|
|
||
|
/// Constructs a span from an array.
|
||
|
// Intentionally implicit.
|
||
|
template <typename T, size_t N> Span(T (&Arr)[N]) : Data(Arr), Size(N) {}
|
||
|
|
||
|
/// Constructs a span from a std::array.
|
||
|
// Intentionally implicit.
|
||
|
template <size_t N>
|
||
|
Span(const std::array<typename std::remove_const<element_type>::type, N> &Arr)
|
||
|
: Data(Arr.data()), Size(N) {}
|
||
|
|
||
|
/// Constructs a span from a container such as a std::vector.
|
||
|
// TODO(jhen): Put in a check to make sure this constructor does not
|
||
|
// participate in overload resolution unless Container meets the following
|
||
|
// requirements:
|
||
|
// * Container is a contiguous container and a sequence container.
|
||
|
// Intentionally implicit.
|
||
|
template <typename Container>
|
||
|
Span(Container &Cont,
|
||
|
typename std::enable_if<
|
||
|
std::is_same<
|
||
|
typename std::remove_const<typename Container::value_type>::type,
|
||
|
typename std::remove_const<element_type>::type>::value &&
|
||
|
!std::is_array<Container>::value &&
|
||
|
!std::is_base_of<SpanBase, Container>::value &&
|
||
|
std::is_convertible<decltype(&Cont[0]), pointer>::value>::type * =
|
||
|
nullptr)
|
||
|
: Data(Cont.data()), Size(Cont.size()) {}
|
||
|
|
||
|
/// Avoids creating spans from expiring temporary objects.
|
||
|
// TODO(jhen): Put in a check to make sure this constructor does not
|
||
|
// participate in overload resolution unless Container meets the following
|
||
|
// requirements:
|
||
|
// * Container is a contiguous container and a sequence container.
|
||
|
template <typename Container>
|
||
|
Span(Container &&Cont,
|
||
|
typename std::enable_if<
|
||
|
std::is_same<
|
||
|
typename std::remove_const<typename Container::value_type>::type,
|
||
|
typename std::remove_const<element_type>::type>::value &&
|
||
|
!std::is_array<Container>::value &&
|
||
|
!std::is_base_of<SpanBase, Container>::value &&
|
||
|
std::is_convertible<decltype(&Cont[0]), pointer>::value>::type * =
|
||
|
nullptr) = delete;
|
||
|
|
||
|
Span(const Span &) noexcept = default;
|
||
|
Span(Span &&) noexcept;
|
||
|
|
||
|
/// Constructs a span from copying a span of another type that can be
|
||
|
/// implicitly converted to the type stored by the constructed span.
|
||
|
// Intentionally implicit.
|
||
|
template <typename OtherElementType>
|
||
|
Span(const Span<OtherElementType> &Other)
|
||
|
: Data(Other.Data), Size(Other.Size) {}
|
||
|
|
||
|
/// Constructs a span from moving a span of another type that can be
|
||
|
/// implicitly converted to the type stored by the constructed span.
|
||
|
// Intentionally implicit.
|
||
|
template <typename OtherElementType>
|
||
|
Span(Span<OtherElementType> &&Other) : Data(Other.Data), Size(Other.Size) {}
|
||
|
|
||
|
~Span() = default;
|
||
|
|
||
|
Span &operator=(const Span &) noexcept = default;
|
||
|
Span &operator=(Span &&) noexcept;
|
||
|
|
||
|
/// \}
|
||
|
|
||
|
/// \name subviews
|
||
|
/// \{
|
||
|
|
||
|
/// Creates a span out of the first Count elements of this span.
|
||
|
Span<element_type> first(index_type Count) const {
|
||
|
bool Valid = Count >= 0 && Count <= size();
|
||
|
if (!Valid)
|
||
|
std::terminate();
|
||
|
return Span<element_type>(data(), Count);
|
||
|
}
|
||
|
|
||
|
/// Creates a span out of the last Count elements of this span.
|
||
|
Span<element_type> last(index_type Count) const {
|
||
|
bool Valid = Count >= 0 && Count <= size();
|
||
|
if (!Valid)
|
||
|
std::terminate();
|
||
|
return Span<element_type>(Count == 0 ? data() : data() + (size() - Count),
|
||
|
Count);
|
||
|
}
|
||
|
|
||
|
/// Creates a span out of the Count elements of this span beginning at Offset.
|
||
|
///
|
||
|
/// If no arguments is provided for Count, the new span will extend to the end
|
||
|
/// of the current span.
|
||
|
Span<element_type> subspan(index_type Offset,
|
||
|
index_type Count = dynamic_extent) const {
|
||
|
bool Valid =
|
||
|
(Offset == 0 || (Offset > 0 && Offset <= size())) &&
|
||
|
(Count == dynamic_extent || (Count >= 0 && Offset + Count <= size()));
|
||
|
if (!Valid)
|
||
|
std::terminate();
|
||
|
return Span<element_type>(
|
||
|
data() + Offset, Count == dynamic_extent ? size() - Offset : Count);
|
||
|
}
|
||
|
|
||
|
/// \}
|
||
|
|
||
|
/// \name observers
|
||
|
/// \{
|
||
|
|
||
|
index_type length() const { return Size; }
|
||
|
index_type size() const { return Size; }
|
||
|
bool empty() const { return size() == 0; }
|
||
|
|
||
|
/// \}
|
||
|
|
||
|
/// \name element access
|
||
|
/// \{
|
||
|
|
||
|
reference operator[](index_type Idx) const {
|
||
|
bool Valid = Idx >= 0 && Idx < size();
|
||
|
if (!Valid)
|
||
|
std::terminate();
|
||
|
return Data[Idx];
|
||
|
}
|
||
|
|
||
|
reference operator()(index_type Idx) const { return operator[](Idx); }
|
||
|
|
||
|
pointer data() const noexcept { return Data; }
|
||
|
|
||
|
/// \}
|
||
|
|
||
|
/// \name iterator support
|
||
|
/// \{
|
||
|
|
||
|
iterator begin() const noexcept { return Data; }
|
||
|
iterator end() const noexcept { return Data + Size; }
|
||
|
const_iterator cbegin() const noexcept { return Data; }
|
||
|
const_iterator cend() const noexcept { return Data + Size; }
|
||
|
|
||
|
/// \}
|
||
|
|
||
|
private:
|
||
|
template <typename OtherElementType> friend class Span;
|
||
|
|
||
|
pointer Data;
|
||
|
index_type Size;
|
||
|
};
|
||
|
|
||
|
template <typename ElementType>
|
||
|
Span<ElementType>::Span(Span &&) noexcept = default;
|
||
|
template <typename ElementType>
|
||
|
Span<ElementType> &Span<ElementType>::operator=(Span &&) noexcept = default;
|
||
|
|
||
|
} // namespace acxxel
|
||
|
|
||
|
#endif // ACXXEL_SPAN_H
|