Sane C++ Libraries
C++ Platform Abstraction Libraries
Loading...
Searching...
No Matches
Span.h
1// Copyright (c) Stefano Cristiano
2// SPDX-License-Identifier: MIT
3#pragma once
4#include "../Foundation/InitializerList.h" // IWYU pragma: keep
5#include "../Foundation/LibC.h" // IWYU pragma: keep
6#include "../Foundation/TypeTraits.h" // SameConstnessAs
7
8namespace SC
9{
10template <typename Type>
11struct Span;
12
13namespace detail
14{
15// clang-format off
16template<typename U> struct SpanSizeOfType { static constexpr auto size = sizeof(U); };
17template<> struct SpanSizeOfType<void> { static constexpr auto size = 1; };
18template<> struct SpanSizeOfType<const void> { static constexpr auto size = 1; };
19// clang-format on
20} // namespace detail
21
24
27template <typename Type>
28struct Span
29{
30 private:
31 // clang-format off
32 using SizeType = size_t;
33 using VoidType = typename TypeTraits::SameConstnessAs<Type, void>::type;
34 template <typename U> using TypeIfNotVoid = typename TypeTraits::EnableIf<not TypeTraits::IsSame<U, VoidType>::value, Type>::type;
35 template <typename U> using SameType = TypeTraits::IsSame<typename TypeTraits::RemoveConst<U>::type, typename TypeTraits::RemoveConst<Type>::type>;
36 template <typename U> using EnableNotVoid = typename TypeTraits::EnableIf<SameType<U>::value and not TypeTraits::IsSame<U, VoidType>::value, bool>::type;
37 // clang-format on
38 Type* items;
39 SizeType sizeElements;
40
41 public:
42 template <size_t N, typename U = Type, EnableNotVoid<U> = true>
43 constexpr Span(U (&itemsArray)[N]) : items(itemsArray), sizeElements(N)
44 {}
45
47 constexpr Span() : items(nullptr), sizeElements(0) {}
48
52 constexpr Span(Type* items, SizeType sizeInElements) : items(items), sizeElements(sizeInElements) {}
53
56 template <typename U = Type>
57 constexpr Span(TypeIfNotVoid<U>& type) : items(&type), sizeElements(1)
58 {}
59
62 template <typename U = Type>
63 constexpr Span(std::initializer_list<TypeIfNotVoid<U>> list) : items(nullptr), sizeElements(0)
64 {
65 // We need this two step initialization to avoid warnings on all compilers
66 items = list.begin();
67 sizeElements = list.size();
68 }
69
70 // clang-format off
71 template <typename U = Type> operator Span<const TypeIfNotVoid<U>>() const { return {items, sizeElements}; }
72 template <typename U = Type> operator Span< TypeIfNotVoid<U>>() { return {items, sizeElements}; }
73 operator Span<const void>() const { return Span<const void>(items, sizeElements * detail::SpanSizeOfType<Type>::size); }
74 operator Span<void>() { return Span<void>(items, sizeElements * detail::SpanSizeOfType<Type>::size); }
75
80 template <typename T> [[nodiscard]] static Span<Type> reinterpret_object(T& value) { return {reinterpret_cast<Type*>(&value), sizeof(T) / detail::SpanSizeOfType<Type>::size}; }
81
86 [[nodiscard]] static Span<Type> reinterpret_bytes(VoidType* rawMemory, SizeType sizeInBytes) { return Span(reinterpret_cast<Type*>(rawMemory), sizeInBytes / detail::SpanSizeOfType<Type>::size); }
87
89 template <typename T> [[nodiscard]] Span<const T> reinterpret_as_span_of() const { return Span<const T>(reinterpret_cast<const T*>(items), sizeInBytes() / sizeof(T)); }
90
92 template <typename T> [[nodiscard]] Span<T> reinterpret_as_span_of() { return Span<T>(reinterpret_cast<T*>(items), sizeInBytes() / sizeof(T)); }
93
94 template <typename T> [[nodiscard]] T* start_lifetime_as_array() const noexcept
95 {
96 // TODO: Not a fully compliant implementation, replace it with a proper one under C++23
97 // https://stackoverflow.com/questions/79164176/emulate-stdstart-lifetime-as-array-in-c20
98 void* p = const_cast<void*>(static_cast<const void*>(data()));
99 return sizeElements == 0 ? static_cast<const T*>(p) : launder(static_cast<const T*>(::memmove(p, p, sizeof(T) * sizeElements)));
100 }
101
102 template <typename T> [[nodiscard]] T* start_lifetime_as_array() noexcept
103 {
104 void* p = data();
105 return sizeElements == 0 ? static_cast<T*>(p) : launder(static_cast<T*>(::memmove(p, p, sizeof(T) * sizeElements)));
106 }
107
108 template <typename T> [[nodiscard]] const T* start_lifetime_as() const noexcept
109 {
110 void* p = const_cast<void*>(static_cast<const void*>(data()));
111 return launder(static_cast<const T*>(::memmove(p, p, sizeof(T))));
112 }
113
114 template <typename T> [[nodiscard]] T* start_lifetime_as() noexcept
115 {
116 void* p = data();
117 return launder(static_cast<T*>(::memmove(p, p, sizeof(T))));
118 }
119
120 [[nodiscard]] constexpr const Type* begin() const { return items; }
121 [[nodiscard]] constexpr const Type* end() const { return items + sizeElements; }
122 [[nodiscard]] constexpr const Type* data() const { return items; }
123 [[nodiscard]] constexpr Type* begin() { return items; }
124 [[nodiscard]] constexpr Type* end() { return items + sizeElements; }
125 [[nodiscard]] constexpr Type* data() { return items; }
126
127 [[nodiscard]] constexpr SizeType sizeInElements() const { return sizeElements; }
128 [[nodiscard]] constexpr SizeType sizeInBytes() const { return sizeElements * detail::SpanSizeOfType<Type>::size; }
129
130 [[nodiscard]] constexpr bool empty() const { return sizeElements == 0; }
131
132 template <typename U = Type> TypeIfNotVoid<U>& operator[](SizeType idx) { return items[idx]; }
133 template <typename U = Type> const TypeIfNotVoid<U>& operator[](SizeType idx) const { return items[idx]; }
134 // clang-format on
135
142 [[nodiscard]] constexpr bool sliceStart(SizeType offsetInElements, Span& destination) const
143 {
144 if (offsetInElements <= sizeInElements())
145 {
146 destination = Span(items + offsetInElements, (sizeInElements() - offsetInElements));
147 return true;
148 }
149 return false;
150 }
151
159 [[nodiscard]] constexpr bool sliceStartLength(SizeType offsetInElements, SizeType lengthInElements,
160 Span& destination) const
161 {
162 if (offsetInElements + lengthInElements <= sizeInElements())
163 {
164 destination = Span(items + offsetInElements, lengthInElements);
165 return true;
166 }
167 return false;
168 }
169};
171
172} // namespace SC
unsigned long size_t
Platform independent unsigned size type.
Definition PrimitiveTypes.h:56
View over a contiguous sequence of items (pointer + size in elements).
Definition Span.h:29
static Span< Type > reinterpret_object(T &value)
Constructs a Span reinterpreting memory pointed by object of type T as a type Type
Definition Span.h:80
static Span< Type > reinterpret_bytes(VoidType *rawMemory, SizeType sizeInBytes)
Construct a span reinterpreting raw memory (void* or const void*) to Type or const Type
Definition Span.h:86
Span< T > reinterpret_as_span_of()
Reinterprets the current span as an array of the specified type.
Definition Span.h:92
Span< const T > reinterpret_as_span_of() const
Reinterprets the current span as an array of the specified type.
Definition Span.h:89
constexpr bool sliceStart(SizeType offsetInElements, Span &destination) const
Creates another Span, starting at an offset in elements from current Span, until end.
Definition Span.h:142
constexpr Span()
Builds an empty Span.
Definition Span.h:47
constexpr bool sliceStartLength(SizeType offsetInElements, SizeType lengthInElements, Span &destination) const
Creates another Span, starting at an offset in elements from current Span of specified length.
Definition Span.h:159
constexpr Span(Type *items, SizeType sizeInElements)
Builds a Span from an array.
Definition Span.h:52
constexpr Span(std::initializer_list< TypeIfNotVoid< U > > list)
Span specialized constructor (mainly used for converting const char* to StringView)
Definition Span.h:63
constexpr Span(TypeIfNotVoid< U > &type)
Builds a Span from a single object.
Definition Span.h:57
EnableIf conditionally defines a type if a boolean template parameter is true.
Definition TypeTraits.h:25
IsSame evaluates to true if the provided types T and U are the same, false otherwise.
Definition TypeTraits.h:29