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#pragma once 18 19#ifndef GSL_SPAN_H 20#define GSL_SPAN_H 21 22#include <gsl/gsl_assert> 23#include <gsl/gsl_byte> 24#include <gsl/gsl_util> 25 26#include <array> 27#include <iterator> 28#include <limits> 29#include <memory> 30#include <stdexcept> 31#include <type_traits> 32#include <utility> 33 34#ifdef _MSC_VER 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// blanket turn off warnings from CppCoreCheck for now 42// so people aren't annoyed by them when running the tool. 43// more targeted suppressions will be added in a future update to the GSL 44#pragma warning(disable : 26481 26482 26483 26485 26490 26491 26492 26493 26495) 45 46#if _MSC_VER < 1910 47#pragma push_macro("constexpr") 48#define constexpr /*constexpr*/ 49 50#endif // _MSC_VER < 1910 51#endif // _MSC_VER 52 53#ifdef GSL_THROW_ON_CONTRACT_VIOLATION 54#define GSL_NOEXCEPT /*noexcept*/ 55#else 56#define GSL_NOEXCEPT noexcept 57#endif // GSL_THROW_ON_CONTRACT_VIOLATION 58 59namespace gsl 60{ 61 62// [views.constants], constants 63constexpr const std::ptrdiff_t dynamic_extent = -1; 64 65template <class ElementType, std::ptrdiff_t Extent = dynamic_extent> 66class span; 67 68// implementation details 69namespace details 70{ 71 template <class T> 72 struct is_span_oracle : std::false_type 73 { 74 }; 75 76 template <class ElementType, std::ptrdiff_t Extent> 77 struct is_span_oracle<gsl::span<ElementType, Extent>> : std::true_type 78 { 79 }; 80 81 template <class T> 82 struct is_span : public is_span_oracle<std::remove_cv_t<T>> 83 { 84 }; 85 86 template <class T> 87 struct is_std_array_oracle : std::false_type 88 { 89 }; 90 91 template <class ElementType, std::size_t Extent> 92 struct is_std_array_oracle<std::array<ElementType, Extent>> : std::true_type 93 { 94 }; 95 96 template <class T> 97 struct is_std_array : public is_std_array_oracle<std::remove_cv_t<T>> 98 { 99 }; 100 101 template <std::ptrdiff_t From, std::ptrdiff_t To> 102 struct is_allowed_extent_conversion 103 : public std::integral_constant<bool, From == To || From == gsl::dynamic_extent || 104 To == gsl::dynamic_extent> 105 { 106 }; 107 108 template <class From, class To> 109 struct is_allowed_element_type_conversion 110 : public std::integral_constant<bool, std::is_convertible<From (*)[], To (*)[]>::value> 111 { 112 }; 113 114 template <class Span, bool IsConst> 115 class span_iterator 116 { 117 using element_type_ = typename Span::element_type; 118 119 public: 120 using iterator_category = std::random_access_iterator_tag; 121 using value_type = std::remove_cv_t<element_type_>; 122 using difference_type = typename Span::index_type; 123 124 using reference = std::conditional_t<IsConst, const element_type_, element_type_>&; 125 using pointer = std::add_pointer_t<reference>; 126 127 span_iterator() = default; 128 129 constexpr span_iterator(const Span* span, typename Span::index_type index) GSL_NOEXCEPT 130 : span_(span), index_(index) 131 { 132 Expects(span == nullptr || (index_ >= 0 && index <= span_->length())); 133 } 134 135 friend span_iterator<Span, true>; 136 template<bool B, std::enable_if_t<!B && IsConst>* = nullptr> 137 constexpr span_iterator(const span_iterator<Span, B>& other) GSL_NOEXCEPT 138 : span_iterator(other.span_, other.index_) 139 { 140 } 141 142 constexpr reference operator*() const GSL_NOEXCEPT 143 { 144 Expects(span_); 145 return (*span_)[index_]; 146 } 147 148 constexpr pointer operator->() const GSL_NOEXCEPT 149 { 150 Expects(span_ && index_ >= 0 && index_ < span_->length()); 151 return span_->data() + index_; 152 } 153 154 constexpr span_iterator& operator++() GSL_NOEXCEPT 155 { 156 Expects(span_ && index_ >= 0 && index_ < span_->length()); 157 ++index_; 158 return *this; 159 } 160 161 constexpr span_iterator operator++(int) GSL_NOEXCEPT 162 { 163 auto ret = *this; 164 ++(*this); 165 return ret; 166 } 167 168 constexpr span_iterator& operator--() GSL_NOEXCEPT 169 { 170 Expects(span_ && index_ > 0 && index_ <= span_->length()); 171 --index_; 172 return *this; 173 } 174 175 constexpr span_iterator operator--(int) GSL_NOEXCEPT 176 { 177 auto ret = *this; 178 --(*this); 179 return ret; 180 } 181 182 constexpr span_iterator operator+(difference_type n) const GSL_NOEXCEPT 183 { 184 auto ret = *this; 185 return ret += n; 186 } 187 188 constexpr span_iterator& operator+=(difference_type n) GSL_NOEXCEPT 189 { 190 Expects(span_ && (index_ + n) >= 0 && (index_ + n) <= span_->length()); 191 index_ += n; 192 return *this; 193 } 194 195 constexpr span_iterator operator-(difference_type n) const GSL_NOEXCEPT 196 { 197 auto ret = *this; 198 return ret -= n; 199 } 200 201 constexpr span_iterator& operator-=(difference_type n) GSL_NOEXCEPT { return *this += -n; } 202 203 constexpr difference_type operator-(const span_iterator& rhs) const GSL_NOEXCEPT 204 { 205 Expects(span_ == rhs.span_); 206 return index_ - rhs.index_; 207 } 208 209 constexpr reference operator[](difference_type n) const GSL_NOEXCEPT 210 { 211 return *(*this + n); 212 } 213 214 constexpr friend bool operator==(const span_iterator& lhs, 215 const span_iterator& rhs) GSL_NOEXCEPT 216 { 217 return lhs.span_ == rhs.span_ && lhs.index_ == rhs.index_; 218 } 219 220 constexpr friend bool operator!=(const span_iterator& lhs, 221 const span_iterator& rhs) GSL_NOEXCEPT 222 { 223 return !(lhs == rhs); 224 } 225 226 constexpr friend bool operator<(const span_iterator& lhs, 227 const span_iterator& rhs) GSL_NOEXCEPT 228 { 229 Expects(lhs.span_ == rhs.span_); 230 return lhs.index_ < rhs.index_; 231 } 232 233 constexpr friend bool operator<=(const span_iterator& lhs, 234 const span_iterator& rhs) GSL_NOEXCEPT 235 { 236 return !(rhs < lhs); 237 } 238 239 constexpr friend bool operator>(const span_iterator& lhs, 240 const span_iterator& rhs) GSL_NOEXCEPT 241 { 242 return rhs < lhs; 243 } 244 245 constexpr friend bool operator>=(const span_iterator& lhs, 246 const span_iterator& rhs) GSL_NOEXCEPT 247 { 248 return !(rhs > lhs); 249 } 250 251 protected: 252 const Span* span_ = nullptr; 253 std::ptrdiff_t index_ = 0; 254 }; 255 256 template <class Span, bool IsConst> 257 inline constexpr span_iterator<Span, IsConst> 258 operator+(typename span_iterator<Span, IsConst>::difference_type n, 259 const span_iterator<Span, IsConst>& rhs) GSL_NOEXCEPT 260 { 261 return rhs + n; 262 } 263 264 template <class Span, bool IsConst> 265 inline constexpr span_iterator<Span, IsConst> 266 operator-(typename span_iterator<Span, IsConst>::difference_type n, 267 const span_iterator<Span, IsConst>& rhs) GSL_NOEXCEPT 268 { 269 return rhs - n; 270 } 271 272 template <std::ptrdiff_t Ext> 273 class extent_type 274 { 275 public: 276 using index_type = std::ptrdiff_t; 277 278 static_assert(Ext >= 0, "A fixed-size span must be >= 0 in size."); 279 280 constexpr extent_type() GSL_NOEXCEPT {} 281 282 template <index_type Other> 283 constexpr extent_type(extent_type<Other> ext) 284 { 285 static_assert(Other == Ext || Other == dynamic_extent, 286 "Mismatch between fixed-size extent and size of initializing data."); 287 Expects(ext.size() == Ext); 288 } 289 290 constexpr extent_type(index_type size) { Expects(size == Ext); } 291 292 constexpr index_type size() const GSL_NOEXCEPT { return Ext; } 293 }; 294 295 template <> 296 class extent_type<dynamic_extent> 297 { 298 public: 299 using index_type = std::ptrdiff_t; 300 301 template <index_type Other> 302 explicit constexpr extent_type(extent_type<Other> ext) : size_(ext.size()) 303 { 304 } 305 306 explicit constexpr extent_type(index_type size) : size_(size) { Expects(size >= 0); } 307 308 constexpr index_type size() const GSL_NOEXCEPT { return size_; } 309 310 private: 311 index_type size_; 312 }; 313} // namespace details 314 315// [span], class template span 316template <class ElementType, std::ptrdiff_t Extent> 317class span 318{ 319public: 320 // constants and types 321 using element_type = ElementType; 322 using value_type = std::remove_cv_t<ElementType>; 323 using index_type = std::ptrdiff_t; 324 using pointer = element_type*; 325 using reference = element_type&; 326 327 using iterator = details::span_iterator<span<ElementType, Extent>, false>; 328 using const_iterator = details::span_iterator<span<ElementType, Extent>, true>; 329 using reverse_iterator = std::reverse_iterator<iterator>; 330 using const_reverse_iterator = std::reverse_iterator<const_iterator>; 331 332 using size_type = index_type; 333 334 constexpr static const index_type extent = Extent; 335 336 // [span.cons], span constructors, copy, assignment, and destructor 337 template <bool Dependent = false, 338 // "Dependent" is needed to make "std::enable_if_t<Dependent || Extent <= 0>" SFINAE, 339 // since "std::enable_if_t<Extent <= 0>" is ill-formed when Extent is greater than 0. 340 class = std::enable_if_t<(Dependent || Extent <= 0)>> 341 constexpr span() GSL_NOEXCEPT : storage_(nullptr, details::extent_type<0>()) 342 { 343 } 344 345 constexpr span(std::nullptr_t) GSL_NOEXCEPT : span() {} 346 347 constexpr span(pointer ptr, index_type count) : storage_(ptr, count) {} 348 349 constexpr span(pointer firstElem, pointer lastElem) 350 : storage_(firstElem, std::distance(firstElem, lastElem)) 351 { 352 } 353 354 template <std::size_t N> 355 constexpr span(element_type (&arr)[N]) GSL_NOEXCEPT 356 : storage_(&arr[0], details::extent_type<N>()) 357 { 358 } 359 360 template <std::size_t N, class ArrayElementType = std::remove_const_t<element_type>> 361 constexpr span(std::array<ArrayElementType, N>& arr) GSL_NOEXCEPT 362 : storage_(&arr[0], details::extent_type<N>()) 363 { 364 } 365 366 template <std::size_t N> 367 constexpr span(const std::array<std::remove_const_t<element_type>, N>& arr) GSL_NOEXCEPT 368 : storage_(&arr[0], details::extent_type<N>()) 369 { 370 } 371 372 template <class ArrayElementType = std::add_pointer<element_type>> 373 constexpr span(const std::unique_ptr<ArrayElementType>& ptr, index_type count) 374 : storage_(ptr.get(), count) 375 { 376 } 377 378 constexpr span(const std::unique_ptr<ElementType>& ptr) : storage_(ptr.get(), ptr.get() ? 1 : 0) 379 { 380 } 381 constexpr span(const std::shared_ptr<ElementType>& ptr) : storage_(ptr.get(), ptr.get() ? 1 : 0) 382 { 383 } 384 385 // NB: the SFINAE here uses .data() as a incomplete/imperfect proxy for the requirement 386 // on Container to be a contiguous sequence container. 387 template <class Container, 388 class = std::enable_if_t< 389 !details::is_span<Container>::value && !details::is_std_array<Container>::value && 390 std::is_convertible<typename Container::pointer, pointer>::value && 391 std::is_convertible<typename Container::pointer, 392 decltype(std::declval<Container>().data())>::value>> 393 constexpr span(Container& cont) : span(cont.data(), narrow<index_type>(cont.size())) 394 { 395 } 396 397 template <class Container, 398 class = std::enable_if_t< 399 std::is_const<element_type>::value && !details::is_span<Container>::value && 400 std::is_convertible<typename Container::pointer, pointer>::value && 401 std::is_convertible<typename Container::pointer, 402 decltype(std::declval<Container>().data())>::value>> 403 constexpr span(const Container& cont) : span(cont.data(), narrow<index_type>(cont.size())) 404 { 405 } 406 407 constexpr span(const span& other) GSL_NOEXCEPT = default; 408 constexpr span(span&& other) GSL_NOEXCEPT = default; 409 410 template < 411 class OtherElementType, std::ptrdiff_t OtherExtent, 412 class = std::enable_if_t< 413 details::is_allowed_extent_conversion<OtherExtent, Extent>::value && 414 details::is_allowed_element_type_conversion<OtherElementType, element_type>::value>> 415 constexpr span(const span<OtherElementType, OtherExtent>& other) 416 : storage_(other.data(), details::extent_type<OtherExtent>(other.size())) 417 { 418 } 419 420 template < 421 class OtherElementType, std::ptrdiff_t OtherExtent, 422 class = std::enable_if_t< 423 details::is_allowed_extent_conversion<OtherExtent, Extent>::value && 424 details::is_allowed_element_type_conversion<OtherElementType, element_type>::value>> 425 constexpr span(span<OtherElementType, OtherExtent>&& other) 426 : storage_(other.data(), details::extent_type<OtherExtent>(other.size())) 427 { 428 } 429 430 ~span() GSL_NOEXCEPT = default; 431 constexpr span& operator=(const span& other) GSL_NOEXCEPT = default; 432 433 constexpr span& operator=(span&& other) GSL_NOEXCEPT = default; 434 435 // [span.sub], span subviews 436 template <std::ptrdiff_t Count> 437 constexpr span<element_type, Count> first() const 438 { 439 Expects(Count >= 0 && Count <= size()); 440 return {data(), Count}; 441 } 442 443 template <std::ptrdiff_t Count> 444 constexpr span<element_type, Count> last() const 445 { 446 Expects(Count >= 0 && Count <= size()); 447 return {data() + (size() - Count), Count}; 448 } 449 450 template <std::ptrdiff_t Offset, std::ptrdiff_t Count = dynamic_extent> 451 constexpr span<element_type, Count> subspan() const 452 { 453 Expects((Offset == 0 || (Offset > 0 && Offset <= size())) && 454 (Count == dynamic_extent || (Count >= 0 && Offset + Count <= size()))); 455 return {data() + Offset, Count == dynamic_extent ? size() - Offset : Count}; 456 } 457 458 constexpr span<element_type, dynamic_extent> first(index_type count) const 459 { 460 Expects(count >= 0 && count <= size()); 461 return {data(), count}; 462 } 463 464 constexpr span<element_type, dynamic_extent> last(index_type count) const 465 { 466 Expects(count >= 0 && count <= size()); 467 return {data() + (size() - count), count}; 468 } 469 470 constexpr span<element_type, dynamic_extent> subspan(index_type offset, 471 index_type count = dynamic_extent) const 472 { 473 Expects((offset == 0 || (offset > 0 && offset <= size())) && 474 (count == dynamic_extent || (count >= 0 && offset + count <= size()))); 475 return {data() + offset, count == dynamic_extent ? size() - offset : count}; 476 } 477 478 // [span.obs], span observers 479 constexpr index_type length() const GSL_NOEXCEPT { return size(); } 480 constexpr index_type size() const GSL_NOEXCEPT { return storage_.size(); } 481 constexpr index_type length_bytes() const GSL_NOEXCEPT { return size_bytes(); } 482 constexpr index_type size_bytes() const GSL_NOEXCEPT 483 { 484 return size() * narrow_cast<index_type>(sizeof(element_type)); 485 } 486 constexpr bool empty() const GSL_NOEXCEPT { return size() == 0; } 487 488 // [span.elem], span element access 489 constexpr reference operator[](index_type idx) const 490 { 491 Expects(idx >= 0 && idx < storage_.size()); 492 return data()[idx]; 493 } 494 495 constexpr reference at(index_type idx) const { return this->operator[](idx); } 496 constexpr reference operator()(index_type idx) const { return this->operator[](idx); } 497 constexpr pointer data() const GSL_NOEXCEPT { return storage_.data(); } 498 499 // [span.iter], span iterator support 500 iterator begin() const GSL_NOEXCEPT { return {this, 0}; } 501 iterator end() const GSL_NOEXCEPT { return {this, length()}; } 502 503 const_iterator cbegin() const GSL_NOEXCEPT { return {this, 0}; } 504 const_iterator cend() const GSL_NOEXCEPT { return {this, length()}; } 505 506 reverse_iterator rbegin() const GSL_NOEXCEPT { return reverse_iterator{end()}; } 507 reverse_iterator rend() const GSL_NOEXCEPT { return reverse_iterator{begin()}; } 508 509 const_reverse_iterator crbegin() const GSL_NOEXCEPT { return const_reverse_iterator{cend()}; } 510 const_reverse_iterator crend() const GSL_NOEXCEPT { return const_reverse_iterator{cbegin()}; } 511 512private: 513 // this implementation detail class lets us take advantage of the 514 // empty base class optimization to pay for only storage of a single 515 // pointer in the case of fixed-size spans 516 template <class ExtentType> 517 class storage_type : public ExtentType 518 { 519 public: 520 template <class OtherExtentType> 521 constexpr storage_type(pointer data, OtherExtentType ext) : ExtentType(ext), data_(data) 522 { 523 Expects((!data && ExtentType::size() == 0) || (data && ExtentType::size() >= 0)); 524 } 525 526 constexpr pointer data() const GSL_NOEXCEPT { return data_; } 527 528 private: 529 pointer data_; 530 }; 531 532 storage_type<details::extent_type<Extent>> storage_; 533}; 534 535// [span.comparison], span comparison operators 536template <class ElementType, std::ptrdiff_t FirstExtent, std::ptrdiff_t SecondExtent> 537inline constexpr bool operator==(const span<ElementType, FirstExtent>& l, 538 const span<ElementType, SecondExtent>& r) 539{ 540 return std::equal(l.begin(), l.end(), r.begin(), r.end()); 541} 542 543template <class ElementType, std::ptrdiff_t Extent> 544inline constexpr bool operator!=(const span<ElementType, Extent>& l, 545 const span<ElementType, Extent>& r) 546{ 547 return !(l == r); 548} 549 550template <class ElementType, std::ptrdiff_t Extent> 551inline constexpr bool operator<(const span<ElementType, Extent>& l, 552 const span<ElementType, Extent>& r) 553{ 554 return std::lexicographical_compare(l.begin(), l.end(), r.begin(), r.end()); 555} 556 557template <class ElementType, std::ptrdiff_t Extent> 558inline constexpr bool operator<=(const span<ElementType, Extent>& l, 559 const span<ElementType, Extent>& r) 560{ 561 return !(l > r); 562} 563 564template <class ElementType, std::ptrdiff_t Extent> 565inline constexpr bool operator>(const span<ElementType, Extent>& l, 566 const span<ElementType, Extent>& r) 567{ 568 return r < l; 569} 570 571template <class ElementType, std::ptrdiff_t Extent> 572inline constexpr bool operator>=(const span<ElementType, Extent>& l, 573 const span<ElementType, Extent>& r) 574{ 575 return !(l < r); 576} 577 578namespace details 579{ 580 // if we only supported compilers with good constexpr support then 581 // this pair of classes could collapse down to a constexpr function 582 583 // we should use a narrow_cast<> to go to std::size_t, but older compilers may not see it as 584 // constexpr 585 // and so will fail compilation of the template 586 template <class ElementType, std::ptrdiff_t Extent> 587 struct calculate_byte_size 588 : std::integral_constant<std::ptrdiff_t, 589 static_cast<std::ptrdiff_t>(sizeof(ElementType) * 590 static_cast<std::size_t>(Extent))> 591 { 592 }; 593 594 template <class ElementType> 595 struct calculate_byte_size<ElementType, dynamic_extent> 596 : std::integral_constant<std::ptrdiff_t, dynamic_extent> 597 { 598 }; 599} 600 601// [span.objectrep], views of object representation 602template <class ElementType, std::ptrdiff_t Extent> 603span<const byte, details::calculate_byte_size<ElementType, Extent>::value> 604as_bytes(span<ElementType, Extent> s) GSL_NOEXCEPT 605{ 606 return {reinterpret_cast<const byte*>(s.data()), s.size_bytes()}; 607} 608 609template <class ElementType, std::ptrdiff_t Extent, 610 class = std::enable_if_t<!std::is_const<ElementType>::value>> 611span<byte, details::calculate_byte_size<ElementType, Extent>::value> 612as_writeable_bytes(span<ElementType, Extent> s) GSL_NOEXCEPT 613{ 614 return {reinterpret_cast<byte*>(s.data()), s.size_bytes()}; 615} 616 617// 618// make_span() - Utility functions for creating spans 619// 620template <class ElementType> 621span<ElementType> make_span(ElementType* ptr, typename span<ElementType>::index_type count) 622{ 623 return span<ElementType>(ptr, count); 624} 625 626template <class ElementType> 627span<ElementType> make_span(ElementType* firstElem, ElementType* lastElem) 628{ 629 return span<ElementType>(firstElem, lastElem); 630} 631 632template <class ElementType, std::size_t N> 633span<ElementType, N> make_span(ElementType (&arr)[N]) 634{ 635 return span<ElementType, N>(arr); 636} 637 638template <class Container> 639span<typename Container::value_type> make_span(Container& cont) 640{ 641 return span<typename Container::value_type>(cont); 642} 643 644template <class Container> 645span<const typename Container::value_type> make_span(const Container& cont) 646{ 647 return span<const typename Container::value_type>(cont); 648} 649 650template <class Ptr> 651span<typename Ptr::element_type> make_span(Ptr& cont, std::ptrdiff_t count) 652{ 653 return span<typename Ptr::element_type>(cont, count); 654} 655 656template <class Ptr> 657span<typename Ptr::element_type> make_span(Ptr& cont) 658{ 659 return span<typename Ptr::element_type>(cont); 660} 661 662// Specialization of gsl::at for span 663template <class ElementType, std::ptrdiff_t Extent> 664inline constexpr ElementType& at(const span<ElementType, Extent>& s, std::ptrdiff_t index) 665{ 666 // No bounds checking here because it is done in span::operator[] called below 667 return s[index]; 668} 669 670} // namespace gsl 671 672#undef GSL_NOEXCEPT 673 674#ifdef _MSC_VER 675#if _MSC_VER < 1910 676#undef constexpr 677#pragma pop_macro("constexpr") 678 679#endif // _MSC_VER < 1910 680 681#pragma warning(pop) 682#endif // _MSC_VER 683 684#endif // GSL_SPAN_H 685