Line | Count | Source |
1 | | #ifndef ZSERIO_SPAN_H_INC |
2 | | #define ZSERIO_SPAN_H_INC |
3 | | |
4 | | #include <array> |
5 | | #include <cstddef> |
6 | | #include <limits> |
7 | | #include <iterator> |
8 | | #include <type_traits> |
9 | | #include <vector> |
10 | | |
11 | | namespace zserio |
12 | | { |
13 | | |
14 | | /** |
15 | | * Constant used to differentiate between spans of dynamic and static extent. |
16 | | */ |
17 | | constexpr std::size_t dynamic_extent = std::numeric_limits<std::size_t>::max(); |
18 | | |
19 | | namespace detail |
20 | | { |
21 | | |
22 | | template <typename T, std::size_t Extent> |
23 | | struct SpanStorage |
24 | | { |
25 | 2 | SpanStorage() = default; |
26 | | |
27 | | SpanStorage(T* data, std::size_t) : |
28 | | m_data(data) |
29 | 29 | {} |
30 | | |
31 | | T* m_data = nullptr; |
32 | | static constexpr std::size_t m_size = Extent; |
33 | | }; |
34 | | |
35 | | template <typename T> |
36 | | struct SpanStorage<T, dynamic_extent> |
37 | | { |
38 | 853 | SpanStorage() = default; |
39 | | |
40 | | SpanStorage(T* data, std::size_t size) : |
41 | | m_data(data), m_size(size) |
42 | 61.6k | {} |
43 | | |
44 | | T* m_data = nullptr; |
45 | | std::size_t m_size = 0; |
46 | | }; |
47 | | |
48 | | } // namespace detail |
49 | | |
50 | | /** |
51 | | * Class that holds non-owning reference (aka. "view") to continuous sequence of objects. |
52 | | * The user of this class is responsible of making sure, that the referenced sequence is valid |
53 | | * as long as the instance of the Span is alive. |
54 | | * Inspired by C++20 std::span. |
55 | | */ |
56 | | template <typename T, std::size_t Extent = dynamic_extent> |
57 | | class Span |
58 | | { |
59 | | public: |
60 | | using element_type = T; |
61 | | using value_type = typename std::remove_cv<T>::type; |
62 | | using size_type = std::size_t; |
63 | | using difference_type = std::ptrdiff_t; |
64 | | using pointer = T*; |
65 | | using const_pointer = const T*; |
66 | | using reference = T&; |
67 | | using iterator = pointer; |
68 | | using const_iterator = const_pointer; |
69 | | using reverse_iterator = std::reverse_iterator<iterator>; |
70 | | using const_reverse_iterator = std::reverse_iterator<const_iterator>; |
71 | | |
72 | | static constexpr size_type extent = Extent; |
73 | | |
74 | | /** |
75 | | * Constructor. Initializes empty Span. |
76 | | */ |
77 | | template <size_type ext = Extent, |
78 | | typename std::enable_if<(ext == 0 || ext == dynamic_extent), int>::type = 0> |
79 | | constexpr Span() noexcept |
80 | 855 | {} |
81 | | |
82 | | /** |
83 | | * Constructor. Initializes Span holding a reference starting at given pointer, having |
84 | | * given number of elements. |
85 | | * |
86 | | * \param first Pointer to first element in the sequence. |
87 | | * \param count Number of elements. |
88 | | */ |
89 | | constexpr Span(pointer first, size_type count) : |
90 | | m_storage(first, count) |
91 | 59.6k | {} |
92 | | |
93 | | /** |
94 | | * Constructor. Initializes Span holding a reference starting at given pointer, ending |
95 | | * at another pointer. |
96 | | * |
97 | | * \param first Pointer to first element in the sequence. |
98 | | * \param last Pointer to one-after-last element in the sequence. |
99 | | */ |
100 | | constexpr Span(pointer first, pointer last) : |
101 | | m_storage(first, static_cast<size_t>(last - first)) |
102 | 2 | {} |
103 | | |
104 | | /** |
105 | | * Constructor. Initializes Span holding a reference to array. |
106 | | * |
107 | | * \param arr Array to which the Span will hold a reference. |
108 | | */ |
109 | | template <size_type N, size_type ext = Extent, |
110 | | typename std::enable_if<(ext == dynamic_extent || ext == N), int>::type = 0> |
111 | | constexpr Span(element_type(&arr)[N]) noexcept : |
112 | | m_storage(arr, N) |
113 | 7 | {} |
114 | | |
115 | | /** |
116 | | * Constructor. Initializes Span holding a reference to std::array. |
117 | | * |
118 | | * \param arr std::array to which the Span will hold a reference. |
119 | | */ |
120 | | template <typename U, size_type N, size_type ext = Extent, |
121 | | typename std::enable_if<(ext == dynamic_extent || ext == N) && |
122 | | std::is_convertible<U(*)[], T(*)[]>::value, int>::type = 0> |
123 | | constexpr Span(std::array<U, N>& arr) noexcept : |
124 | | m_storage(arr.data(), arr.size()) |
125 | 10 | {} |
126 | | |
127 | | /** |
128 | | * Constructor. Initializes Span holding a reference to std::array. |
129 | | * |
130 | | * \param arr std::array to which the Span will hold a reference. |
131 | | */ |
132 | | template <typename U, size_type N, size_type ext = Extent, |
133 | | typename std::enable_if<(ext == dynamic_extent || ext == N) && |
134 | | std::is_convertible<const U(*)[], T(*)[]>::value, int>::type = 0> |
135 | | constexpr Span(const std::array<U, N>& arr) noexcept : |
136 | | m_storage(arr.data(), arr.size()) |
137 | 143 | {} |
138 | | |
139 | | /** |
140 | | * Constructor. Initializes Span holding a reference to std::vector. |
141 | | * |
142 | | * \param vec std::vector to which the Span will hold a reference. |
143 | | */ |
144 | | template <typename U, typename ALLOC, size_type ext = Extent, |
145 | | typename std::enable_if<(ext == dynamic_extent) && |
146 | | std::is_convertible<U(*)[], T(*)[]>::value, int>::type = 0> |
147 | | constexpr Span(std::vector<U, ALLOC>& vec) : |
148 | | m_storage(vec.data(), vec.size()) |
149 | 897 | {} |
150 | | |
151 | | /** |
152 | | * Constructor. Initializes Span holding a reference to std::vector. |
153 | | * |
154 | | * \param vec std::vector to which the Span will hold a reference. |
155 | | */ |
156 | | template <typename U, typename ALLOC, size_type ext = Extent, |
157 | | typename std::enable_if<(ext == dynamic_extent) && |
158 | | std::is_convertible<const U(*)[], T(*)[]>::value, int>::type = 0> |
159 | | constexpr Span(const std::vector<U, ALLOC>& vec) : |
160 | | m_storage(vec.data(), vec.size()) |
161 | 835 | {} |
162 | | |
163 | | /** |
164 | | * Constructor. Convert between spans of different types. |
165 | | * |
166 | | * \param s Input span. |
167 | | */ |
168 | | template <typename U, size_type N, |
169 | | typename std::enable_if<(Extent == N || Extent == dynamic_extent) && |
170 | | std::is_convertible<U(*)[], T(*)[]>::value, int>::type = 0> |
171 | | constexpr Span(const Span<U, N>& s) noexcept : |
172 | | m_storage(s.data(), s.size()) |
173 | 71 | {} |
174 | | |
175 | | /** |
176 | | * Method generated by default. |
177 | | * \{ |
178 | | */ |
179 | | ~Span() = default; |
180 | | |
181 | | Span(const Span& other) noexcept = default; |
182 | | Span& operator=(const Span& other) noexcept = default; |
183 | | |
184 | | Span(Span&& other) noexcept = default; |
185 | | Span& operator=(Span&& other) noexcept = default; |
186 | | /** |
187 | | * \} |
188 | | */ |
189 | | |
190 | | /** |
191 | | * Begin iteration. |
192 | | * |
193 | | * \return Iterator to the beginning of the sequence. |
194 | | */ |
195 | | constexpr iterator begin() const noexcept |
196 | 66.4k | { |
197 | 66.4k | return data(); |
198 | 66.4k | } |
199 | | |
200 | | /** |
201 | | * End iteration. |
202 | | * |
203 | | * \return Iterator one-past-last element of the sequence. |
204 | | */ |
205 | | constexpr iterator end() const noexcept |
206 | 53.9k | { |
207 | 53.9k | return data() + size(); |
208 | 53.9k | } |
209 | | |
210 | | /** |
211 | | * Begin reverse iteration. |
212 | | * |
213 | | * \return Reverse iterator to the last element. |
214 | | */ |
215 | | constexpr reverse_iterator rbegin() const noexcept |
216 | 2 | { |
217 | 2 | return reverse_iterator(end()); |
218 | 2 | } |
219 | | |
220 | | /** |
221 | | * End reverse iteration. |
222 | | * |
223 | | * \return Reverse iterator one-before-first element of the sequence. |
224 | | */ |
225 | | constexpr reverse_iterator rend() const noexcept |
226 | 8 | { |
227 | 8 | return reverse_iterator(begin()); |
228 | 8 | } |
229 | | |
230 | | /** |
231 | | * Get reference to the first element of the sequence. The sequence shall not be empty. |
232 | | * |
233 | | * \return Reference to the first element of the sequence |
234 | | */ |
235 | | constexpr reference front() const |
236 | 2 | { |
237 | 2 | return data()[0]; |
238 | 2 | } |
239 | | |
240 | | /** |
241 | | * Get reference to the last element of the sequence. The sequence shall not be empty. |
242 | | * |
243 | | * \return Reference to the last element of the sequence |
244 | | */ |
245 | | constexpr reference back() const |
246 | 2 | { |
247 | 2 | return data()[size() - 1]; |
248 | 2 | } |
249 | | |
250 | | /** |
251 | | * Access the element on given index. |
252 | | * |
253 | | * \param idx Index of element to be accessed. Must be less than size(). |
254 | | * \return Element on given index. |
255 | | */ |
256 | | constexpr reference operator[](size_type idx) const |
257 | 239k | { |
258 | 239k | return data()[idx]; |
259 | 239k | } |
260 | | |
261 | | /** |
262 | | * Get pointer to the sequence beginning. |
263 | | * |
264 | | * \return Pointer to the sequence beginning |
265 | | */ |
266 | | constexpr pointer data() const noexcept |
267 | 466k | { |
268 | 466k | return m_storage.m_data; |
269 | 466k | } |
270 | | |
271 | | /** |
272 | | * Get number of elements in the sequence. |
273 | | * |
274 | | * \return Number of elements in the sequence. |
275 | | */ |
276 | | constexpr size_type size() const noexcept |
277 | 167k | { |
278 | 167k | return m_storage.m_size; |
279 | 167k | } |
280 | | |
281 | | /** |
282 | | * Get size of sequence in bytes. |
283 | | * |
284 | | * \return Size of sequence in bytes. |
285 | | */ |
286 | | constexpr size_type size_bytes() const noexcept |
287 | 2 | { |
288 | 2 | return size() * sizeof(element_type); |
289 | 2 | } |
290 | | |
291 | | /** |
292 | | * Check if the sequence is empty. |
293 | | * |
294 | | * \return True if the sequence is empty, false otherwise. |
295 | | */ |
296 | | constexpr bool empty() const noexcept |
297 | 6 | { |
298 | 6 | return size() == 0; |
299 | 6 | } |
300 | | |
301 | | /** |
302 | | * Get subspan of given number of elements from the sequence start. |
303 | | * |
304 | | * \return Subspan of given number of elements from the sequence start. |
305 | | */ |
306 | | template <size_type Count> |
307 | | constexpr Span<element_type, Count> first() const |
308 | 2 | { |
309 | 2 | static_assert(Count <= Extent, "Requested number of characters out of range."); |
310 | 2 | return Span<element_type, Count>(data(), Count); |
311 | 2 | } |
312 | | |
313 | | /** |
314 | | * Get subspan of given number of elements from the sequence start. |
315 | | * |
316 | | * \param Count Requested number of elements in the subspan. Shall not be bigger than size(). |
317 | | * \return Subspan of given number of elements from the sequence start. |
318 | | */ |
319 | | constexpr Span<element_type, dynamic_extent> first(size_type Count) const |
320 | 2 | { |
321 | 2 | return Span<element_type, dynamic_extent>(data(), Count); |
322 | 2 | } |
323 | | |
324 | | /** |
325 | | * Get subspan of given number of elements from the sequence end. |
326 | | * |
327 | | * \return Subspan of given number of elements from the sequence end. |
328 | | */ |
329 | | template <size_type Count> |
330 | | constexpr Span<element_type, Count> last() const |
331 | 2 | { |
332 | 2 | static_assert(Count <= Extent, "Requested number of characters out of range."); |
333 | 2 | return Span<element_type, Count>(data() + (size() - Count), Count); |
334 | 2 | } |
335 | | |
336 | | /** |
337 | | * Get subspan of given number of elements from the sequence end. |
338 | | * |
339 | | * \param Count Requested number of elements in the subspan. Shall not be bigger than size(). |
340 | | * \return Subspan of given number of elements from the sequence end. |
341 | | */ |
342 | | constexpr Span<element_type, dynamic_extent> last(size_type Count) const |
343 | 2 | { |
344 | 2 | return Span<element_type, dynamic_extent>(data() + (size() - Count), Count); |
345 | 2 | } |
346 | | |
347 | | template <size_type Offset, size_type Count> |
348 | | using SubspanReturnType = |
349 | | Span<T, Count != dynamic_extent ? Count : (Extent != dynamic_extent ? Extent - Offset |
350 | | : dynamic_extent)>; |
351 | | |
352 | | /** |
353 | | * Get subspan of given number of elements beginning at given index. |
354 | | * |
355 | | * \return Subspan of given number of elements beginning at given index. |
356 | | */ |
357 | | /** \{ */ |
358 | | template <size_type Offset, size_type Count = dynamic_extent, |
359 | | typename std::enable_if<Count == dynamic_extent, int>::type = 0> |
360 | | constexpr SubspanReturnType<Offset, Count> subspan() const |
361 | 2 | { |
362 | 2 | static_assert((Extent == dynamic_extent) || (Offset <= Extent), |
363 | 2 | "Requested number of characters out of range."); |
364 | 2 | return SubspanReturnType<Offset, Count>(data() + Offset, size() - Offset); |
365 | 2 | } |
366 | | |
367 | | template <size_type Offset, size_type Count, |
368 | | typename std::enable_if<Count != dynamic_extent, int>::type = 0> |
369 | | constexpr SubspanReturnType<Offset, Count> subspan() const |
370 | 2 | { |
371 | 2 | static_assert((Extent == dynamic_extent) || (Offset <= Extent && Offset + Count <= Extent), |
372 | 2 | "Requested number of characters out of range."); |
373 | 2 | return SubspanReturnType<Offset, Count>(data() + Offset, Count); |
374 | 2 | } |
375 | | /** \} */ |
376 | | |
377 | | /** |
378 | | * Get subspan of given number of elements beginning at given index. |
379 | | * |
380 | | * \param Offset Index in the original sequence, where the new subspan should start |
381 | | * \param Count Requested number of elements in the subspan. |
382 | | * \return Subspan of given number of elements beginning at given index. |
383 | | */ |
384 | | constexpr Span<element_type, dynamic_extent> subspan(size_type Offset, |
385 | | size_type Count = dynamic_extent) const |
386 | 4 | { |
387 | 4 | return Span<element_type, dynamic_extent>(data() + Offset, |
388 | 4 | Count == dynamic_extent ? size() - Offset2 : Count2 ); |
389 | 4 | } |
390 | | |
391 | | private: |
392 | | detail::SpanStorage<T, Extent> m_storage; |
393 | | }; |
394 | | |
395 | | } // namespace zserio |
396 | | |
397 | | #endif // ZSERIO_SPAN_H_INC |