forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			222 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			222 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			C++
		
	
	
	
//===--- 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
 |