VCTR
Loading...
Searching...
No Matches
Span.h
1/*
2 ==============================================================================
3 DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
5 Copyright 2022- by sonible GmbH.
6
7 This file is part of VCTR - Versatile Container Templates Reconceptualized.
8
9 VCTR is free software: you can redistribute it and/or modify
10 it under the terms of the GNU Lesser General Public License version 3
11 only, as published by the Free Software Foundation.
12
13 VCTR is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU Lesser General Public License version 3 for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 version 3 along with VCTR. If not, see <https://www.gnu.org/licenses/>.
20 ==============================================================================
21*/
22
23namespace vctr
24{
25
38template <class ElementType, bool isDataSIMDAligned, bool isStorageSIMDExtended = false>
39using SpanStorageInfo = StaticStorageInfo<isDataSIMDAligned, isStorageSIMDExtended, alignof (std::span<ElementType>)>;
40
46template <class ElementType>
48
49// clang-format off
50
64template <class ElementType, size_t extent = std::dynamic_extent, class StorageInfoType = StorageInfoWithMemberAlignment<alignof (std::span<ElementType, extent>), StorageInfo<std::span<ElementType, extent> > > > // Extra whitespaces are needed for proper doxygen rendering
65class Span : public VctrBase<ElementType, std::span<ElementType, extent>, extent, StorageInfoType>
66{
67// clang-format on
68private:
69 //==============================================================================
71 using StdSpanType = std::span<ElementType, extent>;
72
73public:
74 //==============================================================================
75 using value_type = typename Vctr::value_type;
76
77 using element_type = ElementType;
78
79 //==============================================================================
80 // Constructors
81 //==============================================================================
82
84 constexpr Span (ElementType* ptr, size_t size)
85 : Vctr (StdSpanType (ptr, size))
86 {
87 VCTR_ASSERT (extent == size || extent == std::dynamic_extent);
88
89 if (Vctr::getStorageInfo().dataIsSIMDAligned)
90 {
91 // If you hit this assertion, you passed a StaticStorageInfo that specifies SIMD aligned
92 // memory, but it is not aligned. Required alignment is 32 byte on x64 and 16 byte on ARM.
93 VCTR_ASSERT (isPtrAligned (ptr));
94 }
95 }
96
102 template <bool isDataSIMDAligned, bool isStorageSIMDExtended>
103 constexpr Span (ElementType* ptr, size_t size, const StaticStorageInfo<isDataSIMDAligned, isStorageSIMDExtended, alignof (StdSpanType)>& info)
104 : Vctr (StdSpanType (ptr, size), info)
105 {
106 VCTR_ASSERT (extent == size || extent == std::dynamic_extent);
107
108 if constexpr (isDataSIMDAligned)
109 {
110 // If you hit this assertion, you passed a StaticStorageInfo that specifies SIMD aligned
111 // memory, but it is not aligned. Required alignment is 32 byte on x64 and 16 byte on ARM.
112 VCTR_ASSERT (isPtrAligned (ptr));
113 }
114 }
115
120 template <has::sizeAndDataWithElementType<ElementType> Container>
121 constexpr Span (Container&& containerToView)
122 : Vctr (StdSpanType (containerToView.data(), containerToView.size()), makeStorageInfo (containerToView))
123 {
124 VCTR_ASSERT (extent == containerToView.size() || extent == std::dynamic_extent);
125 }
126
128 template <std::same_as<ElementType> T, size_t n>
129 requires (n != std::dynamic_extent)
130 constexpr Span (T (&cStyleArray)[n])
131 requires (n == extent)
132 : Vctr (StdSpanType (cStyleArray))
133 {
134 if (Vctr::getStorageInfo().dataIsSIMDAligned)
135 {
136 // If you hit this assertion, you passed a StaticStorageInfo that specifies SIMD aligned
137 // memory, but it is not aligned. Required alignment is 32 byte on x64 and 16 byte on ARM.
138 VCTR_ASSERT (isPtrAligned (cStyleArray));
139 }
140 }
141
143 constexpr Span (ElementType* ptr)
144 requires (extent != std::dynamic_extent)
145 : Vctr (StdSpanType (ptr, extent))
146 {
147 if (Vctr::getStorageInfo().dataIsSIMDAligned)
148 {
149 // If you hit this assertion, you passed a StaticStorageInfo that specifies SIMD aligned
150 // memory, but it is not aligned. Required alignment is 32 byte on x64 and 16 byte on ARM.
151 VCTR_ASSERT (isPtrAligned (ptr));
152 }
153 }
154
155 //==============================================================================
156 // Operators
157 //==============================================================================
158 // Deleting the default copy operator forces the usage of the intended operator below
159 Span& operator= (const Span&) = delete;
160
162 template <has::sizeAndDataWithElementType<ElementType> Container>
163 constexpr Span& operator= (Container&& containerToCopyDataFrom)
164 {
165 if constexpr (Vctr::template shouldMoveFromOtherContainer<Container>)
166 {
167 VCTR_ASSERT (containerToCopyDataFrom.size() == Vctr::size());
168 std::copy (std::make_move_iterator (containerToCopyDataFrom.begin()), std::make_move_iterator (containerToCopyDataFrom.end()), Vctr::storage.begin());
169 }
170 else
171 {
172 Vctr::copyFrom (containerToCopyDataFrom.data(), containerToCopyDataFrom.size());
173 }
174
175 return *this;
176 }
177
179 constexpr Span& operator= (std::initializer_list<ElementType> elementsToAssign)
180 {
181 Vctr::assign (std::move (elementsToAssign));
182 return *this;
183 }
184
189 template <is::expression E>
190 constexpr void operator= (const E& expression)
191 {
192 VCTR_ASSERT (expression.size() == Vctr::size());
193
194 Vctr::assignExpressionTemplate (expression);
195 }
196
198 operator const StdSpanType&() { return Vctr::storage; }
199
200 //==============================================================================
206 template <class DstType>
207 constexpr auto castTo()
208 {
209 using SizeRatio = std::ratio<sizeof (ElementType), sizeof (DstType)>;
210 auto* dstData = reinterpret_cast<DstType*> (Vctr::data());
211
212 if constexpr (extent == std::dynamic_extent)
213 {
214 auto dstSize = detail::expectNoRemainderMultiplyBy<SizeRatio> (Vctr::size());
215 return Span<DstType> (dstData, dstSize);
216 }
217 else
218 {
219 constexpr auto dstSize = detail::expectNoRemainderMultiplyBy<SizeRatio> (Vctr::size());
220 return Span<DstType, dstSize> (dstData, dstSize);
221 }
222 }
223
224private:
225 //==============================================================================
226 template <has::sizeAndData Container>
227 static constexpr auto makeStorageInfo (const Container& container)
228 {
229 constexpr size_t memberAlignment = alignof (StdSpanType);
230
231 if constexpr (is::anyVctr<Container>)
232 {
233 const auto& info = container.getStorageInfo();
234 return StorageInfoWithMemberAlignment<memberAlignment, std::remove_cvref_t<decltype (info)>> (info);
235 }
236 else
237 {
238 return StorageInfoWithMemberAlignment<memberAlignment, StorageInfo<Container>>().init (container.data(), container.size());
239 }
240 }
241};
242
243//==============================================================================
244// Deduction guides
245//==============================================================================
246
247template <class ElementType, bool isDataSIMDAligned, bool isStorageSIMDExtended>
248Span (ElementType*, size_t, const StaticStorageInfo<isDataSIMDAligned, isStorageSIMDExtended, alignof (std::span<ElementType>)>&) -> Span<ElementType, std::dynamic_extent, StaticStorageInfo<isDataSIMDAligned, isStorageSIMDExtended, alignof (std::span<ElementType>)>>;
249
250template <class Container>
251Span (Container&&) -> Span<DataType<Container>, extentOf<Container>, StorageInfoWithMemberAlignment<alignof (std::span<DataType<Container>, extentOf<Container>>), StorageInfoType<Container>>>;
252
253template <class ElementType, size_t size>
254Span (ElementType (&)[size]) -> Span<ElementType, size, StorageInfoWithMemberAlignment<alignof (std::span<ElementType, size>), StorageInfo<std::span<ElementType, size>>>>;
255
257template <class ElementType>
258auto makeSimdAlignedSpan (ElementType* data, size_t size)
259{
260 // If you hit this assertion, you passed a StaticStorageInfo that specifies SIMD aligned
261 // memory, but it is not aligned. Required alignment is 32 byte on x64 and 16 byte on ARM.
262 VCTR_ASSERT (isPtrAligned (data));
263
264 return Span<ElementType, std::dynamic_extent, StaticStorageInfo<true, false, alignof (std::span<ElementType>)>> (data, size);
265}
266
268template <size_t extent, class ElementType>
269requires (extent != std::dynamic_extent)
270auto makeSimdAlignedSpan (ElementType* data)
271{
272 // If you hit this assertion, you passed a StaticStorageInfo that specifies SIMD aligned
273 // memory, but it is not aligned. Required alignment is 32 byte on x64 and 16 byte on ARM.
274 VCTR_ASSERT (isPtrAligned (data));
275
276 return Span<ElementType, extent, StaticStorageInfo<true, false, alignof (std::span<ElementType>)>> (data, extent);
277}
278
279} // namespace vctr
The view type.
Definition: Span.h:66
constexpr Span(ElementType *ptr, size_t size, const StaticStorageInfo< isDataSIMDAligned, isStorageSIMDExtended, alignof(StdSpanType)> &info)
Creates a Span with a given size that views externally managed data, accessed by ptr.
Definition: Span.h:103
constexpr Span(ElementType *ptr, size_t size)
Creates a Span with a given size that views externally managed data, accessed by ptr.
Definition: Span.h:84
constexpr Span(Container &&containerToView)
Creates a Span that acts as a view to the given container.
Definition: Span.h:121
constexpr Span(ElementType *ptr)
Creates a Span with a static extent that views externally managed data, accessed by ptr.
Definition: Span.h:143
constexpr auto castTo()
Casts this Span to a span of a different type by applying a reinterpret cast to the data.
Definition: Span.h:207
The base class to all one dimensional containers and views in the VCTR project.
Definition: VctrBase.h:38
constexpr size_t size() const noexcept
Returns the number of elements.
Definition: VctrBase.h:61
constexpr void assign(std::initializer_list< ElementType > elements)
Assigns elements from the initializer list to this instance.
Definition: VctrBase.h:266
constexpr void copyFrom(const ElementType *otherData, size_t otherSize)
Copies the content from otherData to this instance.
Definition: VctrBase.h:285
VCTR_FORCEDINLINE constexpr auto * data()
Returns a raw pointer to the underlying storage.
Definition: VctrBase.h:123
Constrains a type to be any derived instance of VctrBase.
Definition: ContainerAndExpressionConcepts.h:210
The main namespace of the VCTR project.
Definition: Array.h:24
typename detail::StorageInfoType< std::remove_cvref_t< T > >::Type StorageInfoType
If t is a type derived from VctrBase, this will equal the return value of T::getStorageInfo,...
Definition: Traits.h:227
constexpr bool isPtrAligned(const void *ptr)
Helper function to check if a pointer is aligned to the required alignment value.
Definition: SIMDHelpers.h:81
auto makeSimdAlignedSpan(ElementType *data, size_t size)
Creates a span with dynamic extent pointing to a memory location that is expected to be SIMD aligned.
Definition: Span.h:258
consteval auto simdAlignedSpanStorageInfo()
Creates a StaticStorageInfo instance suitable to be passed to a Span constructor.
Definition: Span.h:47
A storage info type especially used to pass compile time constant traits when viewing externally owne...
Definition: SIMDHelpers.h:183
A storage info type especially used for vctr::Span.
Definition: SIMDHelpers.h:197