scc 2025.09
SystemC components library
span.h
1/*
2This is an implementation of C++20's std::span
3http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/n4820.pdf
4*/
5
6// Copyright Tristan Brindle 2018.
7// Distributed under the Boost Software License, Version 1.0.
8// (See below or https://www.boost.org/LICENSE_1_0.txt)
9/*
10 Boost Software License - Version 1.0 - August 17th, 2003
11
12 Permission is hereby granted, free of charge, to any person or organization
13 obtaining a copy of the software and accompanying documentation covered by
14 this license (the "Software") to use, reproduce, display, distribute,
15 execute, and transmit the Software, and to prepare derivative works of the
16 Software, and to permit third-parties to whom the Software is furnished to
17 do so, all subject to the following:
18
19 The copyright notices in the Software and this entire statement, including
20 the above license grant, this restriction and the following disclaimer,
21 must be included in all copies of the Software, in whole or in part, and
22 all derivative works of the Software, unless such copies or derivative
23 works are solely in the form of machine-executable object code generated by
24 a source language processor.
25
26 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
29 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
30 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
31 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
32 DEALINGS IN THE SOFTWARE.
33 */
34
35#ifndef TCB_SPAN_HPP_INCLUDED
36#define TCB_SPAN_HPP_INCLUDED
37
38#include <array>
39#include <cstddef>
40#include <cstdint>
41#include <type_traits>
42
43#ifndef TCB_SPAN_NO_EXCEPTIONS
44// Attempt to discover whether we're being compiled with exception support
45#if !(defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND))
46#define TCB_SPAN_NO_EXCEPTIONS
47#endif
48#endif
49
50#ifndef TCB_SPAN_NO_EXCEPTIONS
51#include <cstdio>
52#include <stdexcept>
53#endif
54
55// Various feature test macros
56
57#ifndef TCB_SPAN_NAMESPACE_NAME
58#define TCB_SPAN_NAMESPACE_NAME nonstd
59#endif
60
61#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
62#define TCB_SPAN_HAVE_CPP17
63#endif
64
65#if __cplusplus >= 201402L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201402L)
66#define TCB_SPAN_HAVE_CPP14
67#endif
68
69namespace TCB_SPAN_NAMESPACE_NAME {
70
71// Establish default contract checking behavior
72#if !defined(TCB_SPAN_THROW_ON_CONTRACT_VIOLATION) && !defined(TCB_SPAN_TERMINATE_ON_CONTRACT_VIOLATION) && \
73 !defined(TCB_SPAN_NO_CONTRACT_CHECKING)
74#if defined(NDEBUG) || !defined(TCB_SPAN_HAVE_CPP14)
75#define TCB_SPAN_NO_CONTRACT_CHECKING
76#else
77#define TCB_SPAN_TERMINATE_ON_CONTRACT_VIOLATION
78#endif
79#endif
80
81#if defined(TCB_SPAN_THROW_ON_CONTRACT_VIOLATION)
82struct contract_violation_error : std::logic_error {
83 explicit contract_violation_error(const char* msg)
84 : std::logic_error(msg) {}
85};
86
87inline void contract_violation(const char* msg) { throw contract_violation_error(msg); }
88
89#elif defined(TCB_SPAN_TERMINATE_ON_CONTRACT_VIOLATION)
90[[noreturn]] inline void contract_violation(const char* /*unused*/) { std::terminate(); }
91#endif
92
93#if !defined(TCB_SPAN_NO_CONTRACT_CHECKING)
94#define TCB_SPAN_STRINGIFY(cond) #cond
95#define TCB_SPAN_EXPECT(cond) cond ? (void)0 : contract_violation("Expected " TCB_SPAN_STRINGIFY(cond))
96#else
97#define TCB_SPAN_EXPECT(cond)
98#endif
99
100#if defined(TCB_SPAN_HAVE_CPP17) || defined(__cpp_inline_variables)
101#define TCB_SPAN_INLINE_VAR inline
102#else
103#define TCB_SPAN_INLINE_VAR
104#endif
105
106#if defined(TCB_SPAN_HAVE_CPP14) || (defined(__cpp_constexpr) && __cpp_constexpr >= 201304)
107#define TCB_SPAN_HAVE_CPP14_CONSTEXPR
108#endif
109
110#if defined(TCB_SPAN_HAVE_CPP14_CONSTEXPR)
111#define TCB_SPAN_CONSTEXPR14 constexpr
112#else
113#define TCB_SPAN_CONSTEXPR14
114#endif
115
116#if defined(TCB_SPAN_HAVE_CPP14_CONSTEXPR) && (!defined(_MSC_VER) || _MSC_VER > 1900)
117#define TCB_SPAN_CONSTEXPR_ASSIGN constexpr
118#else
119#define TCB_SPAN_CONSTEXPR_ASSIGN
120#endif
121
122#if defined(TCB_SPAN_NO_CONTRACT_CHECKING)
123#define TCB_SPAN_CONSTEXPR11 constexpr
124#else
125#define TCB_SPAN_CONSTEXPR11 TCB_SPAN_CONSTEXPR14
126#endif
127
128#if defined(TCB_SPAN_HAVE_CPP17) || defined(__cpp_deduction_guides)
129#define TCB_SPAN_HAVE_DEDUCTION_GUIDES
130#endif
131
132#if defined(TCB_SPAN_HAVE_CPP17) || defined(__cpp_lib_byte)
133#define TCB_SPAN_HAVE_STD_BYTE
134#endif
135
136#if defined(TCB_SPAN_HAVE_CPP17) || defined(__cpp_lib_array_constexpr)
137#define TCB_SPAN_HAVE_CONSTEXPR_STD_ARRAY_ETC
138#endif
139
140#if defined(TCB_SPAN_HAVE_CONSTEXPR_STD_ARRAY_ETC)
141#define TCB_SPAN_ARRAY_CONSTEXPR constexpr
142#else
143#define TCB_SPAN_ARRAY_CONSTEXPR
144#endif
145
146#ifdef TCB_SPAN_HAVE_STD_BYTE
147using byte = std::byte;
148#else
149using byte = unsigned char;
150#endif
151
152#if defined(TCB_SPAN_HAVE_CPP17)
153#define TCB_SPAN_NODISCARD [[nodiscard]]
154#else
155#define TCB_SPAN_NODISCARD
156#endif
157
158TCB_SPAN_INLINE_VAR constexpr std::size_t dynamic_extent = SIZE_MAX;
159
160template <typename ElementType, std::size_t Extent = dynamic_extent> class span;
161
162namespace detail {
163
164template <typename E, std::size_t S> struct span_storage {
165 constexpr span_storage() noexcept = default;
166
167 constexpr span_storage(E* p_ptr, std::size_t /*unused*/) noexcept
168 : ptr(p_ptr) {}
169
170 E* ptr = nullptr;
171 static constexpr std::size_t size = S;
172};
173
174template <typename E> struct span_storage<E, dynamic_extent> {
175 constexpr span_storage() noexcept = default;
176
177 constexpr span_storage(E* p_ptr, std::size_t p_size) noexcept
178 : ptr(p_ptr)
179 , size(p_size) {}
180
181 E* ptr = nullptr;
182 std::size_t size = 0;
183};
184
185// Reimplementation of C++17 std::size() and std::data()
186#if defined(TCB_SPAN_HAVE_CPP17) || defined(__cpp_lib_nonmember_container_access)
187using std::data;
188using std::size;
189#else
190template <class C> constexpr auto size(const C& c) -> decltype(c.size()) { return c.size(); }
191
192template <class T, std::size_t N> constexpr std::size_t size(const T (&)[N]) noexcept { return N; }
193
194template <class C> constexpr auto data(C& c) -> decltype(c.data()) { return c.data(); }
195
196template <class C> constexpr auto data(const C& c) -> decltype(c.data()) { return c.data(); }
197
198template <class T, std::size_t N> constexpr T* data(T (&array)[N]) noexcept { return array; }
199
200template <class E> constexpr const E* data(std::initializer_list<E> il) noexcept { return il.begin(); }
201#endif // TCB_SPAN_HAVE_CPP17
202
203#if defined(TCB_SPAN_HAVE_CPP17) || defined(__cpp_lib_void_t)
204using std::void_t;
205#else
206template <typename...> using void_t = void;
207#endif
208
209template <typename T> using uncvref_t = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
210
211template <typename> struct is_span : std::false_type {};
212
213template <typename T, std::size_t S> struct is_span<span<T, S>> : std::true_type {};
214
215template <typename> struct is_std_array : std::false_type {};
216
217template <typename T, std::size_t N> struct is_std_array<std::array<T, N>> : std::true_type {};
218
219template <typename, typename = void> struct has_size_and_data : std::false_type {};
220
221template <typename T>
222struct has_size_and_data<T, void_t<decltype(detail::size(std::declval<T>())), decltype(detail::data(std::declval<T>()))>> : std::true_type {
223};
224
225template <typename C, typename U = uncvref_t<C>> struct is_container {
226 static constexpr bool value = !is_span<U>::value && !is_std_array<U>::value && !std::is_array<U>::value && has_size_and_data<C>::value;
227};
228
229template <typename T> using remove_pointer_t = typename std::remove_pointer<T>::type;
230
231template <typename, typename, typename = void> struct is_container_element_type_compatible : std::false_type {};
232
233template <typename T, typename E>
235 T, E,
236 typename std::enable_if<!std::is_same<typename std::remove_cv<decltype(detail::data(std::declval<T>()))>::type, void>::value &&
237 std::is_convertible<remove_pointer_t<decltype(detail::data(std::declval<T>()))> (*)[], E (*)[]>::value>::type>
238: std::true_type {};
239
240template <typename, typename = size_t> struct is_complete : std::false_type {};
241
242template <typename T> struct is_complete<T, decltype(sizeof(T))> : std::true_type {};
243
244} // namespace detail
245
246template <typename ElementType, std::size_t Extent> class span {
247 static_assert(std::is_object<ElementType>::value, "A span's ElementType must be an object type (not a "
248 "reference type or void)");
249 static_assert(detail::is_complete<ElementType>::value, "A span's ElementType must be a complete type (not a forward "
250 "declaration)");
251 static_assert(!std::is_abstract<ElementType>::value, "A span's ElementType cannot be an abstract class type");
252
254
255public:
256 // constants and types
257 using element_type = ElementType;
258 using value_type = typename std::remove_cv<ElementType>::type;
259 using size_type = std::size_t;
260 using difference_type = std::ptrdiff_t;
261 using pointer = element_type*;
262 using const_pointer = const element_type*;
263 using reference = element_type&;
264 using const_reference = const element_type&;
265 using iterator = pointer;
266 using reverse_iterator = std::reverse_iterator<iterator>;
267
268 static constexpr size_type extent = Extent;
269
270 // [span.cons], span constructors, copy, assignment, and destructor
271 template <std::size_t E = Extent, typename std::enable_if<(E == dynamic_extent || E <= 0), int>::type = 0> constexpr span() noexcept {}
272
273 TCB_SPAN_CONSTEXPR11 span(pointer ptr, size_type count)
274 : storage_(ptr, count) {
275 TCB_SPAN_EXPECT(extent == dynamic_extent || count == extent);
276 }
277
278 TCB_SPAN_CONSTEXPR11 span(pointer first_elem, pointer last_elem)
279 : storage_(first_elem, last_elem - first_elem) {
280 TCB_SPAN_EXPECT(extent == dynamic_extent || last_elem - first_elem == static_cast<std::ptrdiff_t>(extent));
281 }
282
283 template <std::size_t N, std::size_t E = Extent,
284 typename std::enable_if<(E == dynamic_extent || N == E) &&
285 detail::is_container_element_type_compatible<element_type (&)[N], ElementType>::value,
286 int>::type = 0>
287 constexpr span(element_type (&arr)[N]) noexcept
288 : storage_(arr, N) {}
289
290 template <typename T, std::size_t N, std::size_t E = Extent,
291 typename std::enable_if<(E == dynamic_extent || N == E) &&
292 detail::is_container_element_type_compatible<std::array<T, N>&, ElementType>::value,
293 int>::type = 0>
294 TCB_SPAN_ARRAY_CONSTEXPR span(std::array<T, N>& arr) noexcept
295 : storage_(arr.data(), N) {}
296
297 template <typename T, std::size_t N, std::size_t E = Extent,
298 typename std::enable_if<(E == dynamic_extent || N == E) &&
299 detail::is_container_element_type_compatible<const std::array<T, N>&, ElementType>::value,
300 int>::type = 0>
301 TCB_SPAN_ARRAY_CONSTEXPR span(const std::array<T, N>& arr) noexcept
302 : storage_(arr.data(), N) {}
303
304 template <typename Container, std::size_t E = Extent,
305 typename std::enable_if<E == dynamic_extent && detail::is_container<Container>::value &&
307 int>::type = 0>
308 constexpr span(Container& cont)
309 : storage_(detail::data(cont), detail::size(cont)) {}
310
311 template <typename Container, std::size_t E = Extent,
312 typename std::enable_if<E == dynamic_extent && detail::is_container<Container>::value &&
314 int>::type = 0>
315 constexpr span(const Container& cont)
316 : storage_(detail::data(cont), detail::size(cont)) {}
317
318 constexpr span(const span& other) noexcept = default;
319
320 template <typename OtherElementType, std::size_t OtherExtent,
321 typename std::enable_if<(Extent == dynamic_extent || OtherExtent == dynamic_extent || Extent == OtherExtent) &&
322 std::is_convertible<OtherElementType (*)[], ElementType (*)[]>::value,
323 int>::type = 0>
324 constexpr span(const span<OtherElementType, OtherExtent>& other) noexcept
325 : storage_(other.data(), other.size()) {}
326
327 ~span() noexcept = default;
328
329 TCB_SPAN_CONSTEXPR_ASSIGN span& operator=(const span& other) noexcept = default;
330
331 // [span.sub], span subviews
332 template <std::size_t Count> TCB_SPAN_CONSTEXPR11 span<element_type, Count> first() const {
333 TCB_SPAN_EXPECT(Count <= size());
334 return {data(), Count};
335 }
336
337 template <std::size_t Count> TCB_SPAN_CONSTEXPR11 span<element_type, Count> last() const {
338 TCB_SPAN_EXPECT(Count <= size());
339 return {data() + (size() - Count), Count};
340 }
341
342 template <std::size_t Offset, std::size_t Count = dynamic_extent>
343 using subspan_return_t =
344 span<ElementType, Count != dynamic_extent ? Count : (Extent != dynamic_extent ? Extent - Offset : dynamic_extent)>;
345
346 template <std::size_t Offset, std::size_t Count = dynamic_extent> TCB_SPAN_CONSTEXPR11 subspan_return_t<Offset, Count> subspan() const {
347 TCB_SPAN_EXPECT(Offset <= size() && (Count == dynamic_extent || Offset + Count <= size()));
348 return {data() + Offset, Count != dynamic_extent ? Count : size() - Offset};
349 }
350
351 TCB_SPAN_CONSTEXPR11 span<element_type, dynamic_extent> first(size_type count) const {
352 TCB_SPAN_EXPECT(count <= size());
353 return {data(), count};
354 }
355
356 TCB_SPAN_CONSTEXPR11 span<element_type, dynamic_extent> last(size_type count) const {
357 TCB_SPAN_EXPECT(count <= size());
358 return {data() + (size() - count), count};
359 }
360
361 TCB_SPAN_CONSTEXPR11 span<element_type, dynamic_extent> subspan(size_type offset, size_type count = dynamic_extent) const {
362 TCB_SPAN_EXPECT(offset <= size() && (count == dynamic_extent || offset + count <= size()));
363 return {data() + offset, count == dynamic_extent ? size() - offset : count};
364 }
365
366 // [span.obs], span observers
367 constexpr size_type size() const noexcept { return storage_.size; }
368
369 constexpr size_type size_bytes() const noexcept { return size() * sizeof(element_type); }
370
371 TCB_SPAN_NODISCARD constexpr bool empty() const noexcept { return size() == 0; }
372
373 // [span.elem], span element access
374 TCB_SPAN_CONSTEXPR11 reference operator[](size_type idx) const {
375 TCB_SPAN_EXPECT(idx < size());
376 return *(data() + idx);
377 }
378
379 TCB_SPAN_CONSTEXPR11 reference front() const {
380 TCB_SPAN_EXPECT(!empty());
381 return *data();
382 }
383
384 TCB_SPAN_CONSTEXPR11 reference back() const {
385 TCB_SPAN_EXPECT(!empty());
386 return *(data() + (size() - 1));
387 }
388
389 constexpr pointer data() const noexcept { return storage_.ptr; }
390
391 // [span.iterators], span iterator support
392 constexpr iterator begin() const noexcept { return data(); }
393
394 constexpr iterator end() const noexcept { return data() + size(); }
395
396 TCB_SPAN_ARRAY_CONSTEXPR reverse_iterator rbegin() const noexcept { return reverse_iterator(end()); }
397
398 TCB_SPAN_ARRAY_CONSTEXPR reverse_iterator rend() const noexcept { return reverse_iterator(begin()); }
399
400private:
401 storage_type storage_{};
402};
403
404#ifdef TCB_SPAN_HAVE_DEDUCTION_GUIDES
405
406/* Deduction Guides */
407template <class T, size_t N> span(T (&)[N]) -> span<T, N>;
408
409template <class T, size_t N> span(std::array<T, N>&) -> span<T, N>;
410
411template <class T, size_t N> span(const std::array<T, N>&) -> span<const T, N>;
412
413template <class Container>
415
416template <class Container> span(const Container&) -> span<const typename Container::value_type>;
417
418#endif // TCB_HAVE_DEDUCTION_GUIDES
419
420template <typename ElementType, std::size_t Extent> constexpr span<ElementType, Extent> make_span(span<ElementType, Extent> s) noexcept {
421 return s;
422}
423
424template <typename T, std::size_t N> constexpr span<T, N> make_span(T (&arr)[N]) noexcept { return {arr}; }
425
426template <typename T, std::size_t N> TCB_SPAN_ARRAY_CONSTEXPR span<T, N> make_span(std::array<T, N>& arr) noexcept { return {arr}; }
427
428template <typename T, std::size_t N> TCB_SPAN_ARRAY_CONSTEXPR span<const T, N> make_span(const std::array<T, N>& arr) noexcept {
429 return {arr};
430}
431
432template <typename Container>
433constexpr span<typename std::remove_reference<decltype(*detail::data(std::declval<Container&>()))>::type> make_span(Container& cont) {
434 return {cont};
435}
436
437template <typename Container> constexpr span<const typename Container::value_type> make_span(const Container& cont) { return {cont}; }
438
439template <typename ElementType, std::size_t Extent>
440span<const byte, ((Extent == dynamic_extent) ? dynamic_extent : sizeof(ElementType) * Extent)>
441as_bytes(span<ElementType, Extent> s) noexcept {
442 return {reinterpret_cast<const byte*>(s.data()), s.size_bytes()};
443}
444
445template <class ElementType, size_t Extent, typename std::enable_if<!std::is_const<ElementType>::value, int>::type = 0>
446span<byte, ((Extent == dynamic_extent) ? dynamic_extent : sizeof(ElementType) * Extent)>
447as_writable_bytes(span<ElementType, Extent> s) noexcept {
448 return {reinterpret_cast<byte*>(s.data()), s.size_bytes()};
449}
450
451template <std::size_t N, typename E, std::size_t S> constexpr auto get(span<E, S> s) -> decltype(s[N]) { return s[N]; }
452
453} // namespace TCB_SPAN_NAMESPACE_NAME
454
455namespace std {
456
457template <typename ElementType, size_t Extent>
458class tuple_size<TCB_SPAN_NAMESPACE_NAME::span<ElementType, Extent>> : public integral_constant<size_t, Extent> {};
459
460template <typename ElementType>
461class tuple_size<TCB_SPAN_NAMESPACE_NAME::span<ElementType, TCB_SPAN_NAMESPACE_NAME::dynamic_extent>>; // not defined
462
463template <size_t I, typename ElementType, size_t Extent> class tuple_element<I, TCB_SPAN_NAMESPACE_NAME::span<ElementType, Extent>> {
464public:
465 static_assert(Extent != TCB_SPAN_NAMESPACE_NAME::dynamic_extent && I < Extent, "");
466 using type = ElementType;
467};
468
469} // end namespace std
470
471#endif // TCB_SPAN_HPP_INCLUDED