blob: a1df6244684beb15a2187d7efd8858f6d1adbf6d [file] [log] [blame]
Jason Henlineac232dd2016-10-25 20:18:56 +00001//===--- span- The span class -----------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#ifndef ACXXEL_SPAN_H
11#define ACXXEL_SPAN_H
12
13#include <array>
14#include <cstddef>
15#include <exception>
16#include <iterator>
17#include <type_traits>
18
19namespace acxxel {
20
21/// Value used to indicate slicing to the end of the span.
22static constexpr std::ptrdiff_t dynamic_extent = -1; // NOLINT
23
24class SpanBase {};
25
26/// Implementation of the proposed C++17 std::span class.
27///
28/// Based on the paper:
29/// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0122r1.pdf
30template <typename ElementType> class Span : public SpanBase {
31public:
32 /// \name constants and types
33 /// \{
34
35 using element_type = ElementType;
36 using index_type = std::ptrdiff_t;
37 using pointer = element_type *;
38 using reference = element_type &;
39 using iterator = element_type *;
40 using const_iterator = const element_type *;
41 using value_type = typename std::remove_const<element_type>::type;
42
43 /// \}
44
45 /// \name constructors, copy, assignment, and destructor.
46 /// \{
47
48 /// Constructs an empty span with null pointer data.
49 Span() : Data(nullptr), Size(0) {}
50
51 /// Constructs an empty span with null pointer data.
52 // Intentionally implicit.
53 Span(std::nullptr_t) : Data(nullptr), Size(0) {}
54
55 /// Constructs a span from a pointer and element count.
56 Span(pointer Ptr, index_type Count) : Data(Ptr), Size(Count) {
57 if (Count < 0 || (!Ptr && Count))
58 std::terminate();
59 }
60
61 /// Constructs a span from a pointer to the fist element in the range and a
62 /// pointer to one past the last element in the range.
63 Span(pointer FirstElem, pointer LastElem)
64 : Data(FirstElem), Size(std::distance(FirstElem, LastElem)) {
65 if (Size < 0)
66 std::terminate();
67 }
68
69 /// Constructs a span from an array.
70 // Intentionally implicit.
71 template <typename T, size_t N> Span(T (&Arr)[N]) : Data(Arr), Size(N) {}
72
73 /// Constructs a span from a std::array.
74 // Intentionally implicit.
75 template <size_t N>
76 Span(const std::array<typename std::remove_const<element_type>::type, N> &Arr)
77 : Data(Arr.data()), Size(N) {}
78
79 /// Constructs a span from a container such as a std::vector.
80 // TODO(jhen): Put in a check to make sure this constructor does not
81 // participate in overload resolution unless Container meets the following
82 // requirements:
83 // * Container is a contiguous container and a sequence container.
84 // Intentionally implicit.
85 template <typename Container>
86 Span(Container &Cont,
87 typename std::enable_if<
88 std::is_same<
89 typename std::remove_const<typename Container::value_type>::type,
90 typename std::remove_const<element_type>::type>::value &&
91 !std::is_array<Container>::value &&
92 !std::is_base_of<SpanBase, Container>::value &&
93 std::is_convertible<decltype(&Cont[0]), pointer>::value>::type * =
94 nullptr)
95 : Data(Cont.data()), Size(Cont.size()) {}
96
97 /// Avoids creating spans from expiring temporary objects.
98 // TODO(jhen): Put in a check to make sure this constructor does not
99 // participate in overload resolution unless Container meets the following
100 // requirements:
101 // * Container is a contiguous container and a sequence container.
102 template <typename Container>
103 Span(Container &&Cont,
104 typename std::enable_if<
105 std::is_same<
106 typename std::remove_const<typename Container::value_type>::type,
107 typename std::remove_const<element_type>::type>::value &&
108 !std::is_array<Container>::value &&
109 !std::is_base_of<SpanBase, Container>::value &&
110 std::is_convertible<decltype(&Cont[0]), pointer>::value>::type * =
111 nullptr) = delete;
112
113 Span(const Span &) noexcept = default;
114 Span(Span &&) noexcept;
115
116 /// Constructs a span from copying a span of another type that can be
117 /// implicitly converted to the type stored by the constructed span.
118 // Intentionally implicit.
119 template <typename OtherElementType>
120 Span(const Span<OtherElementType> &Other)
121 : Data(Other.Data), Size(Other.Size) {}
122
123 /// Constructs a span from moving a span of another type that can be
124 /// implicitly converted to the type stored by the constructed span.
125 // Intentionally implicit.
126 template <typename OtherElementType>
127 Span(Span<OtherElementType> &&Other) : Data(Other.Data), Size(Other.Size) {}
128
129 ~Span() = default;
130
131 Span &operator=(const Span &) noexcept = default;
132 Span &operator=(Span &&) noexcept;
133
134 /// \}
135
136 /// \name subviews
137 /// \{
138
139 /// Creates a span out of the first Count elements of this span.
140 Span<element_type> first(index_type Count) const {
141 bool Valid = Count >= 0 && Count <= size();
142 if (!Valid)
143 std::terminate();
144 return Span<element_type>(data(), Count);
145 }
146
147 /// Creates a span out of the last Count elements of this span.
148 Span<element_type> last(index_type Count) const {
149 bool Valid = Count >= 0 && Count <= size();
150 if (!Valid)
151 std::terminate();
152 return Span<element_type>(Count == 0 ? data() : data() + (size() - Count),
153 Count);
154 }
155
156 /// Creates a span out of the Count elements of this span beginning at Offset.
157 ///
158 /// If no arguments is provided for Count, the new span will extend to the end
159 /// of the current span.
160 Span<element_type> subspan(index_type Offset,
161 index_type Count = dynamic_extent) const {
162 bool Valid =
163 (Offset == 0 || (Offset > 0 && Offset <= size())) &&
164 (Count == dynamic_extent || (Count >= 0 && Offset + Count <= size()));
165 if (!Valid)
166 std::terminate();
167 return Span<element_type>(
168 data() + Offset, Count == dynamic_extent ? size() - Offset : Count);
169 }
170
171 /// \}
172
173 /// \name observers
174 /// \{
175
176 index_type length() const { return Size; }
177 index_type size() const { return Size; }
178 bool empty() const { return size() == 0; }
179
180 /// \}
181
182 /// \name element access
183 /// \{
184
185 reference operator[](index_type Idx) const {
186 bool Valid = Idx >= 0 && Idx < size();
187 if (!Valid)
188 std::terminate();
189 return Data[Idx];
190 }
191
192 reference operator()(index_type Idx) const { return operator[](Idx); }
193
194 pointer data() const noexcept { return Data; }
195
196 /// \}
197
198 /// \name iterator support
199 /// \{
200
201 iterator begin() const noexcept { return Data; }
202 iterator end() const noexcept { return Data + Size; }
203 const_iterator cbegin() const noexcept { return Data; }
204 const_iterator cend() const noexcept { return Data + Size; }
205
206 /// \}
207
208private:
209 template <typename OtherElementType> friend class Span;
210
211 pointer Data;
212 index_type Size;
213};
214
215template <typename ElementType>
216Span<ElementType>::Span(Span &&) noexcept = default;
217template <typename ElementType>
218Span<ElementType> &Span<ElementType>::operator=(Span &&) noexcept = default;
219
220} // namespace acxxel
221
222#endif // ACXXEL_SPAN_H