]> git.proxmox.com Git - ceph.git/blame - ceph/src/jaegertracing/opentelemetry-cpp/third_party/ms-gsl/include/gsl/multi_span
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / jaegertracing / opentelemetry-cpp / third_party / ms-gsl / include / gsl / multi_span
CommitLineData
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
70namespace gsl
71{
72
73/*
74** begin definitions of index and bounds
75*/
76namespace 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
97template <std::size_t Rank>
98class [[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
104public:
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
232private:
233 value_type elems[Rank] = {};
234};
235
236#if !defined(_MSC_VER) || _MSC_VER >= 1910
237
238struct [[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
247constexpr bool operator==(static_bounds_dynamic_range_t, static_bounds_dynamic_range_t) noexcept
248{
249 return true;
250}
251
252constexpr bool operator!=(static_bounds_dynamic_range_t, static_bounds_dynamic_range_t) noexcept
253{
254 return false;
255}
256
257template <typename T, typename = std::enable_if_t<std::is_integral<T>::value>>
258constexpr bool operator==(static_bounds_dynamic_range_t, T other) noexcept
259{
260 return narrow_cast<T>(-1) == other;
261}
262
263template <typename T, typename = std::enable_if_t<std::is_integral<T>::value>>
264constexpr bool operator==(T left, static_bounds_dynamic_range_t right) noexcept
265{
266 return right == left;
267}
268
269template <typename T, typename = std::enable_if_t<std::is_integral<T>::value>>
270constexpr bool operator!=(static_bounds_dynamic_range_t, T other) noexcept
271{
272 return narrow_cast<T>(-1) != other;
273}
274
275template <typename T, typename = std::enable_if_t<std::is_integral<T>::value>>
276constexpr bool operator!=(T left, static_bounds_dynamic_range_t right) noexcept
277{
278 return right != left;
279}
280
281constexpr static_bounds_dynamic_range_t dynamic_range{};
282#else
283const std::ptrdiff_t dynamic_range = -1;
284#endif
285
286struct [[deprecated]] generalized_mapping_tag
287{
288};
289struct[[deprecated]] contiguous_mapping_tag : generalized_mapping_tag{};
290
291namespace 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
553template <typename IndexType>
554class [[deprecated]] bounds_iterator;
555
556template <std::ptrdiff_t... Ranges>
557class [[deprecated]] static_bounds {
558public:
559 static_bounds(const details::BoundsRanges<Ranges...>&) {}
560};
561
562template <std::ptrdiff_t FirstRange, std::ptrdiff_t... RestRanges>
563class[[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
573public:
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
723template <std::size_t Rank>
724class [[deprecated]] strided_bounds {
725 template <std::size_t OtherRank>
726 friend class strided_bounds;
727
728public:
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
820private:
821 index_type m_extents;
822 index_type m_strides;
823};
824
825template <typename T>
826struct[[deprecated]] is_bounds : std::integral_constant<bool, false>{};
827template <std::ptrdiff_t... Ranges>
828struct[[deprecated]] is_bounds<static_bounds<Ranges...>> : std::integral_constant<bool, true>{};
829template <std::size_t Rank>
830struct[[deprecated]] is_bounds<strided_bounds<Rank>> : std::integral_constant<bool, true>{};
831
832template <typename IndexType>
833class [[deprecated]] bounds_iterator {
834public:
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
973private:
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
1015template <typename IndexType>
1016bounds_iterator<IndexType> operator+(typename bounds_iterator<IndexType>::difference_type n,
1017 const bounds_iterator<IndexType>& rhs) noexcept
1018{
1019 return rhs + n;
1020}
1021
1022namespace 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
1069template <typename Span>
1070class [[deprecated]] contiguous_span_iterator;
1071template <typename Span>
1072class [[deprecated]] general_span_iterator;
1073
1074template <std::ptrdiff_t DimSize = dynamic_range>
1075struct [[deprecated]] dim_t
1076{
1077 static const std::ptrdiff_t value = DimSize;
1078};
1079template <>
1080struct [[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
1087template <std::ptrdiff_t N, class = std::enable_if_t<(N >= 0)>>
1088constexpr dim_t<N> dim() noexcept
1089{
1090 return dim_t<N>();
1091}
1092
1093template <std::ptrdiff_t N = dynamic_range, class = std::enable_if_t<N == dynamic_range>>
1094constexpr dim_t<N> dim(std::ptrdiff_t n) noexcept
1095{
1096 return dim_t<>(n);
1097}
1098
1099template <typename ValueType, std::ptrdiff_t FirstDimension = dynamic_range,
1100 std::ptrdiff_t... RestDimensions>
1101class [[deprecated("gsl::multi_span is deprecated because it is not in the C++ Core Guidelines")]] multi_span;
1102
1103template <typename ValueType, std::size_t Rank>
1104class [[deprecated("gsl::strided_span is deprecated because it is not in the C++ Core Guidelines")]] strided_span;
1105
1106namespace 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
1207template <typename ValueType, std::ptrdiff_t FirstDimension, std::ptrdiff_t... RestDimensions>
1208class [[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
1214public:
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
1231private:
1232 pointer data_;
1233 bounds_type bounds_;
1234
1235 friend iterator;
1236 friend const_iterator;
1237
1238public:
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
1629template <typename SpanType, typename... Dimensions2, std::size_t DimCount = sizeof...(Dimensions2),
1630 bool Enabled = (DimCount > 0), typename = std::enable_if_t<Enabled>>
1631constexpr 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>
1644template <typename U, std::ptrdiff_t... Dimensions>
1645multi_span<const byte, dynamic_range>
1646as_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.
1657template <typename U, std::ptrdiff_t... Dimensions>
1658multi_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.
1669template <typename U, std::ptrdiff_t... Dimensions>
1670constexpr 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.
1695template <typename U, std::ptrdiff_t... Dimensions>
1696constexpr 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
1715template <typename T, std::ptrdiff_t... Dimensions>
1716constexpr 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
1724template <typename T>
1725constexpr 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
1731template <typename T, std::size_t N>
1732constexpr auto as_multi_span(T (&arr)[N]) ->
1733 typename details::SpanArrayTraits<T, N>::type
1734{
1735 return {arr};
1736}
1737
1738template <typename T, std::size_t N>
1739constexpr multi_span<const T, N> as_multi_span(const std::array<T, N>& arr)
1740{
1741 return {arr};
1742}
1743
1744template <typename T, std::size_t N>
1745constexpr multi_span<const T, N> as_multi_span(const std::array<T, N>&&) = delete;
1746
1747template <typename T, std::size_t N>
1748constexpr multi_span<T, N> as_multi_span(std::array<T, N>& arr)
1749{
1750 return {arr};
1751}
1752
1753template <typename T>
1754constexpr multi_span<T, dynamic_range> as_multi_span(T* begin, T* end)
1755{
1756 return {begin, end};
1757}
1758
1759template <typename Cont>
1760constexpr 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
1768template <typename Cont>
1769constexpr 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
1774template <typename CharT, typename Traits, typename Allocator>
1775GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute
1776constexpr 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.
1785template <typename ValueType, std::size_t Rank>
1786class [[deprecated("gsl::strided_span is deprecated because it is not in the C++ Core Guidelines")]] strided_span
1787{
1788public:
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
1804private:
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
1813public:
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
1982private:
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
2028template <class Span>
2029class [[deprecated]] contiguous_span_iterator {
2030public:
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
2037private:
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
2057public:
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
2142template <typename Span>
2143contiguous_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
2149template <typename Span>
2150class [[deprecated]] general_span_iterator {
2151public:
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
2158private:
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
2169public:
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
2240template <typename Span>
2241general_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