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_SPAN_H 18#define GSL_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, narrow 23 24#include <algorithm> // for lexicographical_compare 25#include <array> // for array 26#include <cstddef> // for ptrdiff_t, size_t, nullptr_t 27#include <iterator> // for reverse_iterator, distance, random_access_... 28#include <limits> 29#include <stdexcept> 30#include <type_traits> // for enable_if_t, declval, is_convertible, inte... 31#include <utility> 32#include <memory> // for std::addressof 33 34#if defined(_MSC_VER) && !defined(__clang__) 35#pragma warning(push) 36 37// turn off some warnings that are noisy about our Expects statements 38#pragma warning(disable : 4127) // conditional expression is constant 39#pragma warning(disable : 4702) // unreachable code 40 41// Turn MSVC /analyze rules that generate too much noise. TODO: fix in the tool. 42#pragma warning(disable : 26495) // uninitalized member when constructor calls constructor 43#pragma warning(disable : 26446) // parser bug does not allow attributes on some templates 44 45#if _MSC_VER < 1910 46#pragma push_macro("constexpr") 47#define constexpr /*constexpr*/ 48#define GSL_USE_STATIC_CONSTEXPR_WORKAROUND 49 50#endif // _MSC_VER < 1910 51#endif // _MSC_VER 52 53// See if we have enough C++17 power to use a static constexpr data member 54// without needing an out-of-line definition 55#if !(defined(__cplusplus) && (__cplusplus >= 201703L)) 56#define GSL_USE_STATIC_CONSTEXPR_WORKAROUND 57#endif // !(defined(__cplusplus) && (__cplusplus >= 201703L)) 58 59// GCC 7 does not like the signed unsigned missmatch (size_t ptrdiff_t) 60// While there is a conversion from signed to unsigned, it happens at 61// compiletime, so the compiler wouldn't have to warn indiscriminently, but 62// could check if the source value actually doesn't fit into the target type 63// and only warn in those cases. 64#if defined(__GNUC__) && __GNUC__ > 6 65#pragma GCC diagnostic push 66#pragma GCC diagnostic ignored "-Wsign-conversion" 67#endif 68 69namespace gsl 70{ 71 72// [views.constants], constants 73constexpr const std::ptrdiff_t dynamic_extent = -1; 74 75template <class ElementType, std::ptrdiff_t Extent = dynamic_extent> 76class span; 77 78// implementation details 79namespace details 80{ 81 template <class T> 82 struct is_span_oracle : std::false_type 83 { 84 }; 85 86 template <class ElementType, std::ptrdiff_t Extent> 87 struct is_span_oracle<gsl::span<ElementType, Extent>> : std::true_type 88 { 89 }; 90 91 template <class T> 92 struct is_span : public is_span_oracle<std::remove_cv_t<T>> 93 { 94 }; 95 96 template <class T> 97 struct is_std_array_oracle : std::false_type 98 { 99 }; 100 101 template <class ElementType, std::size_t Extent> 102 struct is_std_array_oracle<std::array<ElementType, Extent>> : std::true_type 103 { 104 }; 105 106 template <class T> 107 struct is_std_array : public is_std_array_oracle<std::remove_cv_t<T>> 108 { 109 }; 110 111 template <std::ptrdiff_t From, std::ptrdiff_t To> 112 struct is_allowed_extent_conversion 113 : public std::integral_constant<bool, From == To || From == gsl::dynamic_extent || 114 To == gsl::dynamic_extent> 115 { 116 }; 117 118 template <class From, class To> 119 struct is_allowed_element_type_conversion 120 : public std::integral_constant<bool, std::is_convertible<From (*)[], To (*)[]>::value> 121 { 122 }; 123 124 template <class Span, bool IsConst> 125 class span_iterator 126 { 127 using element_type_ = typename Span::element_type; 128 129 public: 130#ifdef _MSC_VER 131 // Tell Microsoft standard library that span_iterators are checked. 132 using _Unchecked_type = typename Span::pointer; 133#endif 134 135 using iterator_category = std::random_access_iterator_tag; 136 using value_type = std::remove_cv_t<element_type_>; 137 using difference_type = typename Span::index_type; 138 139 using reference = std::conditional_t<IsConst, const element_type_, element_type_>&; 140 using pointer = std::add_pointer_t<reference>; 141 142 span_iterator() = default; 143 144 constexpr span_iterator(const Span* span, typename Span::index_type idx) noexcept 145 : span_(span), index_(idx) 146 {} 147 148 friend span_iterator<Span, true>; 149 template <bool B, std::enable_if_t<!B && IsConst>* = nullptr> 150 constexpr span_iterator(const span_iterator<Span, B>& other) noexcept 151 : span_iterator(other.span_, other.index_) 152 {} 153 154 GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute 155 constexpr reference operator*() const 156 { 157 Expects(index_ != span_->size()); 158 return *(span_->data() + index_); 159 } 160 161 constexpr pointer operator->() const 162 { 163 Expects(index_ != span_->size()); 164 return span_->data() + index_; 165 } 166 167 constexpr span_iterator& operator++() 168 { 169 Expects(0 <= index_ && index_ != span_->size()); 170 ++index_; 171 return *this; 172 } 173 174 constexpr span_iterator operator++(int) 175 { 176 auto ret = *this; 177 ++(*this); 178 return ret; 179 } 180 181 constexpr span_iterator& operator--() 182 { 183 Expects(index_ != 0 && index_ <= span_->size()); 184 --index_; 185 return *this; 186 } 187 188 constexpr span_iterator operator--(int) 189 { 190 auto ret = *this; 191 --(*this); 192 return ret; 193 } 194 195 constexpr span_iterator operator+(difference_type n) const 196 { 197 auto ret = *this; 198 return ret += n; 199 } 200 201 friend constexpr span_iterator operator+(difference_type n, span_iterator const& rhs) 202 { 203 return rhs + n; 204 } 205 206 constexpr span_iterator& operator+=(difference_type n) 207 { 208 Expects((index_ + n) >= 0 && (index_ + n) <= span_->size()); 209 index_ += n; 210 return *this; 211 } 212 213 constexpr span_iterator operator-(difference_type n) const 214 { 215 auto ret = *this; 216 return ret -= n; 217 } 218 219 constexpr span_iterator& operator-=(difference_type n) { return *this += -n; } 220 221 constexpr difference_type operator-(span_iterator rhs) const 222 { 223 Expects(span_ == rhs.span_); 224 return index_ - rhs.index_; 225 } 226 227 constexpr reference operator[](difference_type n) const { return *(*this + n); } 228 229 constexpr friend bool operator==(span_iterator lhs, span_iterator rhs) noexcept 230 { 231 return lhs.span_ == rhs.span_ && lhs.index_ == rhs.index_; 232 } 233 234 constexpr friend bool operator!=(span_iterator lhs, span_iterator rhs) noexcept 235 { 236 return !(lhs == rhs); 237 } 238 239 constexpr friend bool operator<(span_iterator lhs, span_iterator rhs) noexcept 240 { 241 return lhs.index_ < rhs.index_; 242 } 243 244 constexpr friend bool operator<=(span_iterator lhs, span_iterator rhs) noexcept 245 { 246 return !(rhs < lhs); 247 } 248 249 constexpr friend bool operator>(span_iterator lhs, span_iterator rhs) noexcept 250 { 251 return rhs < lhs; 252 } 253 254 constexpr friend bool operator>=(span_iterator lhs, span_iterator rhs) noexcept 255 { 256 return !(rhs > lhs); 257 } 258 259#ifdef _MSC_VER 260 // MSVC++ iterator debugging support; allows STL algorithms in 15.8+ 261 // to unwrap span_iterator to a pointer type after a range check in STL 262 // algorithm calls 263 friend constexpr void _Verify_range(span_iterator lhs, span_iterator rhs) noexcept 264 { // test that [lhs, rhs) forms a valid range inside an STL algorithm 265 Expects(lhs.span_ == rhs.span_ // range spans have to match 266 && lhs.index_ <= rhs.index_); // range must not be transposed 267 } 268 269 constexpr void _Verify_offset(const difference_type n) const noexcept 270 { // test that the iterator *this + n is a valid range in an STL 271 // algorithm call 272 Expects((index_ + n) >= 0 && (index_ + n) <= span_->size()); 273 } 274 275 GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute 276 constexpr pointer _Unwrapped() const noexcept 277 { // after seeking *this to a high water mark, or using one of the 278 // _Verify_xxx functions above, unwrap this span_iterator to a raw 279 // pointer 280 return span_->data() + index_; 281 } 282 283 // Tell the STL that span_iterator should not be unwrapped if it can't 284 // validate in advance, even in release / optimized builds: 285#if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND) 286 static constexpr const bool _Unwrap_when_unverified = false; 287#else 288 static constexpr bool _Unwrap_when_unverified = false; 289#endif 290 GSL_SUPPRESS(con.3) // NO-FORMAT: attribute // TODO: false positive 291 constexpr void _Seek_to(const pointer p) noexcept 292 { // adjust the position of *this to previously verified location p 293 // after _Unwrapped 294 index_ = p - span_->data(); 295 } 296#endif 297 298 protected: 299 const Span* span_ = nullptr; 300 std::ptrdiff_t index_ = 0; 301 }; 302 303 template <std::ptrdiff_t Ext> 304 class extent_type 305 { 306 public: 307 using index_type = std::ptrdiff_t; 308 309 static_assert(Ext >= 0, "A fixed-size span must be >= 0 in size."); 310 311 constexpr extent_type() noexcept {} 312 313 template <index_type Other> 314 constexpr extent_type(extent_type<Other> ext) 315 { 316 static_assert(Other == Ext || Other == dynamic_extent, 317 "Mismatch between fixed-size extent and size of initializing data."); 318 Expects(ext.size() == Ext); 319 } 320 321 constexpr extent_type(index_type size) { Expects(size == Ext); } 322 323 constexpr index_type size() const noexcept { return Ext; } 324 }; 325 326 template <> 327 class extent_type<dynamic_extent> 328 { 329 public: 330 using index_type = std::ptrdiff_t; 331 332 template <index_type Other> 333 explicit constexpr extent_type(extent_type<Other> ext) : size_(ext.size()) 334 {} 335 336 explicit constexpr extent_type(index_type size) : size_(size) { Expects(size >= 0); } 337 338 constexpr index_type size() const noexcept { return size_; } 339 340 private: 341 index_type size_; 342 }; 343 344 template <class ElementType, std::ptrdiff_t Extent, std::ptrdiff_t Offset, std::ptrdiff_t Count> 345 struct calculate_subspan_type 346 { 347 using type = span<ElementType, Count != dynamic_extent 348 ? Count 349 : (Extent != dynamic_extent ? Extent - Offset : Extent)>; 350 }; 351} // namespace details 352 353// [span], class template span 354template <class ElementType, std::ptrdiff_t Extent> 355class span 356{ 357public: 358 // constants and types 359 using element_type = ElementType; 360 using value_type = std::remove_cv_t<ElementType>; 361 using index_type = std::ptrdiff_t; 362 using pointer = element_type*; 363 using reference = element_type&; 364 365 using iterator = details::span_iterator<span<ElementType, Extent>, false>; 366 using const_iterator = details::span_iterator<span<ElementType, Extent>, true>; 367 using reverse_iterator = std::reverse_iterator<iterator>; 368 using const_reverse_iterator = std::reverse_iterator<const_iterator>; 369 370 using size_type = index_type; 371 372#if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND) 373 static constexpr const index_type extent{Extent}; 374#else 375 static constexpr index_type extent{Extent}; 376#endif 377 378 // [span.cons], span constructors, copy, assignment, and destructor 379 template <bool Dependent = false, 380 // "Dependent" is needed to make "std::enable_if_t<Dependent || Extent <= 0>" SFINAE, 381 // since "std::enable_if_t<Extent <= 0>" is ill-formed when Extent is greater than 0. 382 class = std::enable_if_t<(Dependent || Extent <= 0)>> 383 constexpr span() noexcept : storage_(nullptr, details::extent_type<0>()) 384 {} 385 386 constexpr span(pointer ptr, index_type count) : storage_(ptr, count) {} 387 388 constexpr span(pointer firstElem, pointer lastElem) 389 : storage_(firstElem, std::distance(firstElem, lastElem)) 390 {} 391 392 template <std::size_t N> 393 constexpr span(element_type (&arr)[N]) noexcept 394 : storage_(KnownNotNull{std::addressof(arr[0])}, details::extent_type<N>()) 395 {} 396 397 template <std::size_t N, class = std::enable_if_t<(N > 0)>> 398 constexpr span(std::array<std::remove_const_t<element_type>, N>& arr) noexcept 399 : storage_(KnownNotNull{arr.data()}, details::extent_type<N>()) 400 { 401 } 402 403 constexpr span(std::array<std::remove_const_t<element_type>, 0>&) noexcept 404 : storage_(static_cast<pointer>(nullptr), details::extent_type<0>()) 405 { 406 } 407 408 template <std::size_t N, class = std::enable_if_t<(N > 0)>> 409 constexpr span(const std::array<std::remove_const_t<element_type>, N>& arr) noexcept 410 : storage_(KnownNotNull{arr.data()}, details::extent_type<N>()) 411 { 412 } 413 414 constexpr span(const std::array<std::remove_const_t<element_type>, 0>&) noexcept 415 : storage_(static_cast<pointer>(nullptr), details::extent_type<0>()) 416 { 417 } 418 419 // NB: the SFINAE here uses .data() as a incomplete/imperfect proxy for the requirement 420 // on Container to be a contiguous sequence container. 421 template <class Container, 422 class = std::enable_if_t< 423 !details::is_span<Container>::value && !details::is_std_array<Container>::value && 424 std::is_convertible<typename Container::pointer, pointer>::value && 425 std::is_convertible<typename Container::pointer, 426 decltype(std::declval<Container>().data())>::value>> 427 constexpr span(Container& cont) : span(cont.data(), narrow<index_type>(cont.size())) 428 {} 429 430 template <class Container, 431 class = std::enable_if_t< 432 std::is_const<element_type>::value && !details::is_span<Container>::value && 433 std::is_convertible<typename Container::pointer, pointer>::value && 434 std::is_convertible<typename Container::pointer, 435 decltype(std::declval<Container>().data())>::value>> 436 constexpr span(const Container& cont) : span(cont.data(), narrow<index_type>(cont.size())) 437 {} 438 439 constexpr span(const span& other) noexcept = default; 440 441 template < 442 class OtherElementType, std::ptrdiff_t OtherExtent, 443 class = std::enable_if_t< 444 details::is_allowed_extent_conversion<OtherExtent, Extent>::value && 445 details::is_allowed_element_type_conversion<OtherElementType, element_type>::value>> 446 constexpr span(const span<OtherElementType, OtherExtent>& other) 447 : storage_(other.data(), details::extent_type<OtherExtent>(other.size())) 448 {} 449 450 ~span() noexcept = default; 451 constexpr span& operator=(const span& other) noexcept = default; 452 453 // [span.sub], span subviews 454 template <std::ptrdiff_t Count> 455 constexpr span<element_type, Count> first() const 456 { 457 Expects(Count >= 0 && Count <= size()); 458 return {data(), Count}; 459 } 460 461 template <std::ptrdiff_t Count> 462 GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute 463 constexpr span<element_type, Count> last() const 464 { 465 Expects(Count >= 0 && size() - Count >= 0); 466 return {data() + (size() - Count), Count}; 467 } 468 469 template <std::ptrdiff_t Offset, std::ptrdiff_t Count = dynamic_extent> 470 GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute 471 constexpr auto subspan() const -> 472 typename details::calculate_subspan_type<ElementType, Extent, Offset, Count>::type 473 { 474 Expects((Offset >= 0 && size() - Offset >= 0) && 475 (Count == dynamic_extent || (Count >= 0 && Offset + Count <= size()))); 476 477 return {data() + Offset, Count == dynamic_extent ? size() - Offset : Count}; 478 } 479 480 constexpr span<element_type, dynamic_extent> first(index_type count) const 481 { 482 Expects(count >= 0 && count <= size()); 483 return {data(), count}; 484 } 485 486 constexpr span<element_type, dynamic_extent> last(index_type count) const 487 { 488 return make_subspan(size() - count, dynamic_extent, subspan_selector<Extent>{}); 489 } 490 491 constexpr span<element_type, dynamic_extent> subspan(index_type offset, 492 index_type count = dynamic_extent) const 493 { 494 return make_subspan(offset, count, subspan_selector<Extent>{}); 495 } 496 497 // [span.obs], span observers 498 constexpr index_type size() const noexcept { return storage_.size(); } 499 constexpr index_type size_bytes() const noexcept 500 { 501 return size() * narrow_cast<index_type>(sizeof(element_type)); 502 } 503 constexpr bool empty() const noexcept { return size() == 0; } 504 505 // [span.elem], span element access 506 GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute 507 constexpr reference operator[](index_type idx) const 508 { 509 Expects(CheckRange(idx, storage_.size())); 510 return data()[idx]; 511 } 512 513 constexpr reference at(index_type idx) const { return this->operator[](idx); } 514 constexpr reference operator()(index_type idx) const { return this->operator[](idx); } 515 constexpr pointer data() const noexcept { return storage_.data(); } 516 517 // [span.iter], span iterator support 518 constexpr iterator begin() const noexcept { return {this, 0}; } 519 constexpr iterator end() const noexcept { return {this, size()}; } 520 521 constexpr const_iterator cbegin() const noexcept { return {this, 0}; } 522 constexpr const_iterator cend() const noexcept { return {this, size()}; } 523 524 constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator{end()}; } 525 constexpr reverse_iterator rend() const noexcept { return reverse_iterator{begin()}; } 526 527 constexpr const_reverse_iterator crbegin() const noexcept 528 { 529 return const_reverse_iterator{cend()}; 530 } 531 constexpr const_reverse_iterator crend() const noexcept 532 { 533 return const_reverse_iterator{cbegin()}; 534 } 535 536#ifdef _MSC_VER 537 // Tell MSVC how to unwrap spans in range-based-for 538 constexpr pointer _Unchecked_begin() const noexcept { return data(); } 539 constexpr pointer _Unchecked_end() const noexcept 540 { 541 GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute 542 return data() + size(); 543 } 544#endif // _MSC_VER 545 546private: 547 static constexpr bool CheckRange(index_type idx, index_type size) noexcept 548 { 549 // Optimization: 550 // 551 // idx >= 0 && idx < size 552 // => 553 // static_cast<size_t>(idx) < static_cast<size_t>(size) 554 // 555 // because size >=0 by span construction, and negative idx will 556 // wrap around to a value always greater than size when casted. 557 558 // check if we have enough space to wrap around 559#if defined(__cpp_if_constexpr) 560 if constexpr (sizeof(index_type) <= sizeof(size_t)) 561#else 562 if (sizeof(index_type) <= sizeof(size_t)) 563#endif 564 { 565 return narrow_cast<size_t>(idx) < narrow_cast<size_t>(size); 566 } 567 else 568 { 569 return idx >= 0 && idx < size; 570 } 571 } 572 573 // Needed to remove unnecessary null check in subspans 574 struct KnownNotNull 575 { 576 pointer p; 577 }; 578 579 // this implementation detail class lets us take advantage of the 580 // empty base class optimization to pay for only storage of a single 581 // pointer in the case of fixed-size spans 582 template <class ExtentType> 583 class storage_type : public ExtentType 584 { 585 public: 586 // KnownNotNull parameter is needed to remove unnecessary null check 587 // in subspans and constructors from arrays 588 template <class OtherExtentType> 589 constexpr storage_type(KnownNotNull data, OtherExtentType ext) 590 : ExtentType(ext), data_(data.p) 591 { 592 Expects(ExtentType::size() >= 0); 593 } 594 595 template <class OtherExtentType> 596 constexpr storage_type(pointer data, OtherExtentType ext) : ExtentType(ext), data_(data) 597 { 598 Expects(ExtentType::size() >= 0); 599 Expects(data || ExtentType::size() == 0); 600 } 601 602 constexpr pointer data() const noexcept { return data_; } 603 604 private: 605 pointer data_; 606 }; 607 608 storage_type<details::extent_type<Extent>> storage_; 609 610 // The rest is needed to remove unnecessary null check 611 // in subspans and constructors from arrays 612 constexpr span(KnownNotNull ptr, index_type count) : storage_(ptr, count) {} 613 614 template <std::ptrdiff_t CallerExtent> 615 class subspan_selector 616 { 617 }; 618 619 template <std::ptrdiff_t CallerExtent> 620 span<element_type, dynamic_extent> make_subspan(index_type offset, index_type count, 621 subspan_selector<CallerExtent>) const 622 { 623 const span<element_type, dynamic_extent> tmp(*this); 624 return tmp.subspan(offset, count); 625 } 626 627 GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute 628 span<element_type, dynamic_extent> make_subspan(index_type offset, index_type count, 629 subspan_selector<dynamic_extent>) const 630 { 631 Expects(offset >= 0 && size() - offset >= 0); 632 633 if (count == dynamic_extent) { return {KnownNotNull{data() + offset}, size() - offset}; } 634 635 Expects(count >= 0 && size() - offset >= count); 636 return {KnownNotNull{data() + offset}, count}; 637 } 638}; 639 640#if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND) 641template <class ElementType, std::ptrdiff_t Extent> 642constexpr const typename span<ElementType, Extent>::index_type span<ElementType, Extent>::extent; 643#endif 644 645// [span.comparison], span comparison operators 646template <class ElementType, std::ptrdiff_t FirstExtent, std::ptrdiff_t SecondExtent> 647constexpr bool operator==(span<ElementType, FirstExtent> l, span<ElementType, SecondExtent> r) 648{ 649 return std::equal(l.begin(), l.end(), r.begin(), r.end()); 650} 651 652template <class ElementType, std::ptrdiff_t Extent> 653constexpr bool operator!=(span<ElementType, Extent> l, span<ElementType, Extent> r) 654{ 655 return !(l == r); 656} 657 658template <class ElementType, std::ptrdiff_t Extent> 659constexpr bool operator<(span<ElementType, Extent> l, span<ElementType, Extent> r) 660{ 661 return std::lexicographical_compare(l.begin(), l.end(), r.begin(), r.end()); 662} 663 664template <class ElementType, std::ptrdiff_t Extent> 665constexpr bool operator<=(span<ElementType, Extent> l, span<ElementType, Extent> r) 666{ 667 return !(l > r); 668} 669 670template <class ElementType, std::ptrdiff_t Extent> 671constexpr bool operator>(span<ElementType, Extent> l, span<ElementType, Extent> r) 672{ 673 return r < l; 674} 675 676template <class ElementType, std::ptrdiff_t Extent> 677constexpr bool operator>=(span<ElementType, Extent> l, span<ElementType, Extent> r) 678{ 679 return !(l < r); 680} 681 682namespace details 683{ 684 // if we only supported compilers with good constexpr support then 685 // this pair of classes could collapse down to a constexpr function 686 687 // we should use a narrow_cast<> to go to std::size_t, but older compilers may not see it as 688 // constexpr 689 // and so will fail compilation of the template 690 template <class ElementType, std::ptrdiff_t Extent> 691 struct calculate_byte_size 692 : std::integral_constant<std::ptrdiff_t, 693 static_cast<std::ptrdiff_t>(sizeof(ElementType) * 694 static_cast<std::size_t>(Extent))> 695 { 696 }; 697 698 template <class ElementType> 699 struct calculate_byte_size<ElementType, dynamic_extent> 700 : std::integral_constant<std::ptrdiff_t, dynamic_extent> 701 { 702 }; 703} // namespace details 704 705// [span.objectrep], views of object representation 706template <class ElementType, std::ptrdiff_t Extent> 707span<const byte, details::calculate_byte_size<ElementType, Extent>::value> 708as_bytes(span<ElementType, Extent> s) noexcept 709{ 710 GSL_SUPPRESS(type.1) // NO-FORMAT: attribute 711 return {reinterpret_cast<const byte*>(s.data()), s.size_bytes()}; 712} 713 714template <class ElementType, std::ptrdiff_t Extent, 715 class = std::enable_if_t<!std::is_const<ElementType>::value>> 716span<byte, details::calculate_byte_size<ElementType, Extent>::value> 717as_writeable_bytes(span<ElementType, Extent> s) noexcept 718{ 719 GSL_SUPPRESS(type.1) // NO-FORMAT: attribute 720 return {reinterpret_cast<byte*>(s.data()), s.size_bytes()}; 721} 722 723// 724// make_span() - Utility functions for creating spans 725// 726template <class ElementType> 727constexpr span<ElementType> make_span(ElementType* ptr, 728 typename span<ElementType>::index_type count) 729{ 730 return span<ElementType>(ptr, count); 731} 732 733template <class ElementType> 734constexpr span<ElementType> make_span(ElementType* firstElem, ElementType* lastElem) 735{ 736 return span<ElementType>(firstElem, lastElem); 737} 738 739template <class ElementType, std::size_t N> 740constexpr span<ElementType, N> make_span(ElementType (&arr)[N]) noexcept 741{ 742 return span<ElementType, N>(arr); 743} 744 745template <class Container> 746constexpr span<typename Container::value_type> make_span(Container& cont) 747{ 748 return span<typename Container::value_type>(cont); 749} 750 751template <class Container> 752constexpr span<const typename Container::value_type> make_span(const Container& cont) 753{ 754 return span<const typename Container::value_type>(cont); 755} 756 757template <class Ptr> 758constexpr span<typename Ptr::element_type> make_span(Ptr& cont, std::ptrdiff_t count) 759{ 760 return span<typename Ptr::element_type>(cont, count); 761} 762 763template <class Ptr> 764constexpr span<typename Ptr::element_type> make_span(Ptr& cont) 765{ 766 return span<typename Ptr::element_type>(cont); 767} 768 769// Specialization of gsl::at for span 770template <class ElementType, std::ptrdiff_t Extent> 771constexpr ElementType& at(span<ElementType, Extent> s, index i) 772{ 773 // No bounds checking here because it is done in span::operator[] called below 774 return s[i]; 775} 776 777} // namespace gsl 778 779#if defined(_MSC_VER) && !defined(__clang__) 780#if _MSC_VER < 1910 781#undef constexpr 782#pragma pop_macro("constexpr") 783 784#endif // _MSC_VER < 1910 785 786#pragma warning(pop) 787#endif // _MSC_VER 788 789#if defined(__GNUC__) && __GNUC__ > 6 790#pragma GCC diagnostic pop 791#endif // __GNUC__ > 6 792 793#endif // GSL_SPAN_H 794