]>
Commit | Line | Data |
---|---|---|
1e59de90 TL |
1 | /////////////////////////////////////////////////////////////////////////////// |
2 | // | |
3 | // Copyright (c) 2015 Microsoft Corporation. All rights reserved. | |
4 | // | |
5 | // This code is licensed under the MIT License (MIT). | |
6 | // | |
7 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
8 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
9 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
10 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
11 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
12 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
13 | // THE SOFTWARE. | |
14 | // | |
15 | /////////////////////////////////////////////////////////////////////////////// | |
16 | ||
17 | #ifndef GSL_MULTI_SPAN_H | |
18 | #define GSL_MULTI_SPAN_H | |
19 | ||
20 | #include <gsl/gsl_assert> // for Expects | |
21 | #include <gsl/gsl_byte> // for byte | |
22 | #include <gsl/gsl_util> // for narrow_cast | |
23 | ||
24 | #include <algorithm> // for transform, lexicographical_compare | |
25 | #include <array> // for array | |
26 | #include <cstddef> // for std::ptrdiff_t, size_t, nullptr_t | |
27 | #include <cstdint> // for PTRDIFF_MAX | |
28 | #include <functional> // for divides, multiplies, minus, negate, plus | |
29 | #include <initializer_list> // for initializer_list | |
30 | #include <iterator> // for iterator, random_access_iterator_tag | |
31 | #include <limits> // for numeric_limits | |
32 | #include <new> | |
33 | #include <numeric> | |
34 | #include <stdexcept> | |
35 | #include <string> // for basic_string | |
36 | #include <type_traits> // for enable_if_t, remove_cv_t, is_same, is_co... | |
37 | #include <utility> | |
38 | ||
39 | #if defined(_MSC_VER) && !defined(__clang__) | |
40 | ||
41 | // turn off some warnings that are noisy about our Expects statements | |
42 | #pragma warning(push) | |
43 | #pragma warning(disable : 4127) // conditional expression is constant | |
44 | #pragma warning(disable : 4702) // unreachable code | |
45 | ||
46 | // Turn MSVC /analyze rules that generate too much noise. TODO: fix in the tool. | |
47 | #pragma warning(disable : 26495) // uninitalized member when constructor calls constructor | |
48 | #pragma warning(disable : 26473) // in some instantiations we cast to the same type | |
49 | #pragma warning(disable : 26490) // TODO: bug in parser - attributes and templates | |
50 | #pragma warning(disable : 26465) // TODO: bug - suppression does not work on template functions | |
51 | #pragma warning(disable : 4996) // use of function or classes marked [[deprecated]] | |
52 | ||
53 | #endif // _MSC_VER | |
54 | ||
55 | #if defined(__GNUC__) || defined(__clang__) | |
56 | #pragma GCC diagnostic push | |
57 | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" | |
58 | #endif | |
59 | ||
60 | // GCC 7 does not like the signed unsigned missmatch (size_t std::ptrdiff_t) | |
61 | // While there is a conversion from signed to unsigned, it happens at | |
62 | // compiletime, so the compiler wouldn't have to warn indiscriminently, but | |
63 | // could check if the source value actually doesn't fit into the target type | |
64 | // and only warn in those cases. | |
65 | #if defined(__GNUC__) && __GNUC__ > 6 | |
66 | #pragma GCC diagnostic push | |
67 | #pragma GCC diagnostic ignored "-Wsign-conversion" | |
68 | #endif | |
69 | ||
70 | namespace gsl | |
71 | { | |
72 | ||
73 | /* | |
74 | ** begin definitions of index and bounds | |
75 | */ | |
76 | namespace details | |
77 | { | |
78 | template <typename SizeType> | |
79 | struct [[deprecated]] SizeTypeTraits | |
80 | { | |
81 | static const SizeType max_value = std::numeric_limits<SizeType>::max(); | |
82 | }; | |
83 | ||
84 | template <typename... Ts> | |
85 | class [[deprecated]] are_integral : public std::integral_constant<bool, true> | |
86 | { | |
87 | }; | |
88 | ||
89 | template <typename T, typename... Ts> | |
90 | class [[deprecated]] are_integral<T, Ts...> | |
91 | : public std::integral_constant<bool, | |
92 | std::is_integral<T>::value && are_integral<Ts...>::value> | |
93 | { | |
94 | }; | |
95 | } // namespace details | |
96 | ||
97 | template <std::size_t Rank> | |
98 | class [[deprecated]] multi_span_index final { | |
99 | static_assert(Rank > 0, "Rank must be greater than 0!"); | |
100 | ||
101 | template <std::size_t OtherRank> | |
102 | friend class multi_span_index; | |
103 | ||
104 | public: | |
105 | static const std::size_t rank = Rank; | |
106 | using value_type = std::ptrdiff_t; | |
107 | using size_type = value_type; | |
108 | using reference = std::add_lvalue_reference_t<value_type>; | |
109 | using const_reference = std::add_lvalue_reference_t<std::add_const_t<value_type>>; | |
110 | ||
111 | constexpr multi_span_index() noexcept {} | |
112 | ||
113 | constexpr multi_span_index(const value_type(&values)[Rank]) noexcept | |
114 | { | |
115 | GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute | |
116 | GSL_SUPPRESS(bounds.3) // NO-FORMAT: attribute | |
117 | std::copy(values, values + Rank, elems); | |
118 | } | |
119 | ||
120 | template <typename... Ts, typename = std::enable_if_t<(sizeof...(Ts) == Rank) && | |
121 | details::are_integral<Ts...>::value>> | |
122 | constexpr multi_span_index(Ts... ds) noexcept : elems{narrow_cast<value_type>(ds)...} | |
123 | {} | |
124 | ||
125 | constexpr multi_span_index(const multi_span_index& other) noexcept = default; | |
126 | ||
127 | constexpr multi_span_index& operator=(const multi_span_index& rhs) noexcept = default; | |
128 | ||
129 | // Preconditions: component_idx < rank | |
130 | GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute | |
131 | GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute | |
132 | constexpr reference operator[](std::size_t component_idx) | |
133 | { | |
134 | Expects(component_idx < Rank); // Component index must be less than rank | |
135 | return elems[component_idx]; | |
136 | } | |
137 | ||
138 | // Preconditions: component_idx < rank | |
139 | GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute | |
140 | GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute | |
141 | constexpr const_reference operator[](std::size_t component_idx) const | |
142 | { | |
143 | Expects(component_idx < Rank); // Component index must be less than rank | |
144 | return elems[component_idx]; | |
145 | } | |
146 | ||
147 | GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute | |
148 | GSL_SUPPRESS(bounds.3) // NO-FORMAT: attribute | |
149 | constexpr bool operator==(const multi_span_index& rhs) const | |
150 | { | |
151 | return std::equal(elems, elems + rank, rhs.elems); | |
152 | } | |
153 | ||
154 | constexpr bool operator!=(const multi_span_index& rhs) const { return !(*this == rhs); } | |
155 | ||
156 | constexpr multi_span_index operator+() const noexcept { return *this; } | |
157 | ||
158 | constexpr multi_span_index operator-() const | |
159 | { | |
160 | multi_span_index ret = *this; | |
161 | std::transform(ret, ret + rank, ret, std::negate<value_type>{}); | |
162 | return ret; | |
163 | } | |
164 | ||
165 | constexpr multi_span_index operator+(const multi_span_index& rhs) const | |
166 | { | |
167 | multi_span_index ret = *this; | |
168 | ret += rhs; | |
169 | return ret; | |
170 | } | |
171 | ||
172 | constexpr multi_span_index operator-(const multi_span_index& rhs) const | |
173 | { | |
174 | multi_span_index ret = *this; | |
175 | ret -= rhs; | |
176 | return ret; | |
177 | } | |
178 | ||
179 | constexpr multi_span_index& operator+=(const multi_span_index& rhs) | |
180 | { | |
181 | GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute | |
182 | GSL_SUPPRESS(bounds.3) // NO-FORMAT: attribute | |
183 | std::transform(elems, elems + rank, rhs.elems, elems, std::plus<value_type>{}); | |
184 | return *this; | |
185 | } | |
186 | ||
187 | constexpr multi_span_index& operator-=(const multi_span_index& rhs) | |
188 | { | |
189 | GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute | |
190 | GSL_SUPPRESS(bounds.3) // NO-FORMAT: attribute | |
191 | std::transform(elems, elems + rank, rhs.elems, elems, std::minus<value_type>{}); | |
192 | return *this; | |
193 | } | |
194 | ||
195 | constexpr multi_span_index operator*(value_type v) const | |
196 | { | |
197 | multi_span_index ret = *this; | |
198 | ret *= v; | |
199 | return ret; | |
200 | } | |
201 | ||
202 | constexpr multi_span_index operator/(value_type v) const | |
203 | { | |
204 | multi_span_index ret = *this; | |
205 | ret /= v; | |
206 | return ret; | |
207 | } | |
208 | ||
209 | friend constexpr multi_span_index operator*(value_type v, const multi_span_index& rhs) | |
210 | { | |
211 | return rhs * v; | |
212 | } | |
213 | ||
214 | constexpr multi_span_index& operator*=(value_type v) | |
215 | { | |
216 | GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute | |
217 | GSL_SUPPRESS(bounds.3) // NO-FORMAT: attribute | |
218 | std::transform(elems, elems + rank, elems, | |
219 | [v](value_type x) { return std::multiplies<value_type>{}(x, v); }); | |
220 | return *this; | |
221 | } | |
222 | ||
223 | constexpr multi_span_index& operator/=(value_type v) | |
224 | { | |
225 | GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute | |
226 | GSL_SUPPRESS(bounds.3) // NO-FORMAT: attribute | |
227 | std::transform(elems, elems + rank, elems, | |
228 | [v](value_type x) { return std::divides<value_type>{}(x, v); }); | |
229 | return *this; | |
230 | } | |
231 | ||
232 | private: | |
233 | value_type elems[Rank] = {}; | |
234 | }; | |
235 | ||
236 | #if !defined(_MSC_VER) || _MSC_VER >= 1910 | |
237 | ||
238 | struct [[deprecated]] static_bounds_dynamic_range_t | |
239 | { | |
240 | template <typename T, typename = std::enable_if_t<std::is_integral<T>::value>> | |
241 | constexpr operator T() const noexcept | |
242 | { | |
243 | return narrow_cast<T>(-1); | |
244 | } | |
245 | }; | |
246 | ||
247 | constexpr bool operator==(static_bounds_dynamic_range_t, static_bounds_dynamic_range_t) noexcept | |
248 | { | |
249 | return true; | |
250 | } | |
251 | ||
252 | constexpr bool operator!=(static_bounds_dynamic_range_t, static_bounds_dynamic_range_t) noexcept | |
253 | { | |
254 | return false; | |
255 | } | |
256 | ||
257 | template <typename T, typename = std::enable_if_t<std::is_integral<T>::value>> | |
258 | constexpr bool operator==(static_bounds_dynamic_range_t, T other) noexcept | |
259 | { | |
260 | return narrow_cast<T>(-1) == other; | |
261 | } | |
262 | ||
263 | template <typename T, typename = std::enable_if_t<std::is_integral<T>::value>> | |
264 | constexpr bool operator==(T left, static_bounds_dynamic_range_t right) noexcept | |
265 | { | |
266 | return right == left; | |
267 | } | |
268 | ||
269 | template <typename T, typename = std::enable_if_t<std::is_integral<T>::value>> | |
270 | constexpr bool operator!=(static_bounds_dynamic_range_t, T other) noexcept | |
271 | { | |
272 | return narrow_cast<T>(-1) != other; | |
273 | } | |
274 | ||
275 | template <typename T, typename = std::enable_if_t<std::is_integral<T>::value>> | |
276 | constexpr bool operator!=(T left, static_bounds_dynamic_range_t right) noexcept | |
277 | { | |
278 | return right != left; | |
279 | } | |
280 | ||
281 | constexpr static_bounds_dynamic_range_t dynamic_range{}; | |
282 | #else | |
283 | const std::ptrdiff_t dynamic_range = -1; | |
284 | #endif | |
285 | ||
286 | struct [[deprecated]] generalized_mapping_tag | |
287 | { | |
288 | }; | |
289 | struct[[deprecated]] contiguous_mapping_tag : generalized_mapping_tag{}; | |
290 | ||
291 | namespace details | |
292 | { | |
293 | ||
294 | template <std::ptrdiff_t Left, std::ptrdiff_t Right> | |
295 | struct [[deprecated]] LessThan | |
296 | { | |
297 | static const bool value = Left < Right; | |
298 | }; | |
299 | ||
300 | template <std::ptrdiff_t... Ranges> | |
301 | struct [[deprecated]] BoundsRanges { | |
302 | using size_type = std::ptrdiff_t; | |
303 | static const size_type Depth = 0; | |
304 | static const size_type DynamicNum = 0; | |
305 | static const size_type CurrentRange = 1; | |
306 | static const size_type TotalSize = 1; | |
307 | ||
308 | // TODO : following signature is for work around VS bug | |
309 | template <typename OtherRange> | |
310 | constexpr BoundsRanges(const OtherRange&, bool /* firstLevel */) | |
311 | {} | |
312 | ||
313 | constexpr BoundsRanges(const std::ptrdiff_t* const) {} | |
314 | constexpr BoundsRanges() noexcept = default; | |
315 | ||
316 | template <typename T, std::size_t Dim> | |
317 | constexpr void serialize(T&) const | |
318 | {} | |
319 | ||
320 | template <typename T, std::size_t Dim> | |
321 | constexpr size_type linearize(const T&) const | |
322 | { | |
323 | return 0; | |
324 | } | |
325 | ||
326 | template <typename T, std::size_t Dim> | |
327 | constexpr size_type contains(const T&) const | |
328 | { | |
329 | return -1; | |
330 | } | |
331 | ||
332 | constexpr size_type elementNum(std::size_t) const noexcept { return 0; } | |
333 | ||
334 | constexpr size_type totalSize() const noexcept { return TotalSize; } | |
335 | ||
336 | constexpr bool operator==(const BoundsRanges&) const noexcept { return true; } | |
337 | }; | |
338 | ||
339 | template <std::ptrdiff_t... RestRanges> | |
340 | struct[[deprecated]] BoundsRanges<dynamic_range, RestRanges...> : BoundsRanges<RestRanges...> | |
341 | { | |
342 | using Base = BoundsRanges<RestRanges...>; | |
343 | using size_type = std::ptrdiff_t; | |
344 | static const std::size_t Depth = Base::Depth + 1; | |
345 | static const std::size_t DynamicNum = Base::DynamicNum + 1; | |
346 | static const size_type CurrentRange = dynamic_range; | |
347 | static const size_type TotalSize = dynamic_range; | |
348 | ||
349 | private: | |
350 | size_type m_bound; | |
351 | ||
352 | public: | |
353 | GSL_SUPPRESS( | |
354 | f.23) // NO-FORMAT: attribute // this pointer type is cannot be assigned nullptr - issue in not_null | |
355 | GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute | |
356 | constexpr BoundsRanges(const std::ptrdiff_t* const arr) | |
357 | : Base(arr + 1), m_bound(*arr * this->Base::totalSize()) | |
358 | { | |
359 | Expects(0 <= *arr); | |
360 | } | |
361 | ||
362 | constexpr BoundsRanges() noexcept : m_bound(0) {} | |
363 | ||
364 | template <std::ptrdiff_t OtherRange, std::ptrdiff_t... RestOtherRanges> | |
365 | constexpr BoundsRanges(const BoundsRanges<OtherRange, RestOtherRanges...>& other, | |
366 | bool /* firstLevel */ = true) | |
367 | : Base(static_cast<const BoundsRanges<RestOtherRanges...>&>(other), false) | |
368 | , m_bound(other.totalSize()) | |
369 | {} | |
370 | ||
371 | template <typename T, std::size_t Dim = 0> | |
372 | constexpr void serialize(T & arr) const | |
373 | { | |
374 | arr[Dim] = elementNum(); | |
375 | this->Base::template serialize<T, Dim + 1>(arr); | |
376 | } | |
377 | ||
378 | template <typename T, std::size_t Dim = 0> | |
379 | GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute | |
380 | constexpr size_type linearize(const T& arr) const | |
381 | { | |
382 | const size_type index = this->Base::totalSize() * arr[Dim]; | |
383 | Expects(index < m_bound); | |
384 | return index + this->Base::template linearize<T, Dim + 1>(arr); | |
385 | } | |
386 | ||
387 | template <typename T, std::size_t Dim = 0> | |
388 | constexpr size_type contains(const T& arr) const | |
389 | { | |
390 | const std::ptrdiff_t last = this->Base::template contains<T, Dim + 1>(arr); | |
391 | if (last == -1) return -1; | |
392 | const std::ptrdiff_t cur = this->Base::totalSize() * arr[Dim]; | |
393 | return cur < m_bound ? cur + last : -1; | |
394 | } | |
395 | ||
396 | GSL_SUPPRESS( | |
397 | c.128) // NO-FORMAT: attribute // no pointers to BoundsRanges should be ever used | |
398 | constexpr size_type totalSize() const noexcept { return m_bound; } | |
399 | ||
400 | GSL_SUPPRESS( | |
401 | c.128) // NO-FORMAT: attribute // no pointers to BoundsRanges should be ever used | |
402 | constexpr size_type elementNum() const noexcept | |
403 | { | |
404 | return totalSize() / this->Base::totalSize(); | |
405 | } | |
406 | ||
407 | GSL_SUPPRESS( | |
408 | c.128) // NO-FORMAT: attribute // no pointers to BoundsRanges should be ever used | |
409 | constexpr size_type elementNum(std::size_t dim) const noexcept | |
410 | { | |
411 | if (dim > 0) | |
412 | return this->Base::elementNum(dim - 1); | |
413 | else | |
414 | return elementNum(); | |
415 | } | |
416 | ||
417 | constexpr bool operator==(const BoundsRanges& rhs) const noexcept | |
418 | { | |
419 | return m_bound == rhs.m_bound && | |
420 | static_cast<const Base&>(*this) == static_cast<const Base&>(rhs); | |
421 | } | |
422 | }; | |
423 | ||
424 | template <std::ptrdiff_t CurRange, std::ptrdiff_t... RestRanges> | |
425 | struct[[deprecated]] BoundsRanges<CurRange, RestRanges...> : BoundsRanges<RestRanges...> | |
426 | { | |
427 | using Base = BoundsRanges<RestRanges...>; | |
428 | using size_type = std::ptrdiff_t; | |
429 | static const std::size_t Depth = Base::Depth + 1; | |
430 | static const std::size_t DynamicNum = Base::DynamicNum; | |
431 | static const size_type CurrentRange = CurRange; | |
432 | static const size_type TotalSize = | |
433 | Base::TotalSize == dynamic_range ? dynamic_range : CurrentRange * Base::TotalSize; | |
434 | ||
435 | constexpr BoundsRanges(const std::ptrdiff_t* const arr) : Base(arr) {} | |
436 | constexpr BoundsRanges() = default; | |
437 | ||
438 | template <std::ptrdiff_t OtherRange, std::ptrdiff_t... RestOtherRanges> | |
439 | constexpr BoundsRanges(const BoundsRanges<OtherRange, RestOtherRanges...>& other, | |
440 | bool firstLevel = true) | |
441 | : Base(static_cast<const BoundsRanges<RestOtherRanges...>&>(other), false) | |
442 | { | |
443 | GSL_SUPPRESS(type.4) // NO-FORMAT: attribute // TODO: false positive | |
444 | (void) firstLevel; | |
445 | } | |
446 | ||
447 | template <typename T, std::size_t Dim = 0> | |
448 | constexpr void serialize(T & arr) const | |
449 | { | |
450 | arr[Dim] = elementNum(); | |
451 | this->Base::template serialize<T, Dim + 1>(arr); | |
452 | } | |
453 | ||
454 | template <typename T, std::size_t Dim = 0> | |
455 | constexpr size_type linearize(const T& arr) const | |
456 | { | |
457 | GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute | |
458 | Expects(arr[Dim] >= 0 && arr[Dim] < CurrentRange); // Index is out of range | |
459 | GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute | |
460 | const std::ptrdiff_t d = arr[Dim]; | |
461 | return this->Base::totalSize() * d + this->Base::template linearize<T, Dim + 1>(arr); | |
462 | } | |
463 | ||
464 | template <typename T, std::size_t Dim = 0> | |
465 | constexpr size_type contains(const T& arr) const | |
466 | { | |
467 | if (arr[Dim] >= CurrentRange) return -1; | |
468 | const size_type last = this->Base::template contains<T, Dim + 1>(arr); | |
469 | if (last == -1) return -1; | |
470 | return this->Base::totalSize() * arr[Dim] + last; | |
471 | } | |
472 | ||
473 | GSL_SUPPRESS( | |
474 | c.128) // NO-FORMAT: attribute // no pointers to BoundsRanges should be ever used | |
475 | constexpr size_type totalSize() const noexcept | |
476 | { | |
477 | return CurrentRange * this->Base::totalSize(); | |
478 | } | |
479 | ||
480 | GSL_SUPPRESS( | |
481 | c.128) // NO-FORMAT: attribute // no pointers to BoundsRanges should be ever used | |
482 | constexpr size_type elementNum() const noexcept { return CurrentRange; } | |
483 | ||
484 | GSL_SUPPRESS( | |
485 | c.128) // NO-FORMAT: attribute // no pointers to BoundsRanges should be ever used | |
486 | constexpr size_type elementNum(std::size_t dim) const noexcept | |
487 | { | |
488 | if (dim > 0) | |
489 | return this->Base::elementNum(dim - 1); | |
490 | else | |
491 | return elementNum(); | |
492 | } | |
493 | ||
494 | constexpr bool operator==(const BoundsRanges& rhs) const noexcept | |
495 | { | |
496 | return static_cast<const Base&>(*this) == static_cast<const Base&>(rhs); | |
497 | } | |
498 | }; | |
499 | ||
500 | template <typename SourceType, typename TargetType> | |
501 | struct[[deprecated]] BoundsRangeConvertible | |
502 | : public std::integral_constant<bool, (SourceType::TotalSize >= TargetType::TotalSize || | |
503 | TargetType::TotalSize == dynamic_range || | |
504 | SourceType::TotalSize == dynamic_range || | |
505 | TargetType::TotalSize == 0)>{}; | |
506 | ||
507 | template <typename TypeChain> | |
508 | struct [[deprecated]] TypeListIndexer { | |
509 | const TypeChain& obj_; | |
510 | constexpr TypeListIndexer(const TypeChain& obj) : obj_(obj) {} | |
511 | ||
512 | template <std::size_t N> | |
513 | constexpr const TypeChain& getObj(std::true_type) | |
514 | { | |
515 | return obj_; | |
516 | } | |
517 | ||
518 | template <std::size_t N, typename MyChain = TypeChain, | |
519 | typename MyBase = typename MyChain::Base> | |
520 | constexpr auto getObj(std::false_type) | |
521 | ->decltype(TypeListIndexer<MyBase>(static_cast<const MyBase&>(obj_)).template get<N>()) | |
522 | { | |
523 | return TypeListIndexer<MyBase>(static_cast<const MyBase&>(obj_)).template get<N>(); | |
524 | } | |
525 | ||
526 | template <std::size_t N> | |
527 | constexpr auto get()->decltype(getObj<N - 1>(std::integral_constant<bool, N == 0>())) | |
528 | { | |
529 | return getObj<N - 1>(std::integral_constant<bool, N == 0>()); | |
530 | } | |
531 | }; | |
532 | ||
533 | template <typename TypeChain> | |
534 | constexpr TypeListIndexer<TypeChain> createTypeListIndexer(const TypeChain& obj) | |
535 | { | |
536 | return TypeListIndexer<TypeChain>(obj); | |
537 | } | |
538 | ||
539 | template <std::size_t Rank, bool Enabled = (Rank > 1), | |
540 | typename Ret = std::enable_if_t<Enabled, multi_span_index<Rank - 1>>> | |
541 | constexpr Ret shift_left(const multi_span_index<Rank>& other) noexcept | |
542 | { | |
543 | Ret ret{}; | |
544 | for (std::size_t i = 0; i < Rank - 1; ++i) | |
545 | { | |
546 | GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute | |
547 | ret[i] = other[i + 1]; | |
548 | } | |
549 | return ret; | |
550 | } | |
551 | } // namespace details | |
552 | ||
553 | template <typename IndexType> | |
554 | class [[deprecated]] bounds_iterator; | |
555 | ||
556 | template <std::ptrdiff_t... Ranges> | |
557 | class [[deprecated]] static_bounds { | |
558 | public: | |
559 | static_bounds(const details::BoundsRanges<Ranges...>&) {} | |
560 | }; | |
561 | ||
562 | template <std::ptrdiff_t FirstRange, std::ptrdiff_t... RestRanges> | |
563 | class[[deprecated]] static_bounds<FirstRange, RestRanges...> | |
564 | { | |
565 | using MyRanges = details::BoundsRanges<FirstRange, RestRanges...>; | |
566 | ||
567 | MyRanges m_ranges; | |
568 | constexpr static_bounds(const MyRanges& range) noexcept : m_ranges(range) {} | |
569 | ||
570 | template <std::ptrdiff_t... OtherRanges> | |
571 | friend class static_bounds; | |
572 | ||
573 | public: | |
574 | static const std::size_t rank = MyRanges::Depth; | |
575 | static const std::size_t dynamic_rank = MyRanges::DynamicNum; | |
576 | static const std::ptrdiff_t static_size = MyRanges::TotalSize; | |
577 | ||
578 | using size_type = std::ptrdiff_t; | |
579 | using index_type = multi_span_index<rank>; | |
580 | using const_index_type = std::add_const_t<index_type>; | |
581 | using iterator = bounds_iterator<const_index_type>; | |
582 | using const_iterator = bounds_iterator<const_index_type>; | |
583 | using difference_type = std::ptrdiff_t; | |
584 | using sliced_type = static_bounds<RestRanges...>; | |
585 | using mapping_type = contiguous_mapping_tag; | |
586 | ||
587 | constexpr static_bounds() /*noexcept*/ = default; | |
588 | ||
589 | template <typename SourceType, typename TargetType, std::size_t Rank> | |
590 | struct BoundsRangeConvertible2; | |
591 | ||
592 | template <std::size_t Rank, typename SourceType, typename TargetType, | |
593 | typename Ret = BoundsRangeConvertible2<typename SourceType::Base, | |
594 | typename TargetType::Base, Rank>> | |
595 | static auto helpBoundsRangeConvertible(SourceType, TargetType, std::true_type)->Ret; | |
596 | ||
597 | template <std::size_t Rank, typename SourceType, typename TargetType> | |
598 | static auto helpBoundsRangeConvertible(SourceType, TargetType, ...)->std::false_type; | |
599 | ||
600 | template <typename SourceType, typename TargetType, std::size_t Rank> | |
601 | struct BoundsRangeConvertible2 | |
602 | : decltype(helpBoundsRangeConvertible<Rank - 1>( | |
603 | SourceType(), TargetType(), | |
604 | std::integral_constant<bool, | |
605 | SourceType::Depth == TargetType::Depth && | |
606 | (SourceType::CurrentRange == TargetType::CurrentRange || | |
607 | TargetType::CurrentRange == dynamic_range || | |
608 | SourceType::CurrentRange == dynamic_range)>())) | |
609 | { | |
610 | }; | |
611 | ||
612 | template <typename SourceType, typename TargetType> | |
613 | struct BoundsRangeConvertible2<SourceType, TargetType, 0> : std::true_type | |
614 | { | |
615 | }; | |
616 | ||
617 | template <typename SourceType, typename TargetType, std::ptrdiff_t Rank = TargetType::Depth> | |
618 | struct BoundsRangeConvertible | |
619 | : decltype(helpBoundsRangeConvertible<Rank - 1>( | |
620 | SourceType(), TargetType(), | |
621 | std::integral_constant<bool, | |
622 | SourceType::Depth == TargetType::Depth && | |
623 | (!details::LessThan<SourceType::CurrentRange, | |
624 | TargetType::CurrentRange>::value || | |
625 | TargetType::CurrentRange == dynamic_range || | |
626 | SourceType::CurrentRange == dynamic_range)>())) | |
627 | { | |
628 | }; | |
629 | ||
630 | template <typename SourceType, typename TargetType> | |
631 | struct BoundsRangeConvertible<SourceType, TargetType, 0> : std::true_type | |
632 | { | |
633 | }; | |
634 | ||
635 | template <std::ptrdiff_t... Ranges, | |
636 | typename = std::enable_if_t<details::BoundsRangeConvertible< | |
637 | details::BoundsRanges<Ranges...>, | |
638 | details::BoundsRanges<FirstRange, RestRanges...>>::value>> | |
639 | constexpr static_bounds(const static_bounds<Ranges...>& other) : m_ranges(other.m_ranges) | |
640 | { | |
641 | Expects((MyRanges::DynamicNum == 0 && details::BoundsRanges<Ranges...>::DynamicNum == 0) || | |
642 | MyRanges::DynamicNum > 0 || other.m_ranges.totalSize() >= m_ranges.totalSize()); | |
643 | } | |
644 | ||
645 | constexpr static_bounds(std::initializer_list<size_type> il) : m_ranges(il.begin()) | |
646 | { | |
647 | // Size of the initializer list must match the rank of the array | |
648 | Expects((MyRanges::DynamicNum == 0 && il.size() == 1 && *il.begin() == static_size) || | |
649 | MyRanges::DynamicNum == il.size()); | |
650 | // Size of the range must be less than the max element of the size type | |
651 | Expects(m_ranges.totalSize() <= PTRDIFF_MAX); | |
652 | } | |
653 | ||
654 | constexpr sliced_type slice() const noexcept | |
655 | { | |
656 | return sliced_type{static_cast<const details::BoundsRanges<RestRanges...>&>(m_ranges)}; | |
657 | } | |
658 | ||
659 | constexpr size_type stride() const noexcept { return rank > 1 ? slice().size() : 1; } | |
660 | ||
661 | constexpr size_type size() const noexcept { return m_ranges.totalSize(); } | |
662 | ||
663 | constexpr size_type total_size() const noexcept { return m_ranges.totalSize(); } | |
664 | ||
665 | constexpr size_type linearize(const index_type& idx) const { return m_ranges.linearize(idx); } | |
666 | ||
667 | constexpr bool contains(const index_type& idx) const noexcept | |
668 | { | |
669 | return m_ranges.contains(idx) != -1; | |
670 | } | |
671 | ||
672 | constexpr size_type operator[](std::size_t idx) const noexcept | |
673 | { | |
674 | return m_ranges.elementNum(idx); | |
675 | } | |
676 | ||
677 | template <std::size_t Dim = 0> | |
678 | constexpr size_type extent() const noexcept | |
679 | { | |
680 | static_assert(Dim < rank, | |
681 | "dimension should be less than rank (dimension count starts from 0)"); | |
682 | return details::createTypeListIndexer(m_ranges).template get<Dim>().elementNum(); | |
683 | } | |
684 | ||
685 | template <typename IntType> | |
686 | constexpr size_type extent(IntType dim) const | |
687 | { | |
688 | static_assert(std::is_integral<IntType>::value, | |
689 | "Dimension parameter must be supplied as an integral type."); | |
690 | auto real_dim = narrow_cast<std::size_t>(dim); | |
691 | Expects(real_dim < rank); | |
692 | ||
693 | return m_ranges.elementNum(real_dim); | |
694 | } | |
695 | ||
696 | constexpr index_type index_bounds() const noexcept | |
697 | { | |
698 | size_type extents[rank] = {}; | |
699 | m_ranges.serialize(extents); | |
700 | return {extents}; | |
701 | } | |
702 | ||
703 | template <std::ptrdiff_t... Ranges> | |
704 | constexpr bool operator==(const static_bounds<Ranges...>& rhs) const noexcept | |
705 | { | |
706 | return this->size() == rhs.size(); | |
707 | } | |
708 | ||
709 | template <std::ptrdiff_t... Ranges> | |
710 | constexpr bool operator!=(const static_bounds<Ranges...>& rhs) const noexcept | |
711 | { | |
712 | return !(*this == rhs); | |
713 | } | |
714 | ||
715 | constexpr const_iterator begin() const noexcept { return const_iterator(*this, index_type{}); } | |
716 | ||
717 | constexpr const_iterator end() const noexcept | |
718 | { | |
719 | return const_iterator(*this, this->index_bounds()); | |
720 | } | |
721 | }; | |
722 | ||
723 | template <std::size_t Rank> | |
724 | class [[deprecated]] strided_bounds { | |
725 | template <std::size_t OtherRank> | |
726 | friend class strided_bounds; | |
727 | ||
728 | public: | |
729 | static const std::size_t rank = Rank; | |
730 | using value_type = std::ptrdiff_t; | |
731 | using reference = std::add_lvalue_reference_t<value_type>; | |
732 | using const_reference = std::add_const_t<reference>; | |
733 | using size_type = value_type; | |
734 | using difference_type = value_type; | |
735 | using index_type = multi_span_index<rank>; | |
736 | using const_index_type = std::add_const_t<index_type>; | |
737 | using iterator = bounds_iterator<const_index_type>; | |
738 | using const_iterator = bounds_iterator<const_index_type>; | |
739 | static const value_type dynamic_rank = rank; | |
740 | static const value_type static_size = dynamic_range; | |
741 | using sliced_type = std::conditional_t<rank != 0, strided_bounds<rank - 1>, void>; | |
742 | using mapping_type = generalized_mapping_tag; | |
743 | ||
744 | constexpr strided_bounds(const strided_bounds&) noexcept = default; | |
745 | ||
746 | constexpr strided_bounds& operator=(const strided_bounds&) noexcept = default; | |
747 | ||
748 | constexpr strided_bounds(const value_type(&values)[rank], index_type strides) | |
749 | : m_extents(values), m_strides(std::move(strides)) | |
750 | {} | |
751 | ||
752 | constexpr strided_bounds(const index_type& extents, const index_type& strides) noexcept | |
753 | : m_extents(extents), m_strides(strides) | |
754 | {} | |
755 | ||
756 | constexpr index_type strides() const noexcept { return m_strides; } | |
757 | ||
758 | GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute | |
759 | constexpr size_type total_size() const noexcept | |
760 | { | |
761 | size_type ret = 0; | |
762 | for (std::size_t i = 0; i < rank; ++i) { ret += (m_extents[i] - 1) * m_strides[i]; } | |
763 | return ret + 1; | |
764 | } | |
765 | ||
766 | GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute | |
767 | constexpr size_type size() const noexcept | |
768 | { | |
769 | size_type ret = 1; | |
770 | for (std::size_t i = 0; i < rank; ++i) { ret *= m_extents[i]; } | |
771 | return ret; | |
772 | } | |
773 | ||
774 | constexpr bool contains(const index_type& idx) const noexcept | |
775 | { | |
776 | for (std::size_t i = 0; i < rank; ++i) | |
777 | { | |
778 | if (idx[i] < 0 || idx[i] >= m_extents[i]) return false; | |
779 | } | |
780 | return true; | |
781 | } | |
782 | ||
783 | GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute | |
784 | constexpr size_type linearize(const index_type& idx) const | |
785 | { | |
786 | size_type ret = 0; | |
787 | for (std::size_t i = 0; i < rank; i++) | |
788 | { | |
789 | Expects(idx[i] < m_extents[i]); // index is out of bounds of the array | |
790 | ret += idx[i] * m_strides[i]; | |
791 | } | |
792 | return ret; | |
793 | } | |
794 | ||
795 | GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute | |
796 | constexpr size_type stride() const noexcept { return m_strides[0]; } | |
797 | ||
798 | template <bool Enabled = (rank > 1), typename Ret = std::enable_if_t<Enabled, sliced_type>> | |
799 | constexpr sliced_type slice() const | |
800 | { | |
801 | return {details::shift_left(m_extents), details::shift_left(m_strides)}; | |
802 | } | |
803 | ||
804 | template <std::size_t Dim = 0> | |
805 | ||
806 | GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute | |
807 | constexpr size_type extent() const noexcept | |
808 | { | |
809 | static_assert(Dim < Rank, | |
810 | "dimension should be less than rank (dimension count starts from 0)"); | |
811 | return m_extents[Dim]; | |
812 | } | |
813 | ||
814 | constexpr index_type index_bounds() const noexcept { return m_extents; } | |
815 | ||
816 | constexpr const_iterator begin() const noexcept { return const_iterator{*this, index_type{}}; } | |
817 | ||
818 | constexpr const_iterator end() const noexcept { return const_iterator{*this, index_bounds()}; } | |
819 | ||
820 | private: | |
821 | index_type m_extents; | |
822 | index_type m_strides; | |
823 | }; | |
824 | ||
825 | template <typename T> | |
826 | struct[[deprecated]] is_bounds : std::integral_constant<bool, false>{}; | |
827 | template <std::ptrdiff_t... Ranges> | |
828 | struct[[deprecated]] is_bounds<static_bounds<Ranges...>> : std::integral_constant<bool, true>{}; | |
829 | template <std::size_t Rank> | |
830 | struct[[deprecated]] is_bounds<strided_bounds<Rank>> : std::integral_constant<bool, true>{}; | |
831 | ||
832 | template <typename IndexType> | |
833 | class [[deprecated]] bounds_iterator { | |
834 | public: | |
835 | static const std::size_t rank = IndexType::rank; | |
836 | using iterator_category = std::random_access_iterator_tag; | |
837 | using value_type = IndexType; | |
838 | using difference_type = std::ptrdiff_t; | |
839 | using pointer = value_type*; | |
840 | using reference = value_type&; | |
841 | using index_type = value_type; | |
842 | using index_size_type = typename IndexType::value_type; | |
843 | template <typename Bounds> | |
844 | explicit bounds_iterator(const Bounds& bnd, value_type curr) noexcept | |
845 | : boundary_(bnd.index_bounds()), curr_(std::move(curr)) | |
846 | { | |
847 | static_assert(is_bounds<Bounds>::value, "Bounds type must be provided"); | |
848 | } | |
849 | ||
850 | constexpr reference operator*() const noexcept { return curr_; } | |
851 | ||
852 | constexpr pointer operator->() const noexcept { return &curr_; } | |
853 | ||
854 | GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute | |
855 | GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute | |
856 | constexpr bounds_iterator& operator++() noexcept | |
857 | ||
858 | { | |
859 | for (std::size_t i = rank; i-- > 0;) | |
860 | { | |
861 | if (curr_[i] < boundary_[i] - 1) | |
862 | { | |
863 | curr_[i]++; | |
864 | return *this; | |
865 | } | |
866 | curr_[i] = 0; | |
867 | } | |
868 | // If we're here we've wrapped over - set to past-the-end. | |
869 | curr_ = boundary_; | |
870 | return *this; | |
871 | } | |
872 | ||
873 | constexpr bounds_iterator operator++(int) noexcept | |
874 | { | |
875 | auto ret = *this; | |
876 | ++(*this); | |
877 | return ret; | |
878 | } | |
879 | ||
880 | GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute | |
881 | constexpr bounds_iterator& operator--() | |
882 | { | |
883 | if (!less(curr_, boundary_)) | |
884 | { | |
885 | // if at the past-the-end, set to last element | |
886 | for (std::size_t i = 0; i < rank; ++i) { curr_[i] = boundary_[i] - 1; } | |
887 | return *this; | |
888 | } | |
889 | for (std::size_t i = rank; i-- > 0;) | |
890 | { | |
891 | if (curr_[i] >= 1) | |
892 | { | |
893 | curr_[i]--; | |
894 | return *this; | |
895 | } | |
896 | curr_[i] = boundary_[i] - 1; | |
897 | } | |
898 | // If we're here the preconditions were violated | |
899 | // "pre: there exists s such that r == ++s" | |
900 | Expects(false); | |
901 | return *this; | |
902 | } | |
903 | ||
904 | constexpr bounds_iterator operator--(int) noexcept | |
905 | { | |
906 | auto ret = *this; | |
907 | --(*this); | |
908 | return ret; | |
909 | } | |
910 | ||
911 | constexpr bounds_iterator operator+(difference_type n) const noexcept | |
912 | { | |
913 | bounds_iterator ret{*this}; | |
914 | return ret += n; | |
915 | } | |
916 | ||
917 | GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute | |
918 | constexpr bounds_iterator& operator+=(difference_type n) | |
919 | { | |
920 | auto linear_idx = linearize(curr_) + n; | |
921 | std::remove_const_t<value_type> stride = 0; | |
922 | stride[rank - 1] = 1; | |
923 | for (std::size_t i = rank - 1; i-- > 0;) { stride[i] = stride[i + 1] * boundary_[i + 1]; } | |
924 | for (std::size_t i = 0; i < rank; ++i) | |
925 | { | |
926 | curr_[i] = linear_idx / stride[i]; | |
927 | linear_idx = linear_idx % stride[i]; | |
928 | } | |
929 | // index is out of bounds of the array | |
930 | Expects(!less(curr_, index_type{}) && !less(boundary_, curr_)); | |
931 | return *this; | |
932 | } | |
933 | ||
934 | constexpr bounds_iterator operator-(difference_type n) const noexcept | |
935 | { | |
936 | bounds_iterator ret{*this}; | |
937 | return ret -= n; | |
938 | } | |
939 | ||
940 | constexpr bounds_iterator& operator-=(difference_type n) noexcept { return *this += -n; } | |
941 | ||
942 | constexpr difference_type operator-(const bounds_iterator& rhs) const noexcept | |
943 | { | |
944 | return linearize(curr_) - linearize(rhs.curr_); | |
945 | } | |
946 | ||
947 | constexpr value_type operator[](difference_type n) const noexcept { return *(*this + n); } | |
948 | ||
949 | constexpr bool operator==(const bounds_iterator& rhs) const noexcept | |
950 | { | |
951 | return curr_ == rhs.curr_; | |
952 | } | |
953 | ||
954 | constexpr bool operator!=(const bounds_iterator& rhs) const noexcept { return !(*this == rhs); } | |
955 | ||
956 | constexpr bool operator<(const bounds_iterator& rhs) const noexcept | |
957 | { | |
958 | return less(curr_, rhs.curr_); | |
959 | } | |
960 | ||
961 | constexpr bool operator<=(const bounds_iterator& rhs) const noexcept { return !(rhs < *this); } | |
962 | ||
963 | constexpr bool operator>(const bounds_iterator& rhs) const noexcept { return rhs < *this; } | |
964 | ||
965 | constexpr bool operator>=(const bounds_iterator& rhs) const noexcept { return !(rhs > *this); } | |
966 | ||
967 | void swap(bounds_iterator & rhs) noexcept | |
968 | { | |
969 | std::swap(boundary_, rhs.boundary_); | |
970 | std::swap(curr_, rhs.curr_); | |
971 | } | |
972 | ||
973 | private: | |
974 | GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute | |
975 | constexpr bool less(index_type & one, index_type & other) const noexcept | |
976 | { | |
977 | for (std::size_t i = 0; i < rank; ++i) | |
978 | { | |
979 | if (one[i] < other[i]) return true; | |
980 | } | |
981 | return false; | |
982 | } | |
983 | ||
984 | GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute | |
985 | constexpr index_size_type linearize(const value_type& idx) const noexcept | |
986 | { | |
987 | // TODO: Smarter impl. | |
988 | // Check if past-the-end | |
989 | index_size_type multiplier = 1; | |
990 | index_size_type res = 0; | |
991 | if (!less(idx, boundary_)) | |
992 | { | |
993 | res = 1; | |
994 | for (std::size_t i = rank; i-- > 0;) | |
995 | { | |
996 | res += (idx[i] - 1) * multiplier; | |
997 | multiplier *= boundary_[i]; | |
998 | } | |
999 | } | |
1000 | else | |
1001 | { | |
1002 | for (std::size_t i = rank; i-- > 0;) | |
1003 | { | |
1004 | res += idx[i] * multiplier; | |
1005 | multiplier *= boundary_[i]; | |
1006 | } | |
1007 | } | |
1008 | return res; | |
1009 | } | |
1010 | ||
1011 | value_type boundary_; | |
1012 | std::remove_const_t<value_type> curr_; | |
1013 | }; | |
1014 | ||
1015 | template <typename IndexType> | |
1016 | bounds_iterator<IndexType> operator+(typename bounds_iterator<IndexType>::difference_type n, | |
1017 | const bounds_iterator<IndexType>& rhs) noexcept | |
1018 | { | |
1019 | return rhs + n; | |
1020 | } | |
1021 | ||
1022 | namespace details | |
1023 | { | |
1024 | template <typename Bounds> | |
1025 | constexpr std::enable_if_t< | |
1026 | std::is_same<typename Bounds::mapping_type, generalized_mapping_tag>::value, | |
1027 | typename Bounds::index_type> | |
1028 | make_stride(const Bounds& bnd) noexcept | |
1029 | { | |
1030 | return bnd.strides(); | |
1031 | } | |
1032 | ||
1033 | // Make a stride vector from bounds, assuming contiguous memory. | |
1034 | template <typename Bounds> | |
1035 | constexpr std::enable_if_t< | |
1036 | std::is_same<typename Bounds::mapping_type, contiguous_mapping_tag>::value, | |
1037 | typename Bounds::index_type> | |
1038 | make_stride(const Bounds& bnd) noexcept | |
1039 | { | |
1040 | auto extents = bnd.index_bounds(); | |
1041 | typename Bounds::size_type stride[Bounds::rank] = {}; | |
1042 | ||
1043 | stride[Bounds::rank - 1] = 1; | |
1044 | for (std::size_t i = 1; i < Bounds::rank; ++i) | |
1045 | { | |
1046 | GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute | |
1047 | GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute | |
1048 | stride[Bounds::rank - i - 1] = stride[Bounds::rank - i] * extents[Bounds::rank - i]; | |
1049 | } | |
1050 | return {stride}; | |
1051 | } | |
1052 | ||
1053 | template <typename BoundsSrc, typename BoundsDest> | |
1054 | void verifyBoundsReshape(const BoundsSrc& src, const BoundsDest& dest) | |
1055 | { | |
1056 | static_assert(is_bounds<BoundsSrc>::value && is_bounds<BoundsDest>::value, | |
1057 | "The src type and dest type must be bounds"); | |
1058 | static_assert(std::is_same<typename BoundsSrc::mapping_type, contiguous_mapping_tag>::value, | |
1059 | "The source type must be a contiguous bounds"); | |
1060 | static_assert(BoundsDest::static_size == dynamic_range || | |
1061 | BoundsSrc::static_size == dynamic_range || | |
1062 | BoundsDest::static_size == BoundsSrc::static_size, | |
1063 | "The source bounds must have same size as dest bounds"); | |
1064 | Expects(src.size() == dest.size()); | |
1065 | } | |
1066 | ||
1067 | } // namespace details | |
1068 | ||
1069 | template <typename Span> | |
1070 | class [[deprecated]] contiguous_span_iterator; | |
1071 | template <typename Span> | |
1072 | class [[deprecated]] general_span_iterator; | |
1073 | ||
1074 | template <std::ptrdiff_t DimSize = dynamic_range> | |
1075 | struct [[deprecated]] dim_t | |
1076 | { | |
1077 | static const std::ptrdiff_t value = DimSize; | |
1078 | }; | |
1079 | template <> | |
1080 | struct [[deprecated]] dim_t<dynamic_range> | |
1081 | { | |
1082 | static const std::ptrdiff_t value = dynamic_range; | |
1083 | const std::ptrdiff_t dvalue; | |
1084 | constexpr dim_t(std::ptrdiff_t size) noexcept : dvalue(size) {} | |
1085 | }; | |
1086 | ||
1087 | template <std::ptrdiff_t N, class = std::enable_if_t<(N >= 0)>> | |
1088 | constexpr dim_t<N> dim() noexcept | |
1089 | { | |
1090 | return dim_t<N>(); | |
1091 | } | |
1092 | ||
1093 | template <std::ptrdiff_t N = dynamic_range, class = std::enable_if_t<N == dynamic_range>> | |
1094 | constexpr dim_t<N> dim(std::ptrdiff_t n) noexcept | |
1095 | { | |
1096 | return dim_t<>(n); | |
1097 | } | |
1098 | ||
1099 | template <typename ValueType, std::ptrdiff_t FirstDimension = dynamic_range, | |
1100 | std::ptrdiff_t... RestDimensions> | |
1101 | class [[deprecated("gsl::multi_span is deprecated because it is not in the C++ Core Guidelines")]] multi_span; | |
1102 | ||
1103 | template <typename ValueType, std::size_t Rank> | |
1104 | class [[deprecated("gsl::strided_span is deprecated because it is not in the C++ Core Guidelines")]] strided_span; | |
1105 | ||
1106 | namespace details | |
1107 | { | |
1108 | template <typename T, typename = std::true_type> | |
1109 | struct [[deprecated]] SpanTypeTraits | |
1110 | { | |
1111 | using value_type = T; | |
1112 | using size_type = std::size_t; | |
1113 | }; | |
1114 | ||
1115 | template <typename Traits> | |
1116 | struct [[deprecated]] SpanTypeTraits< | |
1117 | Traits, typename std::is_reference<typename Traits::span_traits&>::type> | |
1118 | { | |
1119 | using value_type = typename Traits::span_traits::value_type; | |
1120 | using size_type = typename Traits::span_traits::size_type; | |
1121 | }; | |
1122 | ||
1123 | template <typename T, std::ptrdiff_t... Ranks> | |
1124 | struct [[deprecated]] SpanArrayTraits | |
1125 | { | |
1126 | using type = multi_span<T, Ranks...>; | |
1127 | using value_type = T; | |
1128 | using bounds_type = static_bounds<Ranks...>; | |
1129 | using pointer = T*; | |
1130 | using reference = T&; | |
1131 | }; | |
1132 | template <typename T, std::ptrdiff_t N, std::ptrdiff_t... Ranks> | |
1133 | struct [[deprecated]] SpanArrayTraits<T[N], Ranks...> : SpanArrayTraits<T, Ranks..., N> | |
1134 | { | |
1135 | }; | |
1136 | ||
1137 | template <typename BoundsType> | |
1138 | BoundsType newBoundsHelperImpl(std::ptrdiff_t totalSize, std::true_type) // dynamic size | |
1139 | { | |
1140 | Expects(totalSize >= 0 && totalSize <= PTRDIFF_MAX); | |
1141 | return BoundsType{totalSize}; | |
1142 | } | |
1143 | template <typename BoundsType> | |
1144 | BoundsType newBoundsHelperImpl(std::ptrdiff_t totalSize, std::false_type) // static size | |
1145 | { | |
1146 | Expects(BoundsType::static_size <= totalSize); | |
1147 | return {}; | |
1148 | } | |
1149 | template <typename BoundsType> | |
1150 | BoundsType newBoundsHelper(std::ptrdiff_t totalSize) | |
1151 | { | |
1152 | static_assert(BoundsType::dynamic_rank <= 1, "dynamic rank must less or equal to 1"); | |
1153 | return newBoundsHelperImpl<BoundsType>( | |
1154 | totalSize, std::integral_constant<bool, BoundsType::dynamic_rank == 1>()); | |
1155 | } | |
1156 | ||
1157 | struct [[deprecated]] Sep | |
1158 | { | |
1159 | }; | |
1160 | ||
1161 | template <typename T, typename... Args> | |
1162 | T static_as_multi_span_helper(Sep, Args... args) | |
1163 | { | |
1164 | return T{narrow_cast<typename T::size_type>(args)...}; | |
1165 | } | |
1166 | template <typename T, typename Arg, typename... Args> | |
1167 | std::enable_if_t< | |
1168 | !std::is_same<Arg, dim_t<dynamic_range>>::value && !std::is_same<Arg, Sep>::value, T> | |
1169 | static_as_multi_span_helper(Arg, Args... args) | |
1170 | { | |
1171 | return static_as_multi_span_helper<T>(args...); | |
1172 | } | |
1173 | template <typename T, typename... Args> | |
1174 | T static_as_multi_span_helper(dim_t<dynamic_range> val, Args... args) | |
1175 | { | |
1176 | return static_as_multi_span_helper<T>(args..., val.dvalue); | |
1177 | } | |
1178 | ||
1179 | template <typename... Dimensions> | |
1180 | struct [[deprecated]] static_as_multi_span_static_bounds_helper | |
1181 | { | |
1182 | using type = static_bounds<(Dimensions::value)...>; | |
1183 | }; | |
1184 | ||
1185 | template <typename T> | |
1186 | struct [[deprecated]] is_multi_span_oracle : std::false_type | |
1187 | { | |
1188 | }; | |
1189 | ||
1190 | template <typename ValueType, std::ptrdiff_t FirstDimension, std::ptrdiff_t... RestDimensions> | |
1191 | struct [[deprecated]] is_multi_span_oracle<multi_span<ValueType, FirstDimension, RestDimensions...>> | |
1192 | : std::true_type | |
1193 | { | |
1194 | }; | |
1195 | ||
1196 | template <typename ValueType, std::ptrdiff_t Rank> | |
1197 | struct [[deprecated]] is_multi_span_oracle<strided_span<ValueType, Rank>> : std::true_type | |
1198 | { | |
1199 | }; | |
1200 | ||
1201 | template <typename T> | |
1202 | struct [[deprecated]] is_multi_span : is_multi_span_oracle<std::remove_cv_t<T>> | |
1203 | { | |
1204 | }; | |
1205 | } // namespace details | |
1206 | ||
1207 | template <typename ValueType, std::ptrdiff_t FirstDimension, std::ptrdiff_t... RestDimensions> | |
1208 | class [[deprecated("gsl::multi_span is deprecated because it is not in the C++ Core Guidelines")]] multi_span { | |
1209 | // TODO do we still need this? | |
1210 | template <typename ValueType2, std::ptrdiff_t FirstDimension2, | |
1211 | std::ptrdiff_t... RestDimensions2> | |
1212 | friend class multi_span; | |
1213 | ||
1214 | public: | |
1215 | using bounds_type = static_bounds<FirstDimension, RestDimensions...>; | |
1216 | static const std::size_t Rank = bounds_type::rank; | |
1217 | using size_type = typename bounds_type::size_type; | |
1218 | using index_type = typename bounds_type::index_type; | |
1219 | using value_type = ValueType; | |
1220 | using const_value_type = std::add_const_t<value_type>; | |
1221 | using pointer = std::add_pointer_t<value_type>; | |
1222 | using reference = std::add_lvalue_reference_t<value_type>; | |
1223 | using iterator = contiguous_span_iterator<multi_span>; | |
1224 | using const_span = multi_span<const_value_type, FirstDimension, RestDimensions...>; | |
1225 | using const_iterator = contiguous_span_iterator<const_span>; | |
1226 | using reverse_iterator = std::reverse_iterator<iterator>; | |
1227 | using const_reverse_iterator = std::reverse_iterator<const_iterator>; | |
1228 | using sliced_type = | |
1229 | std::conditional_t<Rank == 1, value_type, multi_span<value_type, RestDimensions...>>; | |
1230 | ||
1231 | private: | |
1232 | pointer data_; | |
1233 | bounds_type bounds_; | |
1234 | ||
1235 | friend iterator; | |
1236 | friend const_iterator; | |
1237 | ||
1238 | public: | |
1239 | // default constructor - same as constructing from nullptr_t | |
1240 | GSL_SUPPRESS(type.6) // NO-FORMAT: attribute // TODO: false positive | |
1241 | constexpr multi_span() noexcept : multi_span(nullptr, bounds_type{}) | |
1242 | { | |
1243 | static_assert(bounds_type::dynamic_rank != 0 || | |
1244 | (bounds_type::dynamic_rank == 0 && bounds_type::static_size == 0), | |
1245 | "Default construction of multi_span<T> only possible " | |
1246 | "for dynamic or fixed, zero-length spans."); | |
1247 | } | |
1248 | ||
1249 | // construct from nullptr - get an empty multi_span | |
1250 | GSL_SUPPRESS(type.6) // NO-FORMAT: attribute // TODO: false positive | |
1251 | constexpr multi_span(std::nullptr_t) noexcept : multi_span(nullptr, bounds_type{}) | |
1252 | { | |
1253 | static_assert(bounds_type::dynamic_rank != 0 || | |
1254 | (bounds_type::dynamic_rank == 0 && bounds_type::static_size == 0), | |
1255 | "nullptr_t construction of multi_span<T> only possible " | |
1256 | "for dynamic or fixed, zero-length spans."); | |
1257 | } | |
1258 | ||
1259 | // construct from nullptr with size of 0 (helps with template function calls) | |
1260 | template <class IntType, typename = std::enable_if_t<std::is_integral<IntType>::value>> | |
1261 | ||
1262 | // GSL_SUPPRESS(type.6) // NO-FORMAT: attribute // TODO: false positive // TODO: parser bug | |
1263 | constexpr multi_span(std::nullptr_t, IntType size) : multi_span(nullptr, bounds_type{}) | |
1264 | { | |
1265 | static_assert(bounds_type::dynamic_rank != 0 || | |
1266 | (bounds_type::dynamic_rank == 0 && bounds_type::static_size == 0), | |
1267 | "nullptr_t construction of multi_span<T> only possible " | |
1268 | "for dynamic or fixed, zero-length spans."); | |
1269 | Expects(size == 0); | |
1270 | } | |
1271 | ||
1272 | // construct from a single element | |
1273 | ||
1274 | GSL_SUPPRESS(type.6) // NO-FORMAT: attribute // TODO: false positive | |
1275 | constexpr multi_span(reference data) noexcept : multi_span(&data, bounds_type{1}) | |
1276 | { | |
1277 | static_assert(bounds_type::dynamic_rank > 0 || bounds_type::static_size == 0 || | |
1278 | bounds_type::static_size == 1, | |
1279 | "Construction from a single element only possible " | |
1280 | "for dynamic or fixed spans of length 0 or 1."); | |
1281 | } | |
1282 | ||
1283 | // prevent constructing from temporaries for single-elements | |
1284 | constexpr multi_span(value_type &&) = delete; | |
1285 | ||
1286 | // construct from pointer + length | |
1287 | GSL_SUPPRESS(type.6) // NO-FORMAT: attribute // TODO: false positive | |
1288 | constexpr multi_span(pointer ptr, size_type size) : multi_span(ptr, bounds_type{size}) {} | |
1289 | ||
1290 | // construct from pointer + length - multidimensional | |
1291 | constexpr multi_span(pointer data, bounds_type bounds) : data_(data), bounds_(std::move(bounds)) | |
1292 | { | |
1293 | Expects((bounds_.size() > 0 && data != nullptr) || bounds_.size() == 0); | |
1294 | } | |
1295 | ||
1296 | // construct from begin,end pointer pair | |
1297 | template <typename Ptr, | |
1298 | typename = std::enable_if_t<std::is_convertible<Ptr, pointer>::value && | |
1299 | details::LessThan<bounds_type::dynamic_rank, 2>::value>> | |
1300 | constexpr multi_span(pointer begin, Ptr end) | |
1301 | : multi_span(begin, | |
1302 | details::newBoundsHelper<bounds_type>(static_cast<pointer>(end) - begin)) | |
1303 | { | |
1304 | Expects(begin != nullptr && end != nullptr && begin <= static_cast<pointer>(end)); | |
1305 | } | |
1306 | ||
1307 | // construct from n-dimensions static array | |
1308 | template <typename T, std::size_t N, typename Helper = details::SpanArrayTraits<T, N>> | |
1309 | constexpr multi_span(T(&arr)[N]) | |
1310 | : multi_span(reinterpret_cast<pointer>(arr), bounds_type{typename Helper::bounds_type{}}) | |
1311 | { | |
1312 | static_assert(std::is_convertible<typename Helper::value_type(*)[], value_type(*)[]>::value, | |
1313 | "Cannot convert from source type to target multi_span type."); | |
1314 | static_assert(std::is_convertible<typename Helper::bounds_type, bounds_type>::value, | |
1315 | "Cannot construct a multi_span from an array with fewer elements."); | |
1316 | } | |
1317 | ||
1318 | // construct from n-dimensions dynamic array (e.g. new int[m][4]) | |
1319 | // (precedence will be lower than the 1-dimension pointer) | |
1320 | template <typename T, typename Helper = details::SpanArrayTraits<T, dynamic_range>> | |
1321 | constexpr multi_span(T* const& data, size_type size) | |
1322 | : multi_span(reinterpret_cast<pointer>(data), typename Helper::bounds_type{size}) | |
1323 | { | |
1324 | static_assert(std::is_convertible<typename Helper::value_type(*)[], value_type(*)[]>::value, | |
1325 | "Cannot convert from source type to target multi_span type."); | |
1326 | } | |
1327 | ||
1328 | // construct from std::array | |
1329 | template <typename T, std::size_t N> | |
1330 | constexpr multi_span(std::array<T, N> & arr) | |
1331 | : multi_span(arr.data(), bounds_type{static_bounds<N>{}}) | |
1332 | { | |
1333 | static_assert( | |
1334 | std::is_convertible<T(*)[], typename std::remove_const_t<value_type>(*)[]>::value, | |
1335 | "Cannot convert from source type to target multi_span type."); | |
1336 | static_assert(std::is_convertible<static_bounds<N>, bounds_type>::value, | |
1337 | "You cannot construct a multi_span from a std::array of smaller size."); | |
1338 | } | |
1339 | ||
1340 | // construct from const std::array | |
1341 | template <typename T, std::size_t N> | |
1342 | constexpr multi_span(const std::array<T, N>& arr) | |
1343 | : multi_span(arr.data(), bounds_type{static_bounds<N>{}}) | |
1344 | { | |
1345 | static_assert( | |
1346 | std::is_convertible<T(*)[], typename std::remove_const_t<value_type>(*)[]>::value, | |
1347 | "Cannot convert from source type to target multi_span type."); | |
1348 | static_assert(std::is_convertible<static_bounds<N>, bounds_type>::value, | |
1349 | "You cannot construct a multi_span from a std::array of smaller size."); | |
1350 | } | |
1351 | ||
1352 | // prevent constructing from temporary std::array | |
1353 | template <typename T, std::size_t N> | |
1354 | constexpr multi_span(std::array<T, N> && arr) = delete; | |
1355 | ||
1356 | // construct from containers | |
1357 | // future: could use contiguous_iterator_traits to identify only contiguous containers | |
1358 | // type-requirements: container must have .size(), operator[] which are value_type compatible | |
1359 | template <typename Cont, typename DataType = typename Cont::value_type, | |
1360 | typename = std::enable_if_t< | |
1361 | !details::is_multi_span<Cont>::value && | |
1362 | std::is_convertible<DataType(*)[], value_type(*)[]>::value && | |
1363 | std::is_same<std::decay_t<decltype(std::declval<Cont>().size(), | |
1364 | *std::declval<Cont>().data())>, | |
1365 | DataType>::value>> | |
1366 | constexpr multi_span(Cont & cont) | |
1367 | : multi_span(static_cast<pointer>(cont.data()), | |
1368 | details::newBoundsHelper<bounds_type>(narrow_cast<size_type>(cont.size()))) | |
1369 | {} | |
1370 | ||
1371 | // prevent constructing from temporary containers | |
1372 | template <typename Cont, typename DataType = typename Cont::value_type, | |
1373 | typename = std::enable_if_t< | |
1374 | !details::is_multi_span<Cont>::value && | |
1375 | std::is_convertible<DataType(*)[], value_type(*)[]>::value && | |
1376 | std::is_same<std::decay_t<decltype(std::declval<Cont>().size(), | |
1377 | *std::declval<Cont>().data())>, | |
1378 | DataType>::value>> | |
1379 | explicit constexpr multi_span(Cont && cont) = delete; | |
1380 | ||
1381 | // construct from a convertible multi_span | |
1382 | template <typename OtherValueType, std::ptrdiff_t... OtherDimensions, | |
1383 | typename OtherBounds = static_bounds<OtherDimensions...>, | |
1384 | typename = std::enable_if_t<std::is_convertible<OtherValueType, ValueType>::value && | |
1385 | std::is_convertible<OtherBounds, bounds_type>::value>> | |
1386 | constexpr multi_span(multi_span<OtherValueType, OtherDimensions...> other) | |
1387 | : data_(other.data_), bounds_(other.bounds_) | |
1388 | {} | |
1389 | ||
1390 | // trivial copy and move | |
1391 | constexpr multi_span(const multi_span&) = default; | |
1392 | constexpr multi_span(multi_span &&) = default; | |
1393 | ||
1394 | // trivial assignment | |
1395 | constexpr multi_span& operator=(const multi_span&) = default; | |
1396 | constexpr multi_span& operator=(multi_span&&) = default; | |
1397 | ||
1398 | // first() - extract the first Count elements into a new multi_span | |
1399 | template <std::ptrdiff_t Count> | |
1400 | ||
1401 | constexpr multi_span<ValueType, Count> first() const | |
1402 | { | |
1403 | static_assert(Count >= 0, "Count must be >= 0."); | |
1404 | static_assert(bounds_type::static_size == dynamic_range || | |
1405 | Count <= bounds_type::static_size, | |
1406 | "Count is out of bounds."); | |
1407 | ||
1408 | Expects(bounds_type::static_size != dynamic_range || Count <= this->size()); | |
1409 | return {this->data(), Count}; | |
1410 | } | |
1411 | ||
1412 | // first() - extract the first count elements into a new multi_span | |
1413 | constexpr multi_span<ValueType, dynamic_range> first(size_type count) const | |
1414 | { | |
1415 | Expects(count >= 0 && count <= this->size()); | |
1416 | return {this->data(), count}; | |
1417 | } | |
1418 | ||
1419 | // last() - extract the last Count elements into a new multi_span | |
1420 | template <std::ptrdiff_t Count> | |
1421 | constexpr multi_span<ValueType, Count> last() const | |
1422 | { | |
1423 | static_assert(Count >= 0, "Count must be >= 0."); | |
1424 | static_assert(bounds_type::static_size == dynamic_range || | |
1425 | Count <= bounds_type::static_size, | |
1426 | "Count is out of bounds."); | |
1427 | ||
1428 | Expects(bounds_type::static_size != dynamic_range || Count <= this->size()); | |
1429 | return {this->data() + this->size() - Count, Count}; | |
1430 | } | |
1431 | ||
1432 | // last() - extract the last count elements into a new multi_span | |
1433 | constexpr multi_span<ValueType, dynamic_range> last(size_type count) const | |
1434 | { | |
1435 | Expects(count >= 0 && count <= this->size()); | |
1436 | return {this->data() + this->size() - count, count}; | |
1437 | } | |
1438 | ||
1439 | // subspan() - create a subview of Count elements starting at Offset | |
1440 | template <std::ptrdiff_t Offset, std::ptrdiff_t Count> | |
1441 | constexpr multi_span<ValueType, Count> subspan() const | |
1442 | { | |
1443 | static_assert(Count >= 0, "Count must be >= 0."); | |
1444 | static_assert(Offset >= 0, "Offset must be >= 0."); | |
1445 | static_assert(bounds_type::static_size == dynamic_range || | |
1446 | ((Offset <= bounds_type::static_size) && | |
1447 | Count <= bounds_type::static_size - Offset), | |
1448 | "You must describe a sub-range within bounds of the multi_span."); | |
1449 | ||
1450 | Expects(bounds_type::static_size != dynamic_range || | |
1451 | (Offset <= this->size() && Count <= this->size() - Offset)); | |
1452 | return {this->data() + Offset, Count}; | |
1453 | } | |
1454 | ||
1455 | // subspan() - create a subview of count elements starting at offset | |
1456 | // supplying dynamic_range for count will consume all available elements from offset | |
1457 | constexpr multi_span<ValueType, dynamic_range> subspan(size_type offset, | |
1458 | size_type count = dynamic_range) const | |
1459 | { | |
1460 | Expects((offset >= 0 && offset <= this->size()) && | |
1461 | (count == dynamic_range || (count <= this->size() - offset))); | |
1462 | return {this->data() + offset, count == dynamic_range ? this->length() - offset : count}; | |
1463 | } | |
1464 | ||
1465 | // section - creates a non-contiguous, strided multi_span from a contiguous one | |
1466 | constexpr strided_span<ValueType, Rank> section(index_type origin, index_type extents) const | |
1467 | { | |
1468 | const size_type size = this->bounds().total_size() - this->bounds().linearize(origin); | |
1469 | return {&this->operator[](origin), size, | |
1470 | strided_bounds<Rank>{extents, details::make_stride(bounds())}}; | |
1471 | } | |
1472 | ||
1473 | // length of the multi_span in elements | |
1474 | constexpr size_type size() const noexcept { return bounds_.size(); } | |
1475 | ||
1476 | // length of the multi_span in elements | |
1477 | constexpr size_type length() const noexcept { return this->size(); } | |
1478 | ||
1479 | // length of the multi_span in bytes | |
1480 | constexpr size_type size_bytes() const noexcept | |
1481 | { | |
1482 | return narrow_cast<size_type>(sizeof(value_type)) * this->size(); | |
1483 | } | |
1484 | ||
1485 | // length of the multi_span in bytes | |
1486 | constexpr size_type length_bytes() const noexcept { return this->size_bytes(); } | |
1487 | ||
1488 | constexpr bool empty() const noexcept { return this->size() == 0; } | |
1489 | ||
1490 | static constexpr std::size_t rank() { return Rank; } | |
1491 | ||
1492 | template <std::size_t Dim = 0> | |
1493 | constexpr size_type extent() const noexcept | |
1494 | { | |
1495 | static_assert(Dim < Rank, | |
1496 | "Dimension should be less than rank (dimension count starts from 0)."); | |
1497 | return bounds_.template extent<Dim>(); | |
1498 | } | |
1499 | ||
1500 | template <typename IntType> | |
1501 | constexpr size_type extent(IntType dim) const | |
1502 | { | |
1503 | return bounds_.extent(dim); | |
1504 | } | |
1505 | ||
1506 | constexpr bounds_type bounds() const noexcept { return bounds_; } | |
1507 | ||
1508 | constexpr pointer data() const noexcept { return data_; } | |
1509 | ||
1510 | template <typename FirstIndex> | |
1511 | constexpr reference operator()(FirstIndex idx) | |
1512 | { | |
1513 | return this->operator[](narrow_cast<std::ptrdiff_t>(idx)); | |
1514 | } | |
1515 | ||
1516 | template <typename FirstIndex, typename... OtherIndices> | |
1517 | constexpr reference operator()(FirstIndex firstIndex, OtherIndices... indices) | |
1518 | { | |
1519 | const index_type idx = {narrow_cast<std::ptrdiff_t>(firstIndex), | |
1520 | narrow_cast<std::ptrdiff_t>(indices)...}; | |
1521 | return this->operator[](idx); | |
1522 | } | |
1523 | ||
1524 | GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute | |
1525 | constexpr reference operator[](const index_type& idx) const | |
1526 | { | |
1527 | return data_[bounds_.linearize(idx)]; | |
1528 | } | |
1529 | ||
1530 | template <bool Enabled = (Rank > 1), typename Ret = std::enable_if_t<Enabled, sliced_type>> | |
1531 | ||
1532 | GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute | |
1533 | constexpr Ret operator[](size_type idx) const | |
1534 | { | |
1535 | Expects(idx >= 0 && idx < bounds_.size()); // index is out of bounds of the array | |
1536 | const size_type ridx = idx * bounds_.stride(); | |
1537 | ||
1538 | // index is out of bounds of the underlying data | |
1539 | Expects(ridx < bounds_.total_size()); | |
1540 | return Ret{data_ + ridx, bounds_.slice()}; | |
1541 | } | |
1542 | ||
1543 | constexpr iterator begin() const noexcept { return iterator{this, true}; } | |
1544 | ||
1545 | constexpr iterator end() const noexcept { return iterator{this, false}; } | |
1546 | ||
1547 | GSL_SUPPRESS(type.1) // NO-FORMAT: attribute | |
1548 | constexpr const_iterator cbegin() const noexcept | |
1549 | { | |
1550 | return const_iterator{reinterpret_cast<const const_span*>(this), true}; | |
1551 | } | |
1552 | ||
1553 | constexpr const_iterator cend() const noexcept | |
1554 | { | |
1555 | return const_iterator{reinterpret_cast<const const_span*>(this), false}; | |
1556 | } | |
1557 | ||
1558 | constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator{end()}; } | |
1559 | ||
1560 | constexpr reverse_iterator rend() const noexcept { return reverse_iterator{begin()}; } | |
1561 | ||
1562 | constexpr const_reverse_iterator crbegin() const noexcept | |
1563 | { | |
1564 | return const_reverse_iterator{cend()}; | |
1565 | } | |
1566 | ||
1567 | constexpr const_reverse_iterator crend() const noexcept | |
1568 | { | |
1569 | return const_reverse_iterator{cbegin()}; | |
1570 | } | |
1571 | ||
1572 | template <typename OtherValueType, std::ptrdiff_t... OtherDimensions, | |
1573 | typename = std::enable_if_t<std::is_same<std::remove_cv_t<value_type>, | |
1574 | std::remove_cv_t<OtherValueType>>::value>> | |
1575 | constexpr bool operator==(const multi_span<OtherValueType, OtherDimensions...>& other) const | |
1576 | { | |
1577 | return bounds_.size() == other.bounds_.size() && | |
1578 | (data_ == other.data_ || std::equal(this->begin(), this->end(), other.begin())); | |
1579 | } | |
1580 | ||
1581 | template <typename OtherValueType, std::ptrdiff_t... OtherDimensions, | |
1582 | typename = std::enable_if_t<std::is_same<std::remove_cv_t<value_type>, | |
1583 | std::remove_cv_t<OtherValueType>>::value>> | |
1584 | constexpr bool operator!=(const multi_span<OtherValueType, OtherDimensions...>& other) const | |
1585 | { | |
1586 | return !(*this == other); | |
1587 | } | |
1588 | ||
1589 | template <typename OtherValueType, std::ptrdiff_t... OtherDimensions, | |
1590 | typename = std::enable_if_t<std::is_same<std::remove_cv_t<value_type>, | |
1591 | std::remove_cv_t<OtherValueType>>::value>> | |
1592 | constexpr bool operator<(const multi_span<OtherValueType, OtherDimensions...>& other) const | |
1593 | { | |
1594 | return std::lexicographical_compare(this->begin(), this->end(), other.begin(), other.end()); | |
1595 | } | |
1596 | ||
1597 | template <typename OtherValueType, std::ptrdiff_t... OtherDimensions, | |
1598 | typename = std::enable_if_t<std::is_same<std::remove_cv_t<value_type>, | |
1599 | std::remove_cv_t<OtherValueType>>::value>> | |
1600 | constexpr bool operator<=(const multi_span<OtherValueType, OtherDimensions...>& other) const | |
1601 | { | |
1602 | return !(other < *this); | |
1603 | } | |
1604 | ||
1605 | template <typename OtherValueType, std::ptrdiff_t... OtherDimensions, | |
1606 | typename = std::enable_if_t<std::is_same<std::remove_cv_t<value_type>, | |
1607 | std::remove_cv_t<OtherValueType>>::value>> | |
1608 | constexpr bool operator>(const multi_span<OtherValueType, OtherDimensions...>& other) | |
1609 | const noexcept | |
1610 | { | |
1611 | return (other < *this); | |
1612 | } | |
1613 | ||
1614 | template <typename OtherValueType, std::ptrdiff_t... OtherDimensions, | |
1615 | typename = std::enable_if_t<std::is_same<std::remove_cv_t<value_type>, | |
1616 | std::remove_cv_t<OtherValueType>>::value>> | |
1617 | constexpr bool operator>=(const multi_span<OtherValueType, OtherDimensions...>& other) const | |
1618 | { | |
1619 | return !(*this < other); | |
1620 | } | |
1621 | }; | |
1622 | ||
1623 | // | |
1624 | // Free functions for manipulating spans | |
1625 | // | |
1626 | ||
1627 | // reshape a multi_span into a different dimensionality | |
1628 | // DimCount and Enabled here are workarounds for a bug in MSVC 2015 | |
1629 | template <typename SpanType, typename... Dimensions2, std::size_t DimCount = sizeof...(Dimensions2), | |
1630 | bool Enabled = (DimCount > 0), typename = std::enable_if_t<Enabled>> | |
1631 | constexpr auto as_multi_span(SpanType s, Dimensions2... dims) | |
1632 | -> multi_span<typename SpanType::value_type, Dimensions2::value...> | |
1633 | { | |
1634 | static_assert(details::is_multi_span<SpanType>::value, | |
1635 | "Variadic as_multi_span() is for reshaping existing spans."); | |
1636 | using BoundsType = | |
1637 | typename multi_span<typename SpanType::value_type, (Dimensions2::value)...>::bounds_type; | |
1638 | const auto tobounds = details::static_as_multi_span_helper<BoundsType>(dims..., details::Sep{}); | |
1639 | details::verifyBoundsReshape(s.bounds(), tobounds); | |
1640 | return {s.data(), tobounds}; | |
1641 | } | |
1642 | ||
1643 | // convert a multi_span<T> to a multi_span<const byte> | |
1644 | template <typename U, std::ptrdiff_t... Dimensions> | |
1645 | multi_span<const byte, dynamic_range> | |
1646 | as_bytes(multi_span<U, Dimensions...> s) noexcept | |
1647 | { | |
1648 | static_assert(std::is_trivial<std::decay_t<U>>::value, | |
1649 | "The value_type of multi_span must be a trivial type."); | |
1650 | return {reinterpret_cast<const byte*>(s.data()), s.size_bytes()}; | |
1651 | } | |
1652 | ||
1653 | // convert a multi_span<T> to a multi_span<byte> (a writeable byte multi_span) | |
1654 | // this is not currently a portable function that can be relied upon to work | |
1655 | // on all implementations. It should be considered an experimental extension | |
1656 | // to the standard GSL interface. | |
1657 | template <typename U, std::ptrdiff_t... Dimensions> | |
1658 | multi_span<byte> as_writeable_bytes(multi_span<U, Dimensions...> s) noexcept | |
1659 | { | |
1660 | static_assert(std::is_trivial<std::decay_t<U>>::value, | |
1661 | "The value_type of multi_span must be a trivial type."); | |
1662 | return {reinterpret_cast<byte*>(s.data()), s.size_bytes()}; | |
1663 | } | |
1664 | ||
1665 | // convert a multi_span<const byte> to a multi_span<const T> | |
1666 | // this is not currently a portable function that can be relied upon to work | |
1667 | // on all implementations. It should be considered an experimental extension | |
1668 | // to the standard GSL interface. | |
1669 | template <typename U, std::ptrdiff_t... Dimensions> | |
1670 | constexpr auto as_multi_span(multi_span<const byte, Dimensions...> s) -> multi_span< | |
1671 | const U, static_cast<std::ptrdiff_t>( | |
1672 | multi_span<const byte, Dimensions...>::bounds_type::static_size != dynamic_range | |
1673 | ? (static_cast<std::size_t>( | |
1674 | multi_span<const byte, Dimensions...>::bounds_type::static_size) / | |
1675 | sizeof(U)) | |
1676 | : dynamic_range)> | |
1677 | { | |
1678 | using ConstByteSpan = multi_span<const byte, Dimensions...>; | |
1679 | static_assert( | |
1680 | std::is_trivial<std::decay_t<U>>::value && | |
1681 | (ConstByteSpan::bounds_type::static_size == dynamic_range || | |
1682 | ConstByteSpan::bounds_type::static_size % narrow_cast<std::ptrdiff_t>(sizeof(U)) == 0), | |
1683 | "Target type must be a trivial type and its size must match the byte array size"); | |
1684 | ||
1685 | Expects((s.size_bytes() % narrow_cast<std::ptrdiff_t>(sizeof(U))) == 0 && | |
1686 | (s.size_bytes() / narrow_cast<std::ptrdiff_t>(sizeof(U))) < PTRDIFF_MAX); | |
1687 | return {reinterpret_cast<const U*>(s.data()), | |
1688 | s.size_bytes() / narrow_cast<std::ptrdiff_t>(sizeof(U))}; | |
1689 | } | |
1690 | ||
1691 | // convert a multi_span<byte> to a multi_span<T> | |
1692 | // this is not currently a portable function that can be relied upon to work | |
1693 | // on all implementations. It should be considered an experimental extension | |
1694 | // to the standard GSL interface. | |
1695 | template <typename U, std::ptrdiff_t... Dimensions> | |
1696 | constexpr auto as_multi_span(multi_span<byte, Dimensions...> s) | |
1697 | -> multi_span<U, narrow_cast<std::ptrdiff_t>( | |
1698 | multi_span<byte, Dimensions...>::bounds_type::static_size != dynamic_range | |
1699 | ? static_cast<std::size_t>( | |
1700 | multi_span<byte, Dimensions...>::bounds_type::static_size) / | |
1701 | sizeof(U) | |
1702 | : dynamic_range)> | |
1703 | { | |
1704 | using ByteSpan = multi_span<byte, Dimensions...>; | |
1705 | static_assert(std::is_trivial<std::decay_t<U>>::value && | |
1706 | (ByteSpan::bounds_type::static_size == dynamic_range || | |
1707 | ByteSpan::bounds_type::static_size % sizeof(U) == 0), | |
1708 | "Target type must be a trivial type and its size must match the byte array size"); | |
1709 | ||
1710 | Expects((s.size_bytes() % sizeof(U)) == 0); | |
1711 | return {reinterpret_cast<U*>(s.data()), | |
1712 | s.size_bytes() / narrow_cast<std::ptrdiff_t>(sizeof(U))}; | |
1713 | } | |
1714 | ||
1715 | template <typename T, std::ptrdiff_t... Dimensions> | |
1716 | constexpr auto as_multi_span(T* const& ptr, dim_t<Dimensions>... args) | |
1717 | -> multi_span<std::remove_all_extents_t<T>, Dimensions...> | |
1718 | { | |
1719 | return {reinterpret_cast<std::remove_all_extents_t<T>*>(ptr), | |
1720 | details::static_as_multi_span_helper<static_bounds<Dimensions...>>(args..., | |
1721 | details::Sep{})}; | |
1722 | } | |
1723 | ||
1724 | template <typename T> | |
1725 | constexpr auto as_multi_span(T* arr, std::ptrdiff_t len) -> | |
1726 | typename details::SpanArrayTraits<T, dynamic_range>::type | |
1727 | { | |
1728 | return {reinterpret_cast<std::remove_all_extents_t<T>*>(arr), len}; | |
1729 | } | |
1730 | ||
1731 | template <typename T, std::size_t N> | |
1732 | constexpr auto as_multi_span(T (&arr)[N]) -> | |
1733 | typename details::SpanArrayTraits<T, N>::type | |
1734 | { | |
1735 | return {arr}; | |
1736 | } | |
1737 | ||
1738 | template <typename T, std::size_t N> | |
1739 | constexpr multi_span<const T, N> as_multi_span(const std::array<T, N>& arr) | |
1740 | { | |
1741 | return {arr}; | |
1742 | } | |
1743 | ||
1744 | template <typename T, std::size_t N> | |
1745 | constexpr multi_span<const T, N> as_multi_span(const std::array<T, N>&&) = delete; | |
1746 | ||
1747 | template <typename T, std::size_t N> | |
1748 | constexpr multi_span<T, N> as_multi_span(std::array<T, N>& arr) | |
1749 | { | |
1750 | return {arr}; | |
1751 | } | |
1752 | ||
1753 | template <typename T> | |
1754 | constexpr multi_span<T, dynamic_range> as_multi_span(T* begin, T* end) | |
1755 | { | |
1756 | return {begin, end}; | |
1757 | } | |
1758 | ||
1759 | template <typename Cont> | |
1760 | constexpr auto as_multi_span(Cont& arr) -> std::enable_if_t< | |
1761 | !details::is_multi_span<std::decay_t<Cont>>::value, | |
1762 | multi_span<std::remove_reference_t<decltype(arr.size(), *arr.data())>, dynamic_range>> | |
1763 | { | |
1764 | Expects(arr.size() < PTRDIFF_MAX); | |
1765 | return {arr.data(), narrow_cast<std::ptrdiff_t>(arr.size())}; | |
1766 | } | |
1767 | ||
1768 | template <typename Cont> | |
1769 | constexpr auto as_multi_span(Cont&& arr) -> std::enable_if_t< | |
1770 | !details::is_multi_span<std::decay_t<Cont>>::value, | |
1771 | multi_span<std::remove_reference_t<decltype(arr.size(), *arr.data())>, dynamic_range>> = delete; | |
1772 | ||
1773 | // from basic_string which doesn't have nonconst .data() member like other contiguous containers | |
1774 | template <typename CharT, typename Traits, typename Allocator> | |
1775 | GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute | |
1776 | constexpr auto as_multi_span(std::basic_string<CharT, Traits, Allocator>& str) | |
1777 | -> multi_span<CharT, dynamic_range> | |
1778 | { | |
1779 | Expects(str.size() < PTRDIFF_MAX); | |
1780 | return {&str[0], narrow_cast<std::ptrdiff_t>(str.size())}; | |
1781 | } | |
1782 | ||
1783 | // strided_span is an extension that is not strictly part of the GSL at this time. | |
1784 | // It is kept here while the multidimensional interface is still being defined. | |
1785 | template <typename ValueType, std::size_t Rank> | |
1786 | class [[deprecated("gsl::strided_span is deprecated because it is not in the C++ Core Guidelines")]] strided_span | |
1787 | { | |
1788 | public: | |
1789 | using bounds_type = strided_bounds<Rank>; | |
1790 | using size_type = typename bounds_type::size_type; | |
1791 | using index_type = typename bounds_type::index_type; | |
1792 | using value_type = ValueType; | |
1793 | using const_value_type = std::add_const_t<value_type>; | |
1794 | using pointer = std::add_pointer_t<value_type>; | |
1795 | using reference = std::add_lvalue_reference_t<value_type>; | |
1796 | using iterator = general_span_iterator<strided_span>; | |
1797 | using const_strided_span = strided_span<const_value_type, Rank>; | |
1798 | using const_iterator = general_span_iterator<const_strided_span>; | |
1799 | using reverse_iterator = std::reverse_iterator<iterator>; | |
1800 | using const_reverse_iterator = std::reverse_iterator<const_iterator>; | |
1801 | using sliced_type = | |
1802 | std::conditional_t<Rank == 1, value_type, strided_span<value_type, Rank - 1>>; | |
1803 | ||
1804 | private: | |
1805 | pointer data_; | |
1806 | bounds_type bounds_; | |
1807 | ||
1808 | friend iterator; | |
1809 | friend const_iterator; | |
1810 | template <typename OtherValueType, std::size_t OtherRank> | |
1811 | friend class strided_span; | |
1812 | ||
1813 | public: | |
1814 | // from raw data | |
1815 | constexpr strided_span(pointer ptr, size_type size, bounds_type bounds) | |
1816 | : data_(ptr), bounds_(std::move(bounds)) | |
1817 | { | |
1818 | Expects((bounds_.size() > 0 && ptr != nullptr) || bounds_.size() == 0); | |
1819 | // Bounds cross data boundaries | |
1820 | Expects(this->bounds().total_size() <= size); | |
1821 | GSL_SUPPRESS(type.4) // NO-FORMAT: attribute // TODO: false positive | |
1822 | (void) size; | |
1823 | } | |
1824 | ||
1825 | // from static array of size N | |
1826 | template <size_type N> | |
1827 | constexpr strided_span(value_type (&values)[N], bounds_type bounds) | |
1828 | : strided_span(values, N, std::move(bounds)) | |
1829 | {} | |
1830 | ||
1831 | // from array view | |
1832 | template <typename OtherValueType, std::ptrdiff_t... Dimensions, | |
1833 | bool Enabled1 = (sizeof...(Dimensions) == Rank), | |
1834 | bool Enabled2 = std::is_convertible<OtherValueType*, ValueType*>::value, | |
1835 | typename = std::enable_if_t<Enabled1 && Enabled2>> | |
1836 | constexpr strided_span(multi_span<OtherValueType, Dimensions...> av, bounds_type bounds) | |
1837 | : strided_span(av.data(), av.bounds().total_size(), std::move(bounds)) | |
1838 | {} | |
1839 | ||
1840 | // convertible | |
1841 | template <typename OtherValueType, typename = std::enable_if_t<std::is_convertible< | |
1842 | OtherValueType (*)[], value_type (*)[]>::value>> | |
1843 | constexpr strided_span(const strided_span<OtherValueType, Rank>& other) | |
1844 | : data_(other.data_), bounds_(other.bounds_) | |
1845 | {} | |
1846 | ||
1847 | // convert from bytes | |
1848 | template <typename OtherValueType> | |
1849 | constexpr strided_span< | |
1850 | typename std::enable_if<std::is_same<value_type, const byte>::value, OtherValueType>::type, | |
1851 | Rank> | |
1852 | as_strided_span() const | |
1853 | { | |
1854 | static_assert((sizeof(OtherValueType) >= sizeof(value_type)) && | |
1855 | (sizeof(OtherValueType) % sizeof(value_type) == 0), | |
1856 | "OtherValueType should have a size to contain a multiple of ValueTypes"); | |
1857 | auto d = narrow_cast<size_type>(sizeof(OtherValueType) / sizeof(value_type)); | |
1858 | ||
1859 | const size_type size = this->bounds().total_size() / d; | |
1860 | ||
1861 | GSL_SUPPRESS(type.3) // NO-FORMAT: attribute | |
1862 | return {const_cast<OtherValueType*>(reinterpret_cast<const OtherValueType*>(this->data())), | |
1863 | size, | |
1864 | bounds_type{resize_extent(this->bounds().index_bounds(), d), | |
1865 | resize_stride(this->bounds().strides(), d)}}; | |
1866 | } | |
1867 | ||
1868 | constexpr strided_span section(index_type origin, index_type extents) const | |
1869 | { | |
1870 | const size_type size = this->bounds().total_size() - this->bounds().linearize(origin); | |
1871 | return {&this->operator[](origin), size, | |
1872 | bounds_type{extents, details::make_stride(bounds())}}; | |
1873 | } | |
1874 | ||
1875 | GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute | |
1876 | constexpr reference operator[](const index_type& idx) const | |
1877 | { | |
1878 | return data_[bounds_.linearize(idx)]; | |
1879 | } | |
1880 | ||
1881 | template <bool Enabled = (Rank > 1), typename Ret = std::enable_if_t<Enabled, sliced_type>> | |
1882 | GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute | |
1883 | constexpr Ret operator[](size_type idx) const | |
1884 | { | |
1885 | Expects(idx < bounds_.size()); // index is out of bounds of the array | |
1886 | const size_type ridx = idx * bounds_.stride(); | |
1887 | ||
1888 | // index is out of bounds of the underlying data | |
1889 | Expects(ridx < bounds_.total_size()); | |
1890 | return {data_ + ridx, bounds_.slice().total_size(), bounds_.slice()}; | |
1891 | } | |
1892 | ||
1893 | constexpr bounds_type bounds() const noexcept { return bounds_; } | |
1894 | ||
1895 | template <std::size_t Dim = 0> | |
1896 | constexpr size_type extent() const noexcept | |
1897 | { | |
1898 | static_assert(Dim < Rank, | |
1899 | "dimension should be less than Rank (dimension count starts from 0)"); | |
1900 | return bounds_.template extent<Dim>(); | |
1901 | } | |
1902 | ||
1903 | constexpr size_type size() const noexcept { return bounds_.size(); } | |
1904 | ||
1905 | constexpr pointer data() const noexcept { return data_; } | |
1906 | ||
1907 | constexpr bool empty() const noexcept { return this->size() == 0; } | |
1908 | ||
1909 | constexpr explicit operator bool() const noexcept { return data_ != nullptr; } | |
1910 | ||
1911 | constexpr iterator begin() const { return iterator{this, true}; } | |
1912 | ||
1913 | constexpr iterator end() const { return iterator{this, false}; } | |
1914 | ||
1915 | constexpr const_iterator cbegin() const | |
1916 | { | |
1917 | return const_iterator{reinterpret_cast<const const_strided_span*>(this), true}; | |
1918 | } | |
1919 | ||
1920 | constexpr const_iterator cend() const | |
1921 | { | |
1922 | return const_iterator{reinterpret_cast<const const_strided_span*>(this), false}; | |
1923 | } | |
1924 | ||
1925 | constexpr reverse_iterator rbegin() const { return reverse_iterator{end()}; } | |
1926 | ||
1927 | constexpr reverse_iterator rend() const { return reverse_iterator{begin()}; } | |
1928 | ||
1929 | constexpr const_reverse_iterator crbegin() const { return const_reverse_iterator{cend()}; } | |
1930 | ||
1931 | constexpr const_reverse_iterator crend() const { return const_reverse_iterator{cbegin()}; } | |
1932 | ||
1933 | template <typename OtherValueType, std::ptrdiff_t OtherRank, | |
1934 | typename = std::enable_if_t<std::is_same<std::remove_cv_t<value_type>, | |
1935 | std::remove_cv_t<OtherValueType>>::value>> | |
1936 | constexpr bool operator==(const strided_span<OtherValueType, OtherRank>& other) const | |
1937 | { | |
1938 | return bounds_.size() == other.bounds_.size() && | |
1939 | (data_ == other.data_ || std::equal(this->begin(), this->end(), other.begin())); | |
1940 | } | |
1941 | ||
1942 | template <typename OtherValueType, std::ptrdiff_t OtherRank, | |
1943 | typename = std::enable_if_t<std::is_same<std::remove_cv_t<value_type>, | |
1944 | std::remove_cv_t<OtherValueType>>::value>> | |
1945 | constexpr bool operator!=(const strided_span<OtherValueType, OtherRank>& other) const | |
1946 | { | |
1947 | return !(*this == other); | |
1948 | } | |
1949 | ||
1950 | template <typename OtherValueType, std::ptrdiff_t OtherRank, | |
1951 | typename = std::enable_if_t<std::is_same<std::remove_cv_t<value_type>, | |
1952 | std::remove_cv_t<OtherValueType>>::value>> | |
1953 | constexpr bool operator<(const strided_span<OtherValueType, OtherRank>& other) const | |
1954 | { | |
1955 | return std::lexicographical_compare(this->begin(), this->end(), other.begin(), other.end()); | |
1956 | } | |
1957 | ||
1958 | template <typename OtherValueType, std::ptrdiff_t OtherRank, | |
1959 | typename = std::enable_if_t<std::is_same<std::remove_cv_t<value_type>, | |
1960 | std::remove_cv_t<OtherValueType>>::value>> | |
1961 | constexpr bool operator<=(const strided_span<OtherValueType, OtherRank>& other) const | |
1962 | { | |
1963 | return !(other < *this); | |
1964 | } | |
1965 | ||
1966 | template <typename OtherValueType, std::ptrdiff_t OtherRank, | |
1967 | typename = std::enable_if_t<std::is_same<std::remove_cv_t<value_type>, | |
1968 | std::remove_cv_t<OtherValueType>>::value>> | |
1969 | constexpr bool operator>(const strided_span<OtherValueType, OtherRank>& other) const | |
1970 | { | |
1971 | return (other < *this); | |
1972 | } | |
1973 | ||
1974 | template <typename OtherValueType, std::ptrdiff_t OtherRank, | |
1975 | typename = std::enable_if_t<std::is_same<std::remove_cv_t<value_type>, | |
1976 | std::remove_cv_t<OtherValueType>>::value>> | |
1977 | constexpr bool operator>=(const strided_span<OtherValueType, OtherRank>& other) const | |
1978 | { | |
1979 | return !(*this < other); | |
1980 | } | |
1981 | ||
1982 | private: | |
1983 | static index_type resize_extent(const index_type& extent, std::ptrdiff_t d) | |
1984 | { | |
1985 | // The last dimension of the array needs to contain a multiple of new type elements | |
1986 | GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute | |
1987 | Expects(extent[Rank - 1] >= d && (extent[Rank - 1] % d == 0)); | |
1988 | ||
1989 | index_type ret = extent; | |
1990 | ret[Rank - 1] /= d; | |
1991 | ||
1992 | return ret; | |
1993 | } | |
1994 | ||
1995 | template <bool Enabled = (Rank == 1), typename = std::enable_if_t<Enabled>> | |
1996 | static index_type resize_stride(const index_type& strides, std::ptrdiff_t, void* = nullptr) | |
1997 | { | |
1998 | // Only strided arrays with regular strides can be resized | |
1999 | GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute | |
2000 | Expects(strides[Rank - 1] == 1); | |
2001 | ||
2002 | return strides; | |
2003 | } | |
2004 | ||
2005 | template <bool Enabled = (Rank > 1), typename = std::enable_if_t<Enabled>> | |
2006 | GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute | |
2007 | static index_type resize_stride(const index_type& strides, std::ptrdiff_t d) | |
2008 | { | |
2009 | // Only strided arrays with regular strides can be resized | |
2010 | Expects(strides[Rank - 1] == 1); | |
2011 | // The strides must have contiguous chunks of | |
2012 | // memory that can contain a multiple of new type elements | |
2013 | Expects(strides[Rank - 2] >= d && (strides[Rank - 2] % d == 0)); | |
2014 | ||
2015 | for (std::size_t i = Rank - 1; i > 0; --i) | |
2016 | { | |
2017 | // Only strided arrays with regular strides can be resized | |
2018 | Expects((strides[i - 1] >= strides[i]) && (strides[i - 1] % strides[i] == 0)); | |
2019 | } | |
2020 | ||
2021 | index_type ret = strides / d; | |
2022 | ret[Rank - 1] = 1; | |
2023 | ||
2024 | return ret; | |
2025 | } | |
2026 | }; | |
2027 | ||
2028 | template <class Span> | |
2029 | class [[deprecated]] contiguous_span_iterator { | |
2030 | public: | |
2031 | using iterator_category = std::random_access_iterator_tag; | |
2032 | using value_type = typename Span::value_type; | |
2033 | using difference_type = std::ptrdiff_t; | |
2034 | using pointer = value_type*; | |
2035 | using reference = value_type&; | |
2036 | ||
2037 | private: | |
2038 | template <typename ValueType, std::ptrdiff_t FirstDimension, std::ptrdiff_t... RestDimensions> | |
2039 | friend class multi_span; | |
2040 | ||
2041 | pointer data_; | |
2042 | const Span* m_validator; | |
2043 | ||
2044 | GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute | |
2045 | void validateThis() const | |
2046 | { | |
2047 | // iterator is out of range of the array | |
2048 | Expects(data_ >= m_validator->data_ && data_ < m_validator->data_ + m_validator->size()); | |
2049 | } | |
2050 | ||
2051 | GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute | |
2052 | contiguous_span_iterator(const Span* container, bool isbegin) | |
2053 | : data_(isbegin ? container->data_ : container->data_ + container->size()) | |
2054 | , m_validator(container) | |
2055 | {} | |
2056 | ||
2057 | public: | |
2058 | reference operator*() const | |
2059 | { | |
2060 | validateThis(); | |
2061 | return *data_; | |
2062 | } | |
2063 | pointer operator->() const | |
2064 | { | |
2065 | validateThis(); | |
2066 | return data_; | |
2067 | } | |
2068 | ||
2069 | GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute | |
2070 | contiguous_span_iterator& operator++() noexcept | |
2071 | { | |
2072 | ++data_; | |
2073 | return *this; | |
2074 | } | |
2075 | contiguous_span_iterator operator++(int) noexcept | |
2076 | { | |
2077 | auto ret = *this; | |
2078 | ++(*this); | |
2079 | return ret; | |
2080 | } | |
2081 | ||
2082 | GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute | |
2083 | contiguous_span_iterator& operator--() noexcept | |
2084 | { | |
2085 | --data_; | |
2086 | return *this; | |
2087 | } | |
2088 | contiguous_span_iterator operator--(int) noexcept | |
2089 | { | |
2090 | auto ret = *this; | |
2091 | --(*this); | |
2092 | return ret; | |
2093 | } | |
2094 | contiguous_span_iterator operator+(difference_type n) const noexcept | |
2095 | { | |
2096 | contiguous_span_iterator ret{*this}; | |
2097 | return ret += n; | |
2098 | } | |
2099 | contiguous_span_iterator& operator+=(difference_type n) noexcept | |
2100 | { | |
2101 | data_ += n; | |
2102 | return *this; | |
2103 | } | |
2104 | contiguous_span_iterator operator-(difference_type n) const noexcept | |
2105 | { | |
2106 | contiguous_span_iterator ret{*this}; | |
2107 | return ret -= n; | |
2108 | } | |
2109 | ||
2110 | contiguous_span_iterator& operator-=(difference_type n) { return *this += -n; } | |
2111 | difference_type operator-(const contiguous_span_iterator& rhs) const | |
2112 | { | |
2113 | Expects(m_validator == rhs.m_validator); | |
2114 | return data_ - rhs.data_; | |
2115 | } | |
2116 | reference operator[](difference_type n) const { return *(*this + n); } | |
2117 | bool operator==(const contiguous_span_iterator& rhs) const | |
2118 | { | |
2119 | Expects(m_validator == rhs.m_validator); | |
2120 | return data_ == rhs.data_; | |
2121 | } | |
2122 | ||
2123 | bool operator!=(const contiguous_span_iterator& rhs) const { return !(*this == rhs); } | |
2124 | ||
2125 | bool operator<(const contiguous_span_iterator& rhs) const | |
2126 | { | |
2127 | Expects(m_validator == rhs.m_validator); | |
2128 | return data_ < rhs.data_; | |
2129 | } | |
2130 | ||
2131 | bool operator<=(const contiguous_span_iterator& rhs) const { return !(rhs < *this); } | |
2132 | bool operator>(const contiguous_span_iterator& rhs) const { return rhs < *this; } | |
2133 | bool operator>=(const contiguous_span_iterator& rhs) const { return !(rhs > *this); } | |
2134 | ||
2135 | void swap(contiguous_span_iterator & rhs) noexcept | |
2136 | { | |
2137 | std::swap(data_, rhs.data_); | |
2138 | std::swap(m_validator, rhs.m_validator); | |
2139 | } | |
2140 | }; | |
2141 | ||
2142 | template <typename Span> | |
2143 | contiguous_span_iterator<Span> operator+(typename contiguous_span_iterator<Span>::difference_type n, | |
2144 | const contiguous_span_iterator<Span>& rhs) noexcept | |
2145 | { | |
2146 | return rhs + n; | |
2147 | } | |
2148 | ||
2149 | template <typename Span> | |
2150 | class [[deprecated]] general_span_iterator { | |
2151 | public: | |
2152 | using iterator_category = std::random_access_iterator_tag; | |
2153 | using value_type = typename Span::value_type; | |
2154 | using difference_type = std::ptrdiff_t; | |
2155 | using pointer = value_type*; | |
2156 | using reference = value_type&; | |
2157 | ||
2158 | private: | |
2159 | template <typename ValueType, std::size_t Rank> | |
2160 | friend class strided_span; | |
2161 | ||
2162 | const Span* m_container; | |
2163 | typename Span::bounds_type::iterator m_itr; | |
2164 | general_span_iterator(const Span* container, bool isbegin) | |
2165 | : m_container(container) | |
2166 | , m_itr(isbegin ? m_container->bounds().begin() : m_container->bounds().end()) | |
2167 | {} | |
2168 | ||
2169 | public: | |
2170 | reference operator*() noexcept { return (*m_container)[*m_itr]; } | |
2171 | pointer operator->() noexcept { return &(*m_container)[*m_itr]; } | |
2172 | general_span_iterator& operator++() noexcept | |
2173 | { | |
2174 | ++m_itr; | |
2175 | return *this; | |
2176 | } | |
2177 | general_span_iterator operator++(int) noexcept | |
2178 | { | |
2179 | auto ret = *this; | |
2180 | ++(*this); | |
2181 | return ret; | |
2182 | } | |
2183 | general_span_iterator& operator--() noexcept | |
2184 | { | |
2185 | --m_itr; | |
2186 | return *this; | |
2187 | } | |
2188 | general_span_iterator operator--(int) noexcept | |
2189 | { | |
2190 | auto ret = *this; | |
2191 | --(*this); | |
2192 | return ret; | |
2193 | } | |
2194 | general_span_iterator operator+(difference_type n) const noexcept | |
2195 | { | |
2196 | general_span_iterator ret{*this}; | |
2197 | return ret += n; | |
2198 | } | |
2199 | general_span_iterator& operator+=(difference_type n) noexcept | |
2200 | { | |
2201 | m_itr += n; | |
2202 | return *this; | |
2203 | } | |
2204 | general_span_iterator operator-(difference_type n) const noexcept | |
2205 | { | |
2206 | general_span_iterator ret{*this}; | |
2207 | return ret -= n; | |
2208 | } | |
2209 | general_span_iterator& operator-=(difference_type n) noexcept { return *this += -n; } | |
2210 | difference_type operator-(const general_span_iterator& rhs) const | |
2211 | { | |
2212 | Expects(m_container == rhs.m_container); | |
2213 | return m_itr - rhs.m_itr; | |
2214 | } | |
2215 | ||
2216 | GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute | |
2217 | value_type operator[](difference_type n) const { return (*m_container)[m_itr[n]]; } | |
2218 | ||
2219 | bool operator==(const general_span_iterator& rhs) const | |
2220 | { | |
2221 | Expects(m_container == rhs.m_container); | |
2222 | return m_itr == rhs.m_itr; | |
2223 | } | |
2224 | bool operator!=(const general_span_iterator& rhs) const { return !(*this == rhs); } | |
2225 | bool operator<(const general_span_iterator& rhs) const | |
2226 | { | |
2227 | Expects(m_container == rhs.m_container); | |
2228 | return m_itr < rhs.m_itr; | |
2229 | } | |
2230 | bool operator<=(const general_span_iterator& rhs) const { return !(rhs < *this); } | |
2231 | bool operator>(const general_span_iterator& rhs) const { return rhs < *this; } | |
2232 | bool operator>=(const general_span_iterator& rhs) const { return !(rhs > *this); } | |
2233 | void swap(general_span_iterator & rhs) noexcept | |
2234 | { | |
2235 | std::swap(m_itr, rhs.m_itr); | |
2236 | std::swap(m_container, rhs.m_container); | |
2237 | } | |
2238 | }; | |
2239 | ||
2240 | template <typename Span> | |
2241 | general_span_iterator<Span> operator+(typename general_span_iterator<Span>::difference_type n, | |
2242 | const general_span_iterator<Span>& rhs) noexcept | |
2243 | { | |
2244 | return rhs + n; | |
2245 | } | |
2246 | ||
2247 | } // namespace gsl | |
2248 | ||
2249 | #if defined(_MSC_VER) && !defined(__clang__) | |
2250 | ||
2251 | #pragma warning(pop) | |
2252 | ||
2253 | #endif // _MSC_VER | |
2254 | ||
2255 | #if defined(__GNUC__) && __GNUC__ > 6 | |
2256 | #pragma GCC diagnostic pop | |
2257 | #endif // __GNUC__ > 6 | |
2258 | ||
2259 | #if defined(__GNUC__) || defined(__clang__) | |
2260 | #pragma GCC diagnostic pop | |
2261 | #endif | |
2262 | ||
2263 | #endif // GSL_MULTI_SPAN_H |