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