blob: 04dda75b5fce4875c259122349843fb5cc49791f [file] [log] [blame]
//===--- span- The span class -----------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#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