scc 2026.07
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>
223 void_t<decltype(::nonstd::detail::size(std::declval<T>())), decltype(::nonstd::detail::data(std::declval<T>()))>>
224: std::true_type {};
225
226template <typename C, typename U = uncvref_t<C>> struct is_container {
227 static constexpr bool value = !is_span<U>::value && !is_std_array<U>::value && !std::is_array<U>::value && has_size_and_data<C>::value;
228};
229
230template <typename T> using remove_pointer_t = typename std::remove_pointer<T>::type;
231
232template <typename, typename, typename = void> struct is_container_element_type_compatible : std::false_type {};
233
234template <typename T, typename E>
236 T, E,
237 typename std::enable_if<
238 !std::is_same<typename std::remove_cv<decltype(::nonstd::detail::data(std::declval<T>()))>::type, void>::value &&
239 std::is_convertible<remove_pointer_t<decltype(::nonstd::detail::data(std::declval<T>()))> (*)[], E (*)[]>::value>::type>
240: std::true_type {};
241
242template <typename, typename = size_t> struct is_complete : std::false_type {};
243
244template <typename T> struct is_complete<T, decltype(sizeof(T))> : std::true_type {};
245
246} // namespace detail
247
248template <typename ElementType, std::size_t Extent> class span {
249 static_assert(std::is_object<ElementType>::value, "A span's ElementType must be an object type (not a "
250 "reference type or void)");
251 static_assert(::nonstd::detail::is_complete<ElementType>::value, "A span's ElementType must be a complete type (not a forward "
252 "declaration)");
253 static_assert(!std::is_abstract<ElementType>::value, "A span's ElementType cannot be an abstract class type");
254
255 using storage_type = ::nonstd::detail::span_storage<ElementType, Extent>;
256
257public:
258 // constants and types
259 using element_type = ElementType;
260 using value_type = typename std::remove_cv<ElementType>::type;
261 using size_type = std::size_t;
262 using difference_type = std::ptrdiff_t;
263 using pointer = element_type*;
264 using const_pointer = const element_type*;
265 using reference = element_type&;
266 using const_reference = const element_type&;
267 using iterator = pointer;
268 using reverse_iterator = std::reverse_iterator<iterator>;
269
270 static constexpr size_type extent = Extent;
271
272 // [span.cons], span constructors, copy, assignment, and destructor
273 template <std::size_t E = Extent, typename std::enable_if<(E == dynamic_extent || E <= 0), int>::type = 0> constexpr span() noexcept {}
274
275 TCB_SPAN_CONSTEXPR11 span(pointer ptr, size_type count)
276 : storage_(ptr, count) {
277 TCB_SPAN_EXPECT(extent == dynamic_extent || count == extent);
278 }
279
280 TCB_SPAN_CONSTEXPR11 span(pointer first_elem, pointer last_elem)
281 : storage_(first_elem, last_elem - first_elem) {
282 TCB_SPAN_EXPECT(extent == dynamic_extent || last_elem - first_elem == static_cast<std::ptrdiff_t>(extent));
283 }
284
285 template <std::size_t N, std::size_t E = Extent,
286 typename std::enable_if<(E == dynamic_extent || N == E) &&
287 ::nonstd::detail::is_container_element_type_compatible<element_type (&)[N], ElementType>::value,
288 int>::type = 0>
289 constexpr span(element_type (&arr)[N]) noexcept
290 : storage_(arr, N) {}
291
292 template <typename T, std::size_t N, std::size_t E = Extent,
293 typename std::enable_if<(E == dynamic_extent || N == E) &&
294 ::nonstd::detail::is_container_element_type_compatible<std::array<T, N>&, ElementType>::value,
295 int>::type = 0>
296 TCB_SPAN_ARRAY_CONSTEXPR span(std::array<T, N>& arr) noexcept
297 : storage_(arr.data(), N) {}
298
299 template <typename T, std::size_t N, std::size_t E = Extent,
300 typename std::enable_if<(E == dynamic_extent || N == E) && ::nonstd::detail::is_container_element_type_compatible<
301 const std::array<T, N>&, ElementType>::value,
302 int>::type = 0>
303 TCB_SPAN_ARRAY_CONSTEXPR span(const std::array<T, N>& arr) noexcept
304 : storage_(arr.data(), N) {}
305
306 template <typename Container, std::size_t E = Extent,
307 typename std::enable_if<E == dynamic_extent&& ::nonstd::detail::is_container<Container>::value&& ::nonstd::detail::
308 is_container_element_type_compatible<Container&, ElementType>::value,
309 int>::type = 0>
310 constexpr span(Container& cont)
311 : storage_(::nonstd::detail::data(cont), ::nonstd::detail::size(cont)) {}
312
313 template <typename Container, std::size_t E = Extent,
314 typename std::enable_if<E == dynamic_extent&& ::nonstd::detail::is_container<Container>::value&& ::nonstd::detail::
315 is_container_element_type_compatible<const Container&, ElementType>::value,
316 int>::type = 0>
317 constexpr span(const Container& cont)
318 : storage_(::nonstd::detail::data(cont), ::nonstd::detail::size(cont)) {}
319
320 constexpr span(const span& other) noexcept = default;
321
322 template <typename OtherElementType, std::size_t OtherExtent,
323 typename std::enable_if<(Extent == dynamic_extent || OtherExtent == dynamic_extent || Extent == OtherExtent) &&
324 std::is_convertible<OtherElementType (*)[], ElementType (*)[]>::value,
325 int>::type = 0>
326 constexpr span(const span<OtherElementType, OtherExtent>& other) noexcept
327 : storage_(other.data(), other.size()) {}
328
329 ~span() noexcept = default;
330
331 TCB_SPAN_CONSTEXPR_ASSIGN span& operator=(const span& other) noexcept = default;
332
333 // [span.sub], span subviews
334 template <std::size_t Count> TCB_SPAN_CONSTEXPR11 span<element_type, Count> first() const {
335 TCB_SPAN_EXPECT(Count <= size());
336 return {data(), Count};
337 }
338
339 template <std::size_t Count> TCB_SPAN_CONSTEXPR11 span<element_type, Count> last() const {
340 TCB_SPAN_EXPECT(Count <= size());
341 return {data() + (size() - Count), Count};
342 }
343
344 template <std::size_t Offset, std::size_t Count = dynamic_extent>
345 using subspan_return_t =
346 span<ElementType, Count != dynamic_extent ? Count : (Extent != dynamic_extent ? Extent - Offset : dynamic_extent)>;
347
348 template <std::size_t Offset, std::size_t Count = dynamic_extent> TCB_SPAN_CONSTEXPR11 subspan_return_t<Offset, Count> subspan() const {
349 TCB_SPAN_EXPECT(Offset <= size() && (Count == dynamic_extent || Offset + Count <= size()));
350 return {data() + Offset, Count != dynamic_extent ? Count : size() - Offset};
351 }
352
353 TCB_SPAN_CONSTEXPR11 span<element_type, dynamic_extent> first(size_type count) const {
354 TCB_SPAN_EXPECT(count <= size());
355 return {data(), count};
356 }
357
358 TCB_SPAN_CONSTEXPR11 span<element_type, dynamic_extent> last(size_type count) const {
359 TCB_SPAN_EXPECT(count <= size());
360 return {data() + (size() - count), count};
361 }
362
363 TCB_SPAN_CONSTEXPR11 span<element_type, dynamic_extent> subspan(size_type offset, size_type count = dynamic_extent) const {
364 TCB_SPAN_EXPECT(offset <= size() && (count == dynamic_extent || offset + count <= size()));
365 return {data() + offset, count == dynamic_extent ? size() - offset : count};
366 }
367
368 // [span.obs], span observers
369 constexpr size_type size() const noexcept { return storage_.size; }
370
371 constexpr size_type size_bytes() const noexcept { return size() * sizeof(element_type); }
372
373 TCB_SPAN_NODISCARD constexpr bool empty() const noexcept { return size() == 0; }
374
375 // [span.elem], span element access
376 TCB_SPAN_CONSTEXPR11 reference operator[](size_type idx) const {
377 TCB_SPAN_EXPECT(idx < size());
378 return *(data() + idx);
379 }
380
381 TCB_SPAN_CONSTEXPR11 reference front() const {
382 TCB_SPAN_EXPECT(!empty());
383 return *data();
384 }
385
386 TCB_SPAN_CONSTEXPR11 reference back() const {
387 TCB_SPAN_EXPECT(!empty());
388 return *(data() + (size() - 1));
389 }
390
391 constexpr pointer data() const noexcept { return storage_.ptr; }
392
393 // [span.iterators], span iterator support
394 constexpr iterator begin() const noexcept { return data(); }
395
396 constexpr iterator end() const noexcept { return data() + size(); }
397
398 TCB_SPAN_ARRAY_CONSTEXPR reverse_iterator rbegin() const noexcept { return reverse_iterator(end()); }
399
400 TCB_SPAN_ARRAY_CONSTEXPR reverse_iterator rend() const noexcept { return reverse_iterator(begin()); }
401
402private:
403 storage_type storage_{};
404};
405
406#ifdef TCB_SPAN_HAVE_DEDUCTION_GUIDES
407
408/* Deduction Guides */
409template <class T, size_t N> span(T (&)[N]) -> span<T, N>;
410
411template <class T, size_t N> span(std::array<T, N>&) -> span<T, N>;
412
413template <class T, size_t N> span(const std::array<T, N>&) -> span<const T, N>;
414
415template <class Container>
417
418template <class Container> span(const Container&) -> span<const typename Container::value_type>;
419
420#endif // TCB_HAVE_DEDUCTION_GUIDES
421
422template <typename ElementType, std::size_t Extent> constexpr span<ElementType, Extent> make_span(span<ElementType, Extent> s) noexcept {
423 return s;
424}
425
426template <typename T, std::size_t N> constexpr span<T, N> make_span(T (&arr)[N]) noexcept { return {arr}; }
427
428template <typename T, std::size_t N> TCB_SPAN_ARRAY_CONSTEXPR span<T, N> make_span(std::array<T, N>& arr) noexcept { return {arr}; }
429
430template <typename T, std::size_t N> TCB_SPAN_ARRAY_CONSTEXPR span<const T, N> make_span(const std::array<T, N>& arr) noexcept {
431 return {arr};
432}
433
434template <typename Container>
435constexpr span<typename std::remove_reference<decltype(*::nonstd::detail::data(std::declval<Container&>()))>::type>
436make_span(Container& cont) {
437 return {cont};
438}
439
440template <typename Container> constexpr span<const typename Container::value_type> make_span(const Container& cont) { return {cont}; }
441
442template <typename ElementType, std::size_t Extent>
443span<const byte, ((Extent == dynamic_extent) ? dynamic_extent : sizeof(ElementType) * Extent)>
444as_bytes(span<ElementType, Extent> s) noexcept {
445 return {reinterpret_cast<const byte*>(s.data()), s.size_bytes()};
446}
447
448template <class ElementType, size_t Extent, typename std::enable_if<!std::is_const<ElementType>::value, int>::type = 0>
449span<byte, ((Extent == dynamic_extent) ? dynamic_extent : sizeof(ElementType) * Extent)>
450as_writable_bytes(span<ElementType, Extent> s) noexcept {
451 return {reinterpret_cast<byte*>(s.data()), s.size_bytes()};
452}
453
454template <std::size_t N, typename E, std::size_t S> constexpr auto get(span<E, S> s) -> decltype(s[N]) { return s[N]; }
455
456} // namespace TCB_SPAN_NAMESPACE_NAME
457
458namespace std {
459
460template <typename ElementType, size_t Extent>
461class tuple_size<TCB_SPAN_NAMESPACE_NAME::span<ElementType, Extent>> : public integral_constant<size_t, Extent> {};
462
463template <typename ElementType>
464class tuple_size<TCB_SPAN_NAMESPACE_NAME::span<ElementType, TCB_SPAN_NAMESPACE_NAME::dynamic_extent>>; // not defined
465
466template <size_t I, typename ElementType, size_t Extent> class tuple_element<I, TCB_SPAN_NAMESPACE_NAME::span<ElementType, Extent>> {
467public:
468 static_assert(Extent != TCB_SPAN_NAMESPACE_NAME::dynamic_extent && I < Extent, "");
469 using type = ElementType;
470};
471
472} // end namespace std
473
474#endif // TCB_SPAN_HPP_INCLUDED