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