Warning, /include/gsl/span is written in an unsupported language. File is not indexed.
0001 ///////////////////////////////////////////////////////////////////////////////
0002 //
0003 // Copyright (c) 2015 Microsoft Corporation. All rights reserved.
0004 //
0005 // This code is licensed under the MIT License (MIT).
0006 //
0007 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0008 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0009 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
0010 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
0011 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
0012 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
0013 // THE SOFTWARE.
0014 //
0015 ///////////////////////////////////////////////////////////////////////////////
0016
0017 #ifndef GSL_SPAN_H
0018 #define GSL_SPAN_H
0019
0020 #include "./assert" // for Expects
0021 #include "./byte" // for gsl::impl::byte
0022 #include "./span_ext" // for span specialization of gsl::at and other span-related extensions
0023 #include "./util" // for narrow_cast
0024
0025 #include <array> // for array
0026 #include <cstddef> // for ptrdiff_t, size_t, nullptr_t
0027 #include <iterator> // for reverse_iterator, distance, random_access_...
0028 #include <memory> // for pointer_traits
0029 #include <type_traits> // for enable_if_t, declval, is_convertible, inte...
0030
0031 #if defined(__has_include) && __has_include(<version>)
0032 #include <version>
0033 #endif
0034
0035 #if defined(_MSC_VER) && !defined(__clang__)
0036 #pragma warning(push)
0037
0038 // turn off some warnings that are noisy about our Expects statements
0039 #pragma warning(disable : 4127) // conditional expression is constant
0040 #pragma warning( \
0041 disable : 4146) // unary minus operator applied to unsigned type, result still unsigned
0042 #pragma warning(disable : 4702) // unreachable code
0043
0044 // Turn MSVC /analyze rules that generate too much noise. TODO: fix in the tool.
0045 #pragma warning(disable : 26495) // uninitialized member when constructor calls constructor
0046 #pragma warning(disable : 26446) // parser bug does not allow attributes on some templates
0047
0048 #endif // _MSC_VER
0049
0050 // See if we have enough C++17 power to use a static constexpr data member
0051 // without needing an out-of-line definition
0052 #if !(defined(__cplusplus) && (__cplusplus >= 201703L))
0053 #define GSL_USE_STATIC_CONSTEXPR_WORKAROUND
0054 #endif // !(defined(__cplusplus) && (__cplusplus >= 201703L))
0055
0056 // GCC 7 does not like the signed unsigned mismatch (size_t ptrdiff_t)
0057 // While there is a conversion from signed to unsigned, it happens at
0058 // compiletime, so the compiler wouldn't have to warn indiscriminately, but
0059 // could check if the source value actually doesn't fit into the target type
0060 // and only warn in those cases.
0061 #if defined(__GNUC__) && __GNUC__ > 6
0062 #pragma GCC diagnostic push
0063 #pragma GCC diagnostic ignored "-Wsign-conversion"
0064 #endif
0065
0066 // Turn off clang unsafe buffer warnings as all accessed are guarded by runtime checks
0067 #if defined(__clang__)
0068 #if __has_warning("-Wunsafe-buffer-usage")
0069 #pragma clang diagnostic push
0070 #pragma clang diagnostic ignored "-Wunsafe-buffer-usage"
0071 #endif // __has_warning("-Wunsafe-buffer-usage")
0072 #endif // defined(__clang__)
0073
0074 namespace gsl
0075 {
0076
0077 // implementation details
0078 namespace details
0079 {
0080 template <class T>
0081 struct is_span_oracle : std::false_type
0082 {
0083 };
0084
0085 template <class ElementType, std::size_t Extent>
0086 struct is_span_oracle<gsl::span<ElementType, Extent>> : std::true_type
0087 {
0088 };
0089
0090 template <class T>
0091 struct is_span : public is_span_oracle<std::remove_cv_t<T>>
0092 {
0093 };
0094
0095 template <class T>
0096 struct is_std_array_oracle : std::false_type
0097 {
0098 };
0099
0100 template <class ElementType, std::size_t Extent>
0101 struct is_std_array_oracle<std::array<ElementType, Extent>> : std::true_type
0102 {
0103 };
0104
0105 template <class T>
0106 struct is_std_array : is_std_array_oracle<std::remove_cv_t<T>>
0107 {
0108 };
0109
0110 template <std::size_t From, std::size_t To>
0111 struct is_allowed_extent_conversion
0112 : std::integral_constant<bool, From == To || To == dynamic_extent>
0113 {
0114 };
0115
0116 template <class From, class To>
0117 struct is_allowed_element_type_conversion
0118 : std::integral_constant<bool, std::is_convertible<From (*)[], To (*)[]>::value>
0119 {
0120 };
0121
0122 template <class Type>
0123 class span_iterator
0124 {
0125 public:
0126 #if defined(__cpp_lib_ranges) || (defined(_MSVC_STL_VERSION) && defined(__cpp_lib_concepts))
0127 using iterator_concept = std::contiguous_iterator_tag;
0128 #endif // __cpp_lib_ranges
0129 using iterator_category = std::random_access_iterator_tag;
0130 using value_type = std::remove_cv_t<Type>;
0131 using difference_type = std::ptrdiff_t;
0132 using pointer = Type*;
0133 using reference = Type&;
0134
0135 #ifdef _MSC_VER
0136 using _Unchecked_type = pointer;
0137 using _Prevent_inheriting_unwrap = span_iterator;
0138 #endif // _MSC_VER
0139 constexpr span_iterator() = default;
0140
0141 constexpr span_iterator(pointer begin, pointer end, pointer current)
0142 : begin_(begin), end_(end), current_(current)
0143 {
0144 Expects(begin_ <= current_ && current <= end_);
0145 }
0146
0147 constexpr operator span_iterator<const Type>() const noexcept
0148 {
0149 return {begin_, end_, current_};
0150 }
0151
0152 constexpr reference operator*() const noexcept
0153 {
0154 Expects(current_ != end_);
0155 return *current_;
0156 }
0157
0158 constexpr pointer operator->() const noexcept
0159 {
0160 Expects(current_ != end_);
0161 return current_;
0162 }
0163 constexpr span_iterator& operator++() noexcept
0164 {
0165 Expects(current_ != end_);
0166 // clang-format off
0167 GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
0168 // clang-format on
0169 ++current_;
0170 return *this;
0171 }
0172
0173 constexpr span_iterator operator++(int) noexcept
0174 {
0175 span_iterator ret = *this;
0176 ++*this;
0177 return ret;
0178 }
0179
0180 constexpr span_iterator& operator--() noexcept
0181 {
0182 Expects(begin_ != current_);
0183 --current_;
0184 return *this;
0185 }
0186
0187 constexpr span_iterator operator--(int) noexcept
0188 {
0189 span_iterator ret = *this;
0190 --*this;
0191 return ret;
0192 }
0193
0194 constexpr span_iterator& operator+=(const difference_type n) noexcept
0195 {
0196 if (n != 0) Expects(begin_ && current_ && end_);
0197 if (n > 0) Expects(end_ - current_ >= n);
0198 if (n < 0) Expects(current_ - begin_ >= -n);
0199 // clang-format off
0200 GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
0201 // clang-format on
0202 current_ += n;
0203 return *this;
0204 }
0205
0206 constexpr span_iterator operator+(const difference_type n) const noexcept
0207 {
0208 span_iterator ret = *this;
0209 ret += n;
0210 return ret;
0211 }
0212
0213 friend constexpr span_iterator operator+(const difference_type n,
0214 const span_iterator& rhs) noexcept
0215 {
0216 return rhs + n;
0217 }
0218
0219 constexpr span_iterator& operator-=(const difference_type n) noexcept
0220 {
0221 if (n != 0) Expects(begin_ && current_ && end_);
0222 if (n > 0) Expects(current_ - begin_ >= n);
0223 if (n < 0) Expects(end_ - current_ >= -n);
0224 GSL_SUPPRESS(bounds .1)
0225 current_ -= n;
0226 return *this;
0227 }
0228
0229 constexpr span_iterator operator-(const difference_type n) const noexcept
0230 {
0231 span_iterator ret = *this;
0232 ret -= n;
0233 return ret;
0234 }
0235
0236 template <
0237 class Type2,
0238 std::enable_if_t<std::is_same<std::remove_cv_t<Type2>, value_type>::value, int> = 0>
0239 constexpr difference_type operator-(const span_iterator<Type2>& rhs) const noexcept
0240 {
0241 Expects(begin_ == rhs.begin_ && end_ == rhs.end_);
0242 return current_ - rhs.current_;
0243 }
0244
0245 constexpr reference operator[](const difference_type n) const noexcept
0246 {
0247 return *(*this + n);
0248 }
0249
0250 template <
0251 class Type2,
0252 std::enable_if_t<std::is_same<std::remove_cv_t<Type2>, value_type>::value, int> = 0>
0253 constexpr bool operator==(const span_iterator<Type2>& rhs) const noexcept
0254 {
0255 Expects(begin_ == rhs.begin_ && end_ == rhs.end_);
0256 return current_ == rhs.current_;
0257 }
0258
0259 template <
0260 class Type2,
0261 std::enable_if_t<std::is_same<std::remove_cv_t<Type2>, value_type>::value, int> = 0>
0262 constexpr bool operator!=(const span_iterator<Type2>& rhs) const noexcept
0263 {
0264 return !(*this == rhs);
0265 }
0266
0267 template <
0268 class Type2,
0269 std::enable_if_t<std::is_same<std::remove_cv_t<Type2>, value_type>::value, int> = 0>
0270 constexpr bool operator<(const span_iterator<Type2>& rhs) const noexcept
0271 {
0272 Expects(begin_ == rhs.begin_ && end_ == rhs.end_);
0273 return current_ < rhs.current_;
0274 }
0275
0276 template <
0277 class Type2,
0278 std::enable_if_t<std::is_same<std::remove_cv_t<Type2>, value_type>::value, int> = 0>
0279 constexpr bool operator>(const span_iterator<Type2>& rhs) const noexcept
0280 {
0281 return rhs < *this;
0282 }
0283
0284 template <
0285 class Type2,
0286 std::enable_if_t<std::is_same<std::remove_cv_t<Type2>, value_type>::value, int> = 0>
0287 constexpr bool operator<=(const span_iterator<Type2>& rhs) const noexcept
0288 {
0289 return !(rhs < *this);
0290 }
0291
0292 template <
0293 class Type2,
0294 std::enable_if_t<std::is_same<std::remove_cv_t<Type2>, value_type>::value, int> = 0>
0295 constexpr bool operator>=(const span_iterator<Type2>& rhs) const noexcept
0296 {
0297 return !(*this < rhs);
0298 }
0299
0300 #ifdef _MSC_VER
0301 // MSVC++ iterator debugging support; allows STL algorithms in 15.8+
0302 // to unwrap span_iterator to a pointer type after a range check in STL
0303 // algorithm calls
0304 friend constexpr void _Verify_range(span_iterator lhs, span_iterator rhs) noexcept
0305 { // test that [lhs, rhs) forms a valid range inside an STL algorithm
0306 Expects(lhs.begin_ == rhs.begin_ // range spans have to match
0307 && lhs.end_ == rhs.end_ &&
0308 lhs.current_ <= rhs.current_); // range must not be transposed
0309 }
0310
0311 constexpr void _Verify_offset(const difference_type n) const noexcept
0312 { // test that *this + n is within the range of this call
0313 if (n != 0) Expects(begin_ && current_ && end_);
0314 if (n > 0) Expects(end_ - current_ >= n);
0315 if (n < 0) Expects(current_ - begin_ >= -n);
0316 }
0317
0318 // clang-format off
0319 GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
0320 // clang-format on
0321 constexpr pointer _Unwrapped() const noexcept
0322 { // after seeking *this to a high water mark, or using one of the
0323 // _Verify_xxx functions above, unwrap this span_iterator to a raw
0324 // pointer
0325 return current_;
0326 }
0327
0328 // Tell the STL that span_iterator should not be unwrapped if it can't
0329 // validate in advance, even in release / optimized builds:
0330 #if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND)
0331 static constexpr const bool _Unwrap_when_unverified = false;
0332 #else
0333 static constexpr bool _Unwrap_when_unverified = false;
0334 #endif
0335 // clang-format off
0336 GSL_SUPPRESS(con.3) // NO-FORMAT: attribute // TODO: false positive
0337 // clang-format on
0338 constexpr void _Seek_to(const pointer p) noexcept
0339 { // adjust the position of *this to previously verified location p
0340 // after _Unwrapped
0341 current_ = p;
0342 }
0343 #endif
0344
0345 pointer begin_ = nullptr;
0346 pointer end_ = nullptr;
0347 pointer current_ = nullptr;
0348
0349 template <typename Ptr>
0350 friend struct std::pointer_traits;
0351 };
0352 }} // namespace gsl::details
0353
0354 namespace std
0355 {
0356 template <class Type>
0357 struct pointer_traits<::gsl::details::span_iterator<Type>>
0358 {
0359 using pointer = ::gsl::details::span_iterator<Type>;
0360 using element_type = Type;
0361 using difference_type = ptrdiff_t;
0362
0363 static constexpr element_type* to_address(const pointer i) noexcept { return i.current_; }
0364 };
0365 } // namespace std
0366
0367 namespace gsl { namespace details {
0368 template <std::size_t Ext>
0369 class extent_type
0370 {
0371 public:
0372 using size_type = std::size_t;
0373
0374 constexpr extent_type() noexcept = default;
0375
0376 constexpr explicit extent_type(extent_type<dynamic_extent>);
0377
0378 constexpr explicit extent_type(size_type size) { Expects(size == Ext); }
0379
0380 constexpr size_type size() const noexcept { return Ext; }
0381
0382 private:
0383 #if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND)
0384 static constexpr const size_type size_ = Ext; // static size equal to Ext
0385 #else
0386 static constexpr size_type size_ = Ext; // static size equal to Ext
0387 #endif
0388 };
0389
0390 template <>
0391 class extent_type<dynamic_extent>
0392 {
0393 public:
0394 using size_type = std::size_t;
0395
0396 template <size_type Other>
0397 constexpr explicit extent_type(extent_type<Other> ext) : size_(ext.size())
0398 {}
0399
0400 constexpr explicit extent_type(size_type size) : size_(size)
0401 {
0402 Expects(size != dynamic_extent);
0403 }
0404
0405 constexpr size_type size() const noexcept { return size_; }
0406
0407 private:
0408 size_type size_;
0409 };
0410
0411 template <std::size_t Ext>
0412 constexpr extent_type<Ext>::extent_type(extent_type<dynamic_extent> ext)
0413 {
0414 Expects(ext.size() == Ext);
0415 }
0416
0417 template <class ElementType, std::size_t Extent, std::size_t Offset, std::size_t Count>
0418 struct calculate_subspan_type
0419 {
0420 using type = span<ElementType, Count != dynamic_extent
0421 ? Count
0422 : (Extent != dynamic_extent ? Extent - Offset : Extent)>;
0423 };
0424 } // namespace details
0425
0426 // [span], class template span
0427 template <class ElementType, std::size_t Extent>
0428 class span
0429 {
0430 public:
0431 // constants and types
0432 using element_type = ElementType;
0433 using value_type = std::remove_cv_t<ElementType>;
0434 using size_type = std::size_t;
0435 using pointer = element_type*;
0436 using const_pointer = const element_type*;
0437 using reference = element_type&;
0438 using const_reference = const element_type&;
0439 using difference_type = std::ptrdiff_t;
0440
0441 using iterator = details::span_iterator<ElementType>;
0442 using reverse_iterator = std::reverse_iterator<iterator>;
0443
0444 #if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND)
0445 static constexpr const size_type extent{Extent};
0446 #else
0447 static constexpr size_type extent{Extent};
0448 #endif
0449
0450 // [span.cons], span constructors, copy, assignment, and destructor
0451 template <bool Dependent = false,
0452 // "Dependent" is needed to make "std::enable_if_t<Dependent || Extent == 0 || Extent
0453 // == dynamic_extent>" SFINAE, since "std::enable_if_t<Extent == 0 || Extent ==
0454 // dynamic_extent>" is ill-formed when Extent is greater than 0.
0455 class = std::enable_if_t<(Dependent ||
0456 details::is_allowed_extent_conversion<0, Extent>::value)>>
0457 constexpr span() noexcept : storage_(nullptr, details::extent_type<0>())
0458 {}
0459
0460 template <std::size_t MyExtent = Extent, std::enable_if_t<MyExtent != dynamic_extent, int> = 0>
0461 constexpr explicit span(pointer ptr, size_type count) noexcept : storage_(ptr, count)
0462 {
0463 Expects(count == Extent);
0464 }
0465
0466 template <std::size_t MyExtent = Extent, std::enable_if_t<MyExtent == dynamic_extent, int> = 0>
0467 constexpr span(pointer ptr, size_type count) noexcept : storage_(ptr, count)
0468 {}
0469
0470 template <std::size_t MyExtent = Extent, std::enable_if_t<MyExtent != dynamic_extent, int> = 0>
0471 constexpr explicit span(pointer firstElem, pointer lastElem) noexcept
0472 : storage_(firstElem, narrow_cast<std::size_t>(lastElem - firstElem))
0473 {
0474 Expects(lastElem - firstElem == static_cast<difference_type>(Extent));
0475 }
0476
0477 template <std::size_t MyExtent = Extent, std::enable_if_t<MyExtent == dynamic_extent, int> = 0>
0478 constexpr span(pointer firstElem, pointer lastElem) noexcept
0479 : storage_(firstElem, narrow_cast<std::size_t>(lastElem - firstElem))
0480 {}
0481
0482 template <std::size_t N,
0483 std::enable_if_t<details::is_allowed_extent_conversion<N, Extent>::value, int> = 0>
0484 constexpr span(element_type (&arr)[N]) noexcept
0485 : storage_(KnownNotNull{arr}, details::extent_type<N>())
0486 {}
0487
0488 template <
0489 class T, std::size_t N,
0490 std::enable_if_t<(details::is_allowed_extent_conversion<N, Extent>::value &&
0491 details::is_allowed_element_type_conversion<T, element_type>::value),
0492 int> = 0>
0493 constexpr span(std::array<T, N>& arr) noexcept
0494 : storage_(KnownNotNull{arr.data()}, details::extent_type<N>())
0495 {}
0496
0497 template <class T, std::size_t N,
0498 std::enable_if_t<
0499 (details::is_allowed_extent_conversion<N, Extent>::value &&
0500 details::is_allowed_element_type_conversion<const T, element_type>::value),
0501 int> = 0>
0502 constexpr span(const std::array<T, N>& arr) noexcept
0503 : storage_(KnownNotNull{arr.data()}, details::extent_type<N>())
0504 {}
0505
0506 // NB: the SFINAE on these constructors uses .data() as an incomplete/imperfect proxy for the
0507 // requirement on Container to be a contiguous sequence container.
0508 template <std::size_t MyExtent = Extent, class Container,
0509 std::enable_if_t<
0510 MyExtent != dynamic_extent && !details::is_span<Container>::value &&
0511 !details::is_std_array<Container>::value &&
0512 std::is_pointer<decltype(std::declval<Container&>().data())>::value &&
0513 std::is_convertible<
0514 std::remove_pointer_t<decltype(std::declval<Container&>().data())> (*)[],
0515 element_type (*)[]>::value,
0516 int> = 0>
0517 constexpr explicit span(Container& cont) noexcept : span(cont.data(), cont.size())
0518 {}
0519
0520 template <std::size_t MyExtent = Extent, class Container,
0521 std::enable_if_t<
0522 MyExtent == dynamic_extent && !details::is_span<Container>::value &&
0523 !details::is_std_array<Container>::value &&
0524 std::is_pointer<decltype(std::declval<Container&>().data())>::value &&
0525 std::is_convertible<
0526 std::remove_pointer_t<decltype(std::declval<Container&>().data())> (*)[],
0527 element_type (*)[]>::value,
0528 int> = 0>
0529 constexpr span(Container& cont) noexcept : span(cont.data(), cont.size())
0530 {}
0531
0532 template <
0533 std::size_t MyExtent = Extent, class Container,
0534 std::enable_if_t<
0535 MyExtent != dynamic_extent && std::is_const<element_type>::value &&
0536 !details::is_span<Container>::value && !details::is_std_array<Container>::value &&
0537 std::is_pointer<decltype(std::declval<const Container&>().data())>::value &&
0538 std::is_convertible<
0539 std::remove_pointer_t<decltype(std::declval<const Container&>().data())> (*)[],
0540 element_type (*)[]>::value,
0541 int> = 0>
0542 constexpr explicit span(const Container& cont) noexcept : span(cont.data(), cont.size())
0543 {}
0544
0545 template <
0546 std::size_t MyExtent = Extent, class Container,
0547 std::enable_if_t<
0548 MyExtent == dynamic_extent && std::is_const<element_type>::value &&
0549 !details::is_span<Container>::value && !details::is_std_array<Container>::value &&
0550 std::is_pointer<decltype(std::declval<const Container&>().data())>::value &&
0551 std::is_convertible<
0552 std::remove_pointer_t<decltype(std::declval<const Container&>().data())> (*)[],
0553 element_type (*)[]>::value,
0554 int> = 0>
0555 constexpr span(const Container& cont) noexcept : span(cont.data(), cont.size())
0556 {}
0557
0558 constexpr span(const span& other) noexcept = default;
0559
0560 template <class OtherElementType, std::size_t OtherExtent, std::size_t MyExtent = Extent,
0561 std::enable_if_t<(MyExtent == dynamic_extent || MyExtent == OtherExtent) &&
0562 details::is_allowed_element_type_conversion<OtherElementType,
0563 element_type>::value,
0564 int> = 0>
0565 constexpr span(const span<OtherElementType, OtherExtent>& other) noexcept
0566 : storage_(other.data(), details::extent_type<OtherExtent>(other.size()))
0567 {}
0568
0569 template <class OtherElementType, std::size_t OtherExtent, std::size_t MyExtent = Extent,
0570 std::enable_if_t<MyExtent != dynamic_extent && OtherExtent == dynamic_extent &&
0571 details::is_allowed_element_type_conversion<OtherElementType,
0572 element_type>::value,
0573 int> = 0>
0574 constexpr explicit span(const span<OtherElementType, OtherExtent>& other) noexcept
0575 : storage_(other.data(), details::extent_type<OtherExtent>(other.size()))
0576 {}
0577
0578 ~span() noexcept = default;
0579 constexpr span& operator=(const span& other) noexcept = default;
0580
0581 // [span.sub], span subviews
0582 template <std::size_t Count>
0583 constexpr span<element_type, Count> first() const noexcept
0584 {
0585 static_assert(Extent == dynamic_extent || Count <= Extent,
0586 "first() cannot extract more elements from a span than it contains.");
0587 Expects(Count <= size());
0588 return span<element_type, Count>{data(), Count};
0589 }
0590
0591 template <std::size_t Count>
0592 // clang-format off
0593 GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
0594 // clang-format on
0595 constexpr span<element_type, Count> last() const noexcept
0596 {
0597 static_assert(Extent == dynamic_extent || Count <= Extent,
0598 "last() cannot extract more elements from a span than it contains.");
0599 Expects(Count <= size());
0600 return span<element_type, Count>{data() + (size() - Count), Count};
0601 }
0602
0603 template <std::size_t Offset, std::size_t Count = dynamic_extent>
0604 // clang-format off
0605 GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
0606 // clang-format on
0607 constexpr auto subspan() const noexcept ->
0608 typename details::calculate_subspan_type<ElementType, Extent, Offset, Count>::type
0609 {
0610 static_assert(Extent == dynamic_extent || (Extent >= Offset && (Count == dynamic_extent ||
0611 Count <= Extent - Offset)),
0612 "subspan() cannot extract more elements from a span than it contains.");
0613 Expects((size() >= Offset) && (Count == dynamic_extent || (Count <= size() - Offset)));
0614 using type =
0615 typename details::calculate_subspan_type<ElementType, Extent, Offset, Count>::type;
0616 return type{data() + Offset, Count == dynamic_extent ? size() - Offset : Count};
0617 }
0618
0619 constexpr span<element_type, dynamic_extent> first(size_type count) const noexcept
0620 {
0621 Expects(count <= size());
0622 return {data(), count};
0623 }
0624
0625 constexpr span<element_type, dynamic_extent> last(size_type count) const noexcept
0626 {
0627 Expects(count <= size());
0628 return make_subspan(size() - count, dynamic_extent, subspan_selector<Extent>{});
0629 }
0630
0631 constexpr span<element_type, dynamic_extent>
0632 subspan(size_type offset, size_type count = dynamic_extent) const noexcept
0633 {
0634 return make_subspan(offset, count, subspan_selector<Extent>{});
0635 }
0636
0637 // [span.obs], span observers
0638 constexpr size_type size() const noexcept { return storage_.size(); }
0639
0640 constexpr size_type size_bytes() const noexcept { return size() * sizeof(element_type); }
0641
0642 constexpr bool empty() const noexcept { return size() == 0; }
0643
0644 // [span.elem], span element access
0645 // clang-format off
0646 GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
0647 // clang-format on
0648 constexpr reference operator[](size_type idx) const noexcept
0649 {
0650 Expects(idx < size());
0651 return data()[idx];
0652 }
0653
0654 constexpr reference front() const noexcept
0655 {
0656 Expects(size() > 0);
0657 return data()[0];
0658 }
0659
0660 constexpr reference back() const noexcept
0661 {
0662 Expects(size() > 0);
0663 return data()[size() - 1];
0664 }
0665
0666 constexpr pointer data() const noexcept { return storage_.data(); }
0667
0668 // [span.iter], span iterator support
0669 constexpr iterator begin() const noexcept
0670 {
0671 const auto data = storage_.data();
0672 // clang-format off
0673 GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
0674 // clang-format on
0675 return {data, data + size(), data};
0676 }
0677
0678 constexpr iterator end() const noexcept
0679 {
0680 const auto data = storage_.data();
0681 // clang-format off
0682 GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
0683 // clang-format on
0684 const auto endData = data + storage_.size();
0685 return {data, endData, endData};
0686 }
0687
0688 constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator{end()}; }
0689 constexpr reverse_iterator rend() const noexcept { return reverse_iterator{begin()}; }
0690
0691 #ifdef _MSC_VER
0692 // Tell MSVC how to unwrap spans in range-based-for
0693 constexpr pointer _Unchecked_begin() const noexcept { return data(); }
0694 constexpr pointer _Unchecked_end() const noexcept
0695 {
0696 // clang-format off
0697 GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
0698 // clang-format on
0699 return data() + size();
0700 }
0701 #endif // _MSC_VER
0702
0703 private:
0704 // Needed to remove unnecessary null check in subspans
0705 struct KnownNotNull
0706 {
0707 pointer p;
0708 };
0709
0710 // this implementation detail class lets us take advantage of the
0711 // empty base class optimization to pay for only storage of a single
0712 // pointer in the case of fixed-size spans
0713 template <class ExtentType>
0714 class storage_type : public ExtentType
0715 {
0716 public:
0717 // KnownNotNull parameter is needed to remove unnecessary null check
0718 // in subspans and constructors from arrays
0719 template <class OtherExtentType>
0720 constexpr storage_type(KnownNotNull data, OtherExtentType ext)
0721 : ExtentType(ext), data_(data.p)
0722 {}
0723
0724 template <class OtherExtentType>
0725 constexpr storage_type(pointer data, OtherExtentType ext) : ExtentType(ext), data_(data)
0726 {
0727 Expects(data || ExtentType::size() == 0);
0728 }
0729
0730 constexpr pointer data() const noexcept { return data_; }
0731
0732 private:
0733 pointer data_;
0734 };
0735
0736 storage_type<details::extent_type<Extent>> storage_;
0737
0738 // The rest is needed to remove unnecessary null check
0739 // in subspans and constructors from arrays
0740 constexpr span(KnownNotNull ptr, size_type count) noexcept : storage_(ptr, count) {}
0741
0742 template <std::size_t CallerExtent>
0743 class subspan_selector
0744 {
0745 };
0746
0747 template <std::size_t CallerExtent>
0748 constexpr span<element_type, dynamic_extent>
0749 make_subspan(size_type offset, size_type count, subspan_selector<CallerExtent>) const noexcept
0750 {
0751 const span<element_type, dynamic_extent> tmp(*this);
0752 return tmp.subspan(offset, count);
0753 }
0754
0755 // clang-format off
0756 GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
0757 // clang-format on
0758 constexpr span<element_type, dynamic_extent>
0759 make_subspan(size_type offset, size_type count, subspan_selector<dynamic_extent>) const noexcept
0760 {
0761 Expects(size() >= offset);
0762
0763 if (count == dynamic_extent) { return {KnownNotNull{data() + offset}, size() - offset}; }
0764
0765 Expects(size() - offset >= count);
0766 return {KnownNotNull{data() + offset}, count};
0767 }
0768 };
0769
0770 #if (defined(__cpp_deduction_guides) && (__cpp_deduction_guides >= 201611L))
0771
0772 // Deduction Guides
0773 template <class Type, std::size_t Extent>
0774 span(Type (&)[Extent]) -> span<Type, Extent>;
0775
0776 template <class Type, std::size_t Size>
0777 span(std::array<Type, Size>&) -> span<Type, Size>;
0778
0779 template <class Type, std::size_t Size>
0780 span(const std::array<Type, Size>&) -> span<const Type, Size>;
0781
0782 template <class Container,
0783 class Element = std::remove_pointer_t<decltype(std::declval<Container&>().data())>>
0784 span(Container&) -> span<Element>;
0785
0786 template <class Container,
0787 class Element = std::remove_pointer_t<decltype(std::declval<const Container&>().data())>>
0788 span(const Container&) -> span<Element>;
0789
0790 #endif // ( defined(__cpp_deduction_guides) && (__cpp_deduction_guides >= 201611L) )
0791
0792 #if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND)
0793 #if defined(__clang__) && defined(_MSC_VER) && defined(__cplusplus) && (__cplusplus < 201703L)
0794 #pragma clang diagnostic push
0795 #pragma clang diagnostic ignored "-Wdeprecated" // Bug in clang-cl.exe which raises a C++17 -Wdeprecated warning about this static constexpr workaround in C++14 mode.
0796 #endif // defined(__clang__) && defined(_MSC_VER) && defined(__cplusplus) && (__cplusplus < 201703L)
0797 template <class ElementType, std::size_t Extent>
0798 constexpr const typename span<ElementType, Extent>::size_type span<ElementType, Extent>::extent;
0799 #if defined(__clang__) && defined(_MSC_VER) && defined(__cplusplus) && (__cplusplus < 201703L)
0800 #pragma clang diagnostic pop
0801 #endif // defined(__clang__) && defined(_MSC_VER) && defined(__cplusplus) && (__cplusplus < 201703L)
0802 #endif
0803
0804 namespace details
0805 {
0806 // if we only supported compilers with good constexpr support then
0807 // this pair of classes could collapse down to a constexpr function
0808
0809 // we should use a narrow_cast<> to go to std::size_t, but older compilers may not see it as
0810 // constexpr
0811 // and so will fail compilation of the template
0812 template <class ElementType, std::size_t Extent>
0813 struct calculate_byte_size : std::integral_constant<std::size_t, sizeof(ElementType) * Extent>
0814 {
0815 static_assert(Extent < dynamic_extent / sizeof(ElementType), "Size is too big.");
0816 };
0817
0818 template <class ElementType>
0819 struct calculate_byte_size<ElementType, dynamic_extent>
0820 : std::integral_constant<std::size_t, dynamic_extent>
0821 {
0822 };
0823 } // namespace details
0824
0825 // [span.objectrep], views of object representation
0826 template <class ElementType, std::size_t Extent>
0827 span<const gsl::impl::byte, details::calculate_byte_size<ElementType, Extent>::value>
0828 as_bytes(span<ElementType, Extent> s) noexcept
0829 {
0830 using type = span<const gsl::impl::byte, details::calculate_byte_size<ElementType, Extent>::value>;
0831
0832 // clang-format off
0833 GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
0834 // clang-format on
0835 return type{reinterpret_cast<const gsl::impl::byte*>(s.data()), s.size_bytes()};
0836 }
0837
0838 template <class ElementType, std::size_t Extent,
0839 std::enable_if_t<!std::is_const<ElementType>::value, int> = 0>
0840 span<gsl::impl::byte, details::calculate_byte_size<ElementType, Extent>::value>
0841 as_writable_bytes(span<ElementType, Extent> s) noexcept
0842 {
0843 using type = span<gsl::impl::byte, details::calculate_byte_size<ElementType, Extent>::value>;
0844
0845 // clang-format off
0846 GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
0847 // clang-format on
0848 return type{reinterpret_cast<gsl::impl::byte*>(s.data()), s.size_bytes()};
0849 }
0850
0851 } // namespace gsl
0852
0853 #if defined(_MSC_VER) && !defined(__clang__)
0854
0855 #pragma warning(pop)
0856 #endif // _MSC_VER
0857
0858 #if defined(__GNUC__) && __GNUC__ > 6
0859 #pragma GCC diagnostic pop
0860 #endif // __GNUC__ > 6
0861
0862 #if defined(__clang__)
0863 #if __has_warning("-Wunsafe-buffer-usage")
0864 #pragma clang diagnostic pop
0865 #endif // __has_warning("-Wunsafe-buffer-usage")
0866 #endif // defined(__clang__)
0867
0868 #endif // GSL_SPAN_H