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