SpECTRE Documentation Coverage Report
Current view: top level - Utilities - Gsl.hpp Coverage Total Hit
Commit: a37d7b3c1803b88b537d2aef1c27ca5e6b499398 Lines: 19.2 % 120 23
Test Date: 2026-11-12 04:47:19
Legend: Lines:     hit not hit

            Line data    Source code
       1            1 : 
       2              : /// \file
       3              : /// Defines functions and classes from the GSL
       4              : 
       5              : #pragma once
       6              : 
       7              : #pragma GCC system_header
       8              : 
       9              : // The code in this file is adapted from Microsoft's GSL that can be found at
      10              : // https://github.com/Microsoft/GSL
      11              : // The original license and copyright are:
      12              : ///////////////////////////////////////////////////////////////////////////////
      13              : //
      14              : // Copyright (c) 2015 Microsoft Corporation. All rights reserved.
      15              : //
      16              : // This code is licensed under the MIT License (MIT).
      17              : //
      18              : // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      19              : // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      20              : // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      21              : // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      22              : // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      23              : // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
      24              : // THE SOFTWARE.
      25              : //
      26              : ///////////////////////////////////////////////////////////////////////////////
      27              : // The code changes are because SpECTRE is not allowed to throw under any
      28              : // circumstances that cannot be guaranteed to be caught and so all throw's
      29              : // are replaced by hard errors (ERROR).
      30              : 
      31              : #include <algorithm>
      32              : #include <array>
      33              : #include <cstddef>
      34              : #include <iterator>
      35              : #include <limits>
      36              : #include <memory>
      37              : #include <stdexcept>
      38              : #include <type_traits>
      39              : #include <utility>
      40              : 
      41              : #include "Utilities/Array.hpp"
      42              : #include "Utilities/ErrorHandling/ExpectsAndEnsures.hpp"
      43              : #include "Utilities/ForceInline.hpp"
      44              : #include "Utilities/Kokkos/KokkosMacros.hpp"
      45              : #include "Utilities/Literals.hpp"
      46              : #include "Utilities/PrettyType.hpp"
      47              : #include "Utilities/Requires.hpp"
      48              : #include "Utilities/TMPL.hpp"
      49              : 
      50              : #if defined(__clang__) || defined(__GNUC__)
      51              : 
      52              : /*!
      53              :  * \ingroup UtilitiesGroup
      54              :  * The if statement is expected to evaluate true most of the time
      55              :  */
      56              : #define LIKELY(x) __builtin_expect(!!(x), 1)
      57              : 
      58              : /*!
      59              :  * \ingroup UtilitiesGroup
      60              :  * The if statement is expected to evaluate false most of the time
      61              :  */
      62              : #define UNLIKELY(x) __builtin_expect(!!(x), 0)
      63              : 
      64              : #else
      65              : /*!
      66              :  * \ingroup UtilitiesGroup
      67              :  * The if statement is expected to evaluate true most of the time
      68              :  */
      69            1 : #define LIKELY(x) (x)
      70              : 
      71              : /*!
      72              :  * \ingroup UtilitiesGroup
      73              :  * The if statement is expected to evaluate false most of the time
      74              :  */
      75            1 : #define UNLIKELY(x) (x)
      76              : #endif
      77              : 
      78              : /*!
      79              :  * \ingroup UtilitiesGroup
      80              :  * \brief Implementations from the Guideline Support Library
      81              :  */
      82            1 : namespace gsl {
      83              : 
      84              : /*!
      85              :  * \ingroup UtilitiesGroup
      86              :  * \brief Cast `u` to a type `T` where the cast may result in narrowing
      87              :  */
      88              : template <class T, class U>
      89            1 : KOKKOS_FUNCTION SPECTRE_ALWAYS_INLINE constexpr T narrow_cast(U&& u) {
      90              :   return static_cast<T>(std::forward<U>(u));
      91              : }
      92              : 
      93              : namespace gsl_detail {
      94              : // Checks that `index` is a valid index into a container of size `size`, like
      95              : // `Expects`. Can be called in Kokkos kernels, where a failed check aborts.
      96              : template <typename Size>
      97              : KOKKOS_FUNCTION SPECTRE_ALWAYS_INLINE constexpr void kokkos_check_bounds(
      98              :     const Size index, const std::size_t size) {
      99              : #if defined(SPECTRE_DEBUG) || defined(EXPECTS_ENSURES)
     100              :   KOKKOS_IF_ON_HOST((Expects(index >= 0 and index < narrow_cast<Size>(size));))
     101              :   KOKKOS_IF_ON_DEVICE(
     102              :       (if (not(index >= 0 and index < narrow_cast<Size>(size))) {
     103              :         Kokkos::abort("gsl::at: index out of bounds");
     104              :       }))
     105              : #else
     106              :   static_cast<void>(index);
     107              :   static_cast<void>(size);
     108              : #endif
     109              : }
     110              : 
     111              : template <class T, class U>
     112              : struct is_same_signedness
     113              :     : public std::integral_constant<bool, std::is_signed<T>::value ==
     114              :                                               std::is_signed<U>::value> {};
     115              : }  // namespace gsl_detail
     116              : 
     117              : /*!
     118              :  * \ingroup UtilitiesGroup
     119              :  * \brief A checked version of narrow_cast() that ERRORs if the cast changed
     120              :  * the value
     121              :  */
     122              : template <class T, class U>
     123            1 : SPECTRE_ALWAYS_INLINE T narrow(U u) {
     124              :   T t = narrow_cast<T>(u);
     125              :   if (static_cast<U>(t) != u) {
     126              :     ERROR("Failed to cast " << u << " of type " << pretty_type::get_name<U>()
     127              :                             << " to type " << pretty_type::get_name<T>());
     128              :   }
     129              :   if (not gsl_detail::is_same_signedness<T, U>::value and
     130              :       ((t < T{}) != (u < U{}))) {
     131              :     ERROR("Failed to cast " << u << " of type " << pretty_type::get_name<U>()
     132              :                             << " to type " << pretty_type::get_name<T>());
     133              :   }
     134              :   return t;
     135              : }
     136              : 
     137              : /// @{
     138              : /*!
     139              :  * \ingroup UtilitiesGroup
     140              :  * \brief Retrieve a entry from a container, with checks in Debug mode that
     141              :  * the index being retrieved is valid.
     142              :  *
     143              :  * The overloads for `std::array` can be called in Kokkos kernels.
     144              :  */
     145              : template <class T, std::size_t N, typename Size>
     146            1 : KOKKOS_FUNCTION SPECTRE_ALWAYS_INLINE constexpr T& at(std::array<T, N>& arr,
     147              :                                                       Size index) {
     148              :   gsl_detail::kokkos_check_bounds(index, N);
     149              :   return arr[static_cast<std::size_t>(index)];
     150              : }
     151              : 
     152              : template <class T, std::size_t N, typename Size>
     153            1 : KOKKOS_FUNCTION SPECTRE_ALWAYS_INLINE constexpr const T& at(
     154              :     const std::array<T, N>& arr, Size index) {
     155              :   gsl_detail::kokkos_check_bounds(index, N);
     156              :   return arr[static_cast<std::size_t>(index)];
     157              : }
     158              : 
     159              : template <class T, std::size_t N, typename Size>
     160            1 : SPECTRE_ALWAYS_INLINE constexpr T& at(cpp20::array<T, N>& arr, Size index) {
     161              :   Expects(index >= 0 and index < narrow_cast<Size>(N));
     162              :   return arr[static_cast<std::size_t>(index)];
     163              : }
     164              : 
     165              : template <class T, std::size_t N, typename Size>
     166            1 : SPECTRE_ALWAYS_INLINE constexpr const T& at(const cpp20::array<T, N>& arr,
     167              :                                             Size index) {
     168              :   Expects(index >= 0 and index < narrow_cast<Size>(N));
     169              :   return arr[static_cast<std::size_t>(index)];
     170              : }
     171              : 
     172              : template <class Cont, typename Size>
     173            1 : SPECTRE_ALWAYS_INLINE constexpr const typename Cont::value_type& at(
     174              :     const Cont& cont, Size index) {
     175              :   Expects(index >= 0 and index < narrow_cast<Size>(cont.size()));
     176              :   return cont[static_cast<typename Cont::size_type>(index)];
     177              : }
     178              : 
     179              : template <class T, typename Size>
     180            1 : SPECTRE_ALWAYS_INLINE constexpr const T& at(std::initializer_list<T> cont,
     181              :                                             Size index) {
     182              :   Expects(index >= 0 and index < narrow_cast<Size>(cont.size()));
     183              :   return *(cont.begin() + index);
     184              : }
     185              : /// @}
     186              : 
     187              : namespace detail {
     188              : template <class T>
     189              : struct owner_impl {
     190              :   static_assert(std::is_same<T, const owner_impl<int*>&>::value,
     191              :                 "You should not have an owning raw pointer, instead you should "
     192              :                 "use std::unique_ptr or, sparingly, std::shared_ptr. If "
     193              :                 "clang-tidy told you to use gsl::owner, then you should still "
     194              :                 "use std::unique_ptr instead.");
     195              :   using type = T;
     196              : };
     197              : }  // namespace detail
     198              : 
     199              : /*!
     200              :  * \ingroup UtilitiesGroup
     201              :  * \brief Mark a raw pointer as owning its data
     202              :  *
     203              :  * \warning You should never actually use `gsl::owner`. Instead you should use
     204              :  * `std::unique_ptr`, and if shared ownership is required, `std::shared_ptr`.
     205              :  */
     206              : template <class T, Requires<std::is_pointer<T>::value> = nullptr>
     207            1 : using owner = typename detail::owner_impl<T>::type;
     208              : 
     209              : /*!
     210              :  * \ingroup UtilitiesGroup
     211              :  * \brief Require a pointer to not be a `nullptr`
     212              :  *
     213              :  * Restricts a pointer or smart pointer to only hold non-null values.
     214              :  *
     215              :  * Has zero size overhead over `T`.
     216              :  *
     217              :  * If `T` is a pointer (i.e. `T == U*`) then
     218              :  * - allow construction from `U*`
     219              :  * - disallow construction from `nullptr_t`
     220              :  * - disallow default construction
     221              :  * - ensure construction from null `U*` fails
     222              :  * - allow implicit conversion to `U*`
     223              :  */
     224              : template <class T>
     225            1 : class not_null {
     226              :  public:
     227              :   static_assert(std::is_assignable<T&, std::nullptr_t>::value,
     228              :                 "T cannot be assigned nullptr.");
     229              : 
     230              :   template <typename U, Requires<std::is_convertible<U, T>::value> = nullptr>
     231            0 :   constexpr not_null(U&& u) : ptr_(std::forward<U>(u)) {
     232              :     Expects(ptr_ != nullptr);
     233              :   }
     234              : 
     235              :   template <typename U, Requires<std::is_convertible<U, T>::value> = nullptr>
     236            0 :   constexpr not_null(const not_null<U>& other) : not_null(other.get()) {}
     237              : 
     238            0 :   not_null(const not_null& other) = default;
     239            0 :   not_null& operator=(const not_null& other) = default;
     240              : 
     241            0 :   constexpr T get() const {
     242              :     Ensures(ptr_ != nullptr);
     243              :     return ptr_;
     244              :   }
     245              : 
     246            0 :   constexpr operator T() const { return get(); }
     247            0 :   constexpr T operator->() const { return get(); }
     248            0 :   constexpr decltype(auto) operator*() const { return *get(); }
     249              : 
     250              :   // prevents compilation when someone attempts to assign a null pointer
     251              :   // constant
     252            0 :   not_null(std::nullptr_t) = delete;
     253            0 :   not_null& operator=(std::nullptr_t) = delete;
     254              : 
     255              :   // unwanted operators...pointers only point to single objects!
     256            0 :   not_null& operator++() = delete;
     257            0 :   not_null& operator--() = delete;
     258            0 :   not_null operator++(int) = delete;
     259            0 :   not_null operator--(int) = delete;
     260            0 :   not_null& operator+=(std::ptrdiff_t) = delete;
     261            0 :   not_null& operator-=(std::ptrdiff_t) = delete;
     262            0 :   void operator[](std::ptrdiff_t) const = delete;
     263              : 
     264              :  private:
     265            0 :   T ptr_;
     266              : };
     267              : 
     268              : template <class T>
     269            0 : std::ostream& operator<<(std::ostream& os, const not_null<T>& val) {
     270              :   os << val.get();
     271              :   return os;
     272              : }
     273              : 
     274              : template <class T, class U>
     275            0 : auto operator==(const not_null<T>& lhs, const not_null<U>& rhs)
     276              :     -> decltype(lhs.get() == rhs.get()) {
     277              :   return lhs.get() == rhs.get();
     278              : }
     279              : 
     280              : template <class T, class U>
     281            0 : auto operator!=(const not_null<T>& lhs, const not_null<U>& rhs)
     282              :     -> decltype(lhs.get() != rhs.get()) {
     283              :   return lhs.get() != rhs.get();
     284              : }
     285              : 
     286              : template <class T, class U>
     287            0 : auto operator<(const not_null<T>& lhs, const not_null<U>& rhs)
     288              :     -> decltype(lhs.get() < rhs.get()) {
     289              :   return lhs.get() < rhs.get();
     290              : }
     291              : 
     292              : template <class T, class U>
     293            0 : auto operator<=(const not_null<T>& lhs, const not_null<U>& rhs)
     294              :     -> decltype(lhs.get() <= rhs.get()) {
     295              :   return lhs.get() <= rhs.get();
     296              : }
     297              : 
     298              : template <class T, class U>
     299            0 : auto operator>(const not_null<T>& lhs, const not_null<U>& rhs)
     300              :     -> decltype(lhs.get() > rhs.get()) {
     301              :   return lhs.get() > rhs.get();
     302              : }
     303              : 
     304              : template <class T, class U>
     305            0 : auto operator>=(const not_null<T>& lhs, const not_null<U>& rhs)
     306              :     -> decltype(lhs.get() >= rhs.get()) {
     307              :   return lhs.get() >= rhs.get();
     308              : }
     309              : 
     310              : // more unwanted operators
     311              : template <class T, class U>
     312            0 : std::ptrdiff_t operator-(const not_null<T>&, const not_null<U>&) = delete;
     313              : template <class T>
     314            0 : not_null<T> operator-(const not_null<T>&, std::ptrdiff_t) = delete;
     315              : template <class T>
     316            0 : not_null<T> operator+(const not_null<T>&, std::ptrdiff_t) = delete;
     317              : template <class T>
     318            0 : not_null<T> operator+(std::ptrdiff_t, const not_null<T>&) = delete;
     319              : 
     320              : // GCC 7 does not like the signed unsigned missmatch (size_t ptrdiff_t)
     321              : // While there is a conversion from signed to unsigned, it happens at
     322              : // compile time, so the compiler wouldn't have to warn indiscriminently, but
     323              : // could check if the source value actually doesn't fit into the target type
     324              : // and only warn in those cases.
     325              : #if __GNUC__ > 6
     326              : #pragma GCC diagnostic push
     327              : #pragma GCC diagnostic ignored "-Wsign-conversion"
     328              : #endif  // __GNUC__ > 6
     329              : 
     330              : // [views.constants], constants
     331            0 : constexpr const std::ptrdiff_t dynamic_extent = -1;
     332              : 
     333              : template <class ElementType, std::ptrdiff_t Extent = dynamic_extent>
     334              : class span;
     335              : 
     336              : // implementation details
     337              : namespace detail {
     338              : template <class T>
     339              : struct is_span_oracle : std::false_type {};
     340              : 
     341              : template <class ElementType, std::ptrdiff_t Extent>
     342              : struct is_span_oracle<gsl::span<ElementType, Extent>> : std::true_type {};
     343              : 
     344              : template <class T>
     345              : struct is_span : public is_span_oracle<std::remove_cv_t<T>> {};
     346              : 
     347              : template <class T>
     348              : struct is_std_array_oracle : std::false_type {};
     349              : 
     350              : template <class ElementType, std::size_t Extent>
     351              : struct is_std_array_oracle<std::array<ElementType, Extent>> : std::true_type {};
     352              : 
     353              : template <class T>
     354              : struct is_std_array : public is_std_array_oracle<std::remove_cv_t<T>> {};
     355              : 
     356              : template <std::ptrdiff_t From, std::ptrdiff_t To>
     357              : struct is_allowed_extent_conversion
     358              :     : public std::integral_constant<bool, From == To ||
     359              :                                               From == gsl::dynamic_extent ||
     360              :                                               To == gsl::dynamic_extent> {};
     361              : 
     362              : template <class From, class To>
     363              : struct is_allowed_element_type_conversion
     364              :     : public std::integral_constant<
     365              :           bool, std::is_convertible<From (*)[], To (*)[]>::value> {};
     366              : 
     367              : template <class Span, bool IsConst>
     368              : class span_iterator {
     369              :   using element_type_ = typename Span::element_type;
     370              : 
     371              :  public:
     372              :   using iterator_category = std::random_access_iterator_tag;
     373              :   using value_type = std::remove_cv_t<element_type_>;
     374              :   using difference_type = typename Span::index_type;
     375              : 
     376              :   using reference =
     377              :       tmpl::conditional_t<IsConst, const element_type_, element_type_>&;
     378              :   using pointer = std::add_pointer_t<reference>;
     379              : 
     380              :   span_iterator() = default;
     381              : 
     382              :   constexpr span_iterator(const Span* span, typename Span::index_type idx)
     383              :       : span_(span), index_(idx) {}
     384              : 
     385              :   friend span_iterator<Span, true>;
     386              :   template <bool B, Requires<!B && IsConst> = nullptr>
     387              :   constexpr span_iterator(const span_iterator<Span, B>& other)
     388              :       : span_iterator(other.span_, other.index_) {}
     389              : 
     390              :   constexpr reference operator*() const {
     391              :     Expects(index_ != span_->size());
     392              :     return *(span_->data() + index_);
     393              :   }
     394              : 
     395              :   constexpr pointer operator->() const {
     396              :     Expects(index_ != span_->size());
     397              :     return span_->data() + index_;
     398              :   }
     399              : 
     400              :   constexpr span_iterator& operator++() {
     401              :     Expects(0 <= index_ && index_ != span_->size());
     402              :     ++index_;
     403              :     return *this;
     404              :   }
     405              : 
     406              :   constexpr span_iterator operator++(int) {
     407              :     auto ret = *this;
     408              :     ++(*this);
     409              :     return ret;
     410              :   }
     411              : 
     412              :   constexpr span_iterator& operator--() {
     413              :     Expects(index_ != 0 && index_ <= span_->size());
     414              :     --index_;
     415              :     return *this;
     416              :   }
     417              : 
     418              :   constexpr span_iterator operator--(int) {
     419              :     auto ret = *this;
     420              :     --(*this);
     421              :     return ret;
     422              :   }
     423              : 
     424              :   constexpr span_iterator operator+(difference_type n) const {
     425              :     auto ret = *this;
     426              :     return ret += n;
     427              :   }
     428              : 
     429              :   friend constexpr span_iterator operator+(difference_type n,
     430              :                                            span_iterator const& rhs) {
     431              :     return rhs + n;
     432              :   }
     433              : 
     434              :   constexpr span_iterator& operator+=(difference_type n) {
     435              :     Expects((index_ + n) >= 0 && (index_ + n) <= span_->size());
     436              :     index_ += n;
     437              :     return *this;
     438              :   }
     439              : 
     440              :   constexpr span_iterator operator-(difference_type n) const {
     441              :     auto ret = *this;
     442              :     return ret -= n;
     443              :   }
     444              : 
     445              :   constexpr span_iterator& operator-=(difference_type n) { return *this += -n; }
     446              : 
     447              :   constexpr difference_type operator-(span_iterator rhs) const {
     448              :     Expects(span_ == rhs.span_);
     449              :     return index_ - rhs.index_;
     450              :   }
     451              : 
     452              :   constexpr reference operator[](difference_type n) const {
     453              :     return *(*this + n);
     454              :   }
     455              : 
     456              :   constexpr friend bool operator==(span_iterator lhs, span_iterator rhs) {
     457              :     return lhs.span_ == rhs.span_ && lhs.index_ == rhs.index_;
     458              :   }
     459              : 
     460              :   constexpr friend bool operator!=(span_iterator lhs, span_iterator rhs) {
     461              :     return !(lhs == rhs);
     462              :   }
     463              : 
     464              :   constexpr friend bool operator<(span_iterator lhs, span_iterator rhs) {
     465              :     return lhs.index_ < rhs.index_;
     466              :   }
     467              : 
     468              :   constexpr friend bool operator<=(span_iterator lhs, span_iterator rhs) {
     469              :     return !(rhs < lhs);
     470              :   }
     471              : 
     472              :   constexpr friend bool operator>(span_iterator lhs, span_iterator rhs) {
     473              :     return rhs < lhs;
     474              :   }
     475              : 
     476              :   constexpr friend bool operator>=(span_iterator lhs, span_iterator rhs) {
     477              :     return !(rhs > lhs);
     478              :   }
     479              : 
     480              :  protected:
     481              :   const Span* span_ = nullptr;
     482              :   std::ptrdiff_t index_ = 0;
     483              : };
     484              : 
     485              : template <std::ptrdiff_t Ext>
     486              : class extent_type {
     487              :  public:
     488              :   using index_type = std::ptrdiff_t;
     489              : 
     490              :   static_assert(Ext >= 0, "A fixed-size span must be >= 0 in size.");
     491              : 
     492              :   constexpr extent_type() {}
     493              : 
     494              :   template <index_type Other>
     495              :   constexpr extent_type(extent_type<Other> ext) {
     496              :     static_assert(
     497              :         Other == Ext || Other == dynamic_extent,
     498              :         "Mismatch between fixed-size extent and size of initializing data.");
     499              :     Expects(ext.size() == Ext);
     500              :   }
     501              : 
     502              :   constexpr extent_type(index_type size) { Expects(size == Ext); }
     503              : 
     504              :   constexpr index_type size() const { return Ext; }
     505              : };
     506              : 
     507              : template <>
     508              : class extent_type<dynamic_extent> {
     509              :  public:
     510              :   using index_type = std::ptrdiff_t;
     511              : 
     512              :   template <index_type Other>
     513              :   explicit constexpr extent_type(extent_type<Other> ext) : size_(ext.size()) {}
     514              : 
     515              :   explicit constexpr extent_type(index_type size) : size_(size) {
     516              :     Expects(size >= 0);
     517              :   }
     518              : 
     519              :   constexpr index_type size() const { return size_; }
     520              : 
     521              :  private:
     522              :   index_type size_;
     523              : };
     524              : 
     525              : template <class ElementType, std::ptrdiff_t Extent, std::ptrdiff_t Offset,
     526              :           std::ptrdiff_t Count>
     527              : struct calculate_subspan_type {
     528              :   using type =
     529              :       span<ElementType,
     530              :            Count != dynamic_extent
     531              :                ? Count
     532              :                : (Extent != dynamic_extent ? Extent - Offset : Extent)>;
     533              : };
     534              : }  // namespace detail
     535              : 
     536              : /*!
     537              :  * \ingroup UtilitiesGroup
     538              :  * \brief Create a span/view on a range, which is cheap to copy (one pointer).
     539              :  */
     540              : template <class ElementType, std::ptrdiff_t Extent>
     541            1 : class span {
     542              :  public:
     543              :   // constants and types
     544            0 :   using element_type = ElementType;
     545            0 :   using value_type = std::remove_cv_t<ElementType>;
     546            0 :   using index_type = size_t;
     547            0 :   using pointer = element_type*;
     548            0 :   using reference = element_type&;
     549              : 
     550            0 :   using iterator = detail::span_iterator<span<ElementType, Extent>, false>;
     551            0 :   using const_iterator = detail::span_iterator<span<ElementType, Extent>, true>;
     552            0 :   using reverse_iterator = std::reverse_iterator<iterator>;
     553            0 :   using const_reverse_iterator = std::reverse_iterator<const_iterator>;
     554              : 
     555            0 :   using size_type = index_type;
     556              : 
     557            0 :   static constexpr index_type extent{Extent};
     558              : 
     559              :   // [span.cons], span constructors, copy, assignment, and destructor
     560              :   template <bool Dependent = false,
     561              :             // "Dependent" is needed to make "Requires<Dependent ||
     562              :             // Extent <= 0>" SFINAE, since "Requires<Extent <= 0>" is
     563              :             // ill-formed when Extent is greater than 0.
     564              :             Requires<(Dependent || Extent <= 0)> = nullptr>
     565            0 :   constexpr span() : storage_(nullptr, detail::extent_type<0>()) {}
     566              : 
     567            0 :   constexpr span(pointer ptr, index_type count) : storage_(ptr, count) {}
     568              : 
     569            0 :   constexpr span(pointer firstElem, pointer lastElem)
     570              :       : storage_(firstElem, std::distance(firstElem, lastElem)) {}
     571              : 
     572              :   template <std::size_t N>
     573            0 :   constexpr span(element_type (&arr)[N])
     574              :       : storage_(KnownNotNull{std::addressof(arr[0])},
     575              :                  detail::extent_type<N>()) {}
     576              : 
     577              :   template <std::size_t N, Requires<(N > 0)> = nullptr>
     578            0 :   constexpr span(std::array<std::remove_const_t<element_type>, N>& arr)
     579              :       : storage_(KnownNotNull{arr.data()}, detail::extent_type<N>()) {}
     580              : 
     581            0 :   constexpr span(std::array<std::remove_const_t<element_type>, 0>&)
     582              :       : storage_(static_cast<pointer>(nullptr), detail::extent_type<0>()) {}
     583              : 
     584              :   template <std::size_t N, Requires<(N > 0)> = nullptr>
     585            0 :   constexpr span(const std::array<std::remove_const_t<element_type>, N>& arr)
     586              :       : storage_(KnownNotNull{arr.data()}, detail::extent_type<N>()) {}
     587              : 
     588            0 :   constexpr span(const std::array<std::remove_const_t<element_type>, 0>&)
     589              :       : storage_(static_cast<pointer>(nullptr), detail::extent_type<0>()) {}
     590              : 
     591              :   // NB: the SFINAE here uses .data() as a incomplete/imperfect proxy for the
     592              :   // requirement on Container to be a contiguous sequence container.
     593              :   template <
     594              :       class Container,
     595              :       Requires<
     596              :           !detail::is_span<Container>::value &&
     597              :           !detail::is_std_array<Container>::value &&
     598              :           std::is_convertible<typename Container::pointer, pointer>::value &&
     599              :           std::is_convertible<
     600              :               typename Container::pointer,
     601              :               decltype(std::declval<Container>().data())>::value> = nullptr>
     602            0 :   constexpr span(Container& cont)
     603              :       : span(cont.data(), narrow<index_type>(cont.size())) {}
     604              : 
     605              :   template <
     606              :       class Container,
     607              :       Requires<
     608              :           std::is_const<element_type>::value &&
     609              :           !detail::is_span<Container>::value &&
     610              :           std::is_convertible<typename Container::pointer, pointer>::value &&
     611              :           std::is_convertible<
     612              :               typename Container::pointer,
     613              :               decltype(std::declval<Container>().data())>::value> = nullptr>
     614            0 :   constexpr span(const Container& cont)
     615              :       : span(cont.data(), narrow<index_type>(cont.size())) {}
     616              : 
     617            0 :   constexpr span(const span& other) = default;
     618              : 
     619              :   template <class OtherElementType, std::ptrdiff_t OtherExtent,
     620              :             Requires<detail::is_allowed_extent_conversion<OtherExtent,
     621              :                                                           Extent>::value &&
     622              :                      detail::is_allowed_element_type_conversion<
     623              :                          OtherElementType, element_type>::value> = nullptr>
     624            0 :   constexpr span(const span<OtherElementType, OtherExtent>& other)
     625              :       : storage_(other.data(), detail::extent_type<OtherExtent>(other.size())) {
     626              :   }
     627              : 
     628            0 :   ~span() = default;
     629            0 :   constexpr span& operator=(const span& other) = default;
     630              : 
     631              :   // [span.sub], span subviews
     632              :   template <std::ptrdiff_t Count>
     633            0 :   constexpr span<element_type, Count> first() const {
     634              :     Expects(Count >= 0 && Count <= size());
     635              :     return {data(), Count};
     636              :   }
     637              : 
     638              :   template <std::ptrdiff_t Count>
     639            0 :   constexpr span<element_type, Count> last() const {
     640              :     Expects(Count >= 0 && size() - Count >= 0);
     641              :     return {data() + (size() - Count), Count};
     642              :   }
     643              : 
     644              :   template <std::ptrdiff_t Offset, std::ptrdiff_t Count = dynamic_extent>
     645            0 :   constexpr auto subspan() const ->
     646              :       typename detail::calculate_subspan_type<ElementType, Extent, Offset,
     647              :                                               Count>::type {
     648              :     Expects(
     649              :         (Offset >= 0 && size() - Offset >= 0) &&
     650              :         (Count == dynamic_extent || (Count >= 0 && Offset + Count <= size())));
     651              : 
     652              :     return {data() + Offset, Count == dynamic_extent ? size() - Offset : Count};
     653              :   }
     654              : 
     655            0 :   constexpr span<element_type, dynamic_extent> first(index_type count) const {
     656              :     Expects(count >= 0 && count <= size());
     657              :     return {data(), count};
     658              :   }
     659              : 
     660            0 :   constexpr span<element_type, dynamic_extent> last(index_type count) const {
     661              :     return make_subspan(size() - count, dynamic_extent,
     662              :                         subspan_selector<Extent>{});
     663              :   }
     664              : 
     665            0 :   constexpr span<element_type, dynamic_extent> subspan(
     666              :       index_type offset, index_type count = dynamic_extent) const {
     667              :     return make_subspan(offset, count, subspan_selector<Extent>{});
     668              :   }
     669              : 
     670              :   // [span.obs], span observers
     671            0 :   constexpr index_type size() const { return storage_.size(); }
     672            0 :   constexpr index_type size_bytes() const {
     673              :     return size() * narrow_cast<index_type>(sizeof(element_type));
     674              :   }
     675            0 :   constexpr bool empty() const { return size() == 0; }
     676              : 
     677              :   // [span.elem], span element access
     678            0 :   constexpr reference operator[](index_type idx) const {
     679              :     Expects(CheckRange(idx, storage_.size()));
     680              :     return data()[idx];
     681              :   }
     682              : 
     683            0 :   constexpr reference at(index_type idx) const { return this->operator[](idx); }
     684            0 :   constexpr reference operator()(index_type idx) const {
     685              :     return this->operator[](idx);
     686              :   }
     687            0 :   constexpr pointer data() const { return storage_.data(); }
     688              : 
     689              :   // [span.iter], span iterator support
     690            0 :   constexpr iterator begin() const { return {this, 0}; }
     691            0 :   constexpr iterator end() const { return {this, size()}; }
     692              : 
     693            0 :   constexpr const_iterator cbegin() const { return {this, 0}; }
     694            0 :   constexpr const_iterator cend() const { return {this, size()}; }
     695              : 
     696            0 :   constexpr reverse_iterator rbegin() const { return reverse_iterator{end()}; }
     697            0 :   constexpr reverse_iterator rend() const { return reverse_iterator{begin()}; }
     698              : 
     699            0 :   constexpr const_reverse_iterator crbegin() const {
     700              :     return const_reverse_iterator{cend()};
     701              :   }
     702            0 :   constexpr const_reverse_iterator crend() const {
     703              :     return const_reverse_iterator{cbegin()};
     704              :   }
     705              : 
     706              :  private:
     707            0 :   static bool CheckRange(index_type idx, index_type size) {
     708              :     // Optimization:
     709              :     //
     710              :     // idx >= 0 && idx < size
     711              :     // =>
     712              :     // static_cast<size_t>(idx) < static_cast<size_t>(size)
     713              :     //
     714              :     // because size >=0 by span construction, and negative idx will
     715              :     // wrap around to a value always greater than size when casted.
     716              : 
     717              :     // check if we have enough space to wrap around
     718              :     if (sizeof(index_type) <= sizeof(size_t)) {
     719              :       return narrow_cast<size_t>(idx) < narrow_cast<size_t>(size);
     720              :     } else {
     721              :       return idx >= 0 && idx < size;
     722              :     }
     723              :   }
     724              : 
     725              :   // Needed to remove unnecessary null check in subspans
     726            0 :   struct KnownNotNull {
     727            0 :     pointer p;
     728              :   };
     729              : 
     730              :   // this implementation detail class lets us take advantage of the
     731              :   // empty base class optimization to pay for only storage of a single
     732              :   // pointer in the case of fixed-size spans
     733              :   template <class ExtentType>
     734            0 :   class storage_type : public ExtentType {
     735              :    public:
     736              :     // KnownNotNull parameter is needed to remove unnecessary null check
     737              :     // in subspans and constructors from arrays
     738              :     template <class OtherExtentType>
     739            0 :     constexpr storage_type(KnownNotNull data, OtherExtentType ext)
     740              :         : ExtentType(ext), data_(data.p) {
     741              :       Expects(ExtentType::size() >= 0);
     742              :     }
     743              : 
     744              :     template <class OtherExtentType>
     745            0 :     constexpr storage_type(pointer data, OtherExtentType ext)
     746              :         : ExtentType(ext), data_(data) {
     747              :       Expects(ExtentType::size() >= 0);
     748              :       Expects(data || ExtentType::size() == 0);
     749              :     }
     750              : 
     751            0 :     constexpr pointer data() const { return data_; }
     752              : 
     753              :    private:
     754            0 :     pointer data_;
     755              :   };
     756              : 
     757            0 :   storage_type<detail::extent_type<Extent>> storage_;
     758              : 
     759              :   // The rest is needed to remove unnecessary null check
     760              :   // in subspans and constructors from arrays
     761            0 :   constexpr span(KnownNotNull ptr, index_type count) : storage_(ptr, count) {}
     762              : 
     763              :   template <std::ptrdiff_t CallerExtent>
     764            0 :   class subspan_selector {};
     765              : 
     766              :   template <std::ptrdiff_t CallerExtent>
     767            0 :   span<element_type, dynamic_extent> make_subspan(
     768              :       index_type offset, index_type count,
     769              :       subspan_selector<CallerExtent>) const {
     770              :     const span<element_type, dynamic_extent> tmp(*this);
     771              :     return tmp.subspan(offset, count);
     772              :   }
     773              : 
     774            0 :   span<element_type, dynamic_extent> make_subspan(
     775              :       index_type offset, index_type count,
     776              :       subspan_selector<dynamic_extent>) const {
     777              :     Expects(offset >= 0 && size() - offset >= 0);
     778              : 
     779              :     if (count == dynamic_extent) {
     780              :       return {KnownNotNull{data() + offset}, size() - offset};
     781              :     }
     782              : 
     783              :     Expects(count >= 0 && size() - offset >= count);
     784              :     return {KnownNotNull{data() + offset}, count};
     785              :   }
     786              : };
     787              : 
     788              : // [span.comparison], span comparison operators
     789              : template <class ElementType, std::ptrdiff_t FirstExtent,
     790              :           std::ptrdiff_t SecondExtent>
     791            0 : constexpr bool operator==(span<ElementType, FirstExtent> l,
     792              :                           span<ElementType, SecondExtent> r) {
     793              :   return std::equal(l.begin(), l.end(), r.begin(), r.end());
     794              : }
     795              : 
     796              : template <class ElementType, std::ptrdiff_t Extent>
     797            0 : constexpr bool operator!=(span<ElementType, Extent> l,
     798              :                           span<ElementType, Extent> r) {
     799              :   return !(l == r);
     800              : }
     801              : 
     802              : template <class ElementType, std::ptrdiff_t Extent>
     803            0 : constexpr bool operator<(span<ElementType, Extent> l,
     804              :                          span<ElementType, Extent> r) {
     805              :   return std::lexicographical_compare(l.begin(), l.end(), r.begin(), r.end());
     806              : }
     807              : 
     808              : template <class ElementType, std::ptrdiff_t Extent>
     809            0 : constexpr bool operator<=(span<ElementType, Extent> l,
     810              :                           span<ElementType, Extent> r) {
     811              :   return !(l > r);
     812              : }
     813              : 
     814              : template <class ElementType, std::ptrdiff_t Extent>
     815            0 : constexpr bool operator>(span<ElementType, Extent> l,
     816              :                          span<ElementType, Extent> r) {
     817              :   return r < l;
     818              : }
     819              : 
     820              : template <class ElementType, std::ptrdiff_t Extent>
     821            0 : constexpr bool operator>=(span<ElementType, Extent> l,
     822              :                           span<ElementType, Extent> r) {
     823              :   return !(l < r);
     824              : }
     825              : 
     826              : /// @{
     827              : /// \ingroup UtilitiesGroup
     828              : /// Utility function for creating spans
     829              : template <class ElementType>
     830            1 : constexpr span<ElementType> make_span(
     831              :     ElementType* ptr, typename span<ElementType>::index_type count) {
     832              :   return span<ElementType>(ptr, count);
     833              : }
     834              : 
     835              : template <class ElementType>
     836            1 : constexpr span<ElementType> make_span(ElementType* firstElem,
     837              :                                       ElementType* lastElem) {
     838              :   return span<ElementType>(firstElem, lastElem);
     839              : }
     840              : 
     841              : template <class ElementType, std::size_t N>
     842            1 : constexpr span<ElementType, N> make_span(ElementType (&arr)[N]) {
     843              :   return span<ElementType, N>(arr);
     844              : }
     845              : 
     846              : template <class Container>
     847            1 : constexpr span<typename Container::value_type> make_span(Container& cont) {
     848              :   return span<typename Container::value_type>(cont);
     849              : }
     850              : 
     851              : template <class Container>
     852            1 : constexpr span<const typename Container::value_type> make_span(
     853              :     const Container& cont) {
     854              :   return span<const typename Container::value_type>(cont);
     855              : }
     856              : 
     857              : template <class Ptr>
     858            1 : constexpr span<typename Ptr::element_type> make_span(Ptr& cont,
     859              :                                                      std::ptrdiff_t count) {
     860              :   return span<typename Ptr::element_type>(cont, count);
     861              : }
     862              : 
     863              : template <class Ptr>
     864            1 : constexpr span<typename Ptr::element_type> make_span(Ptr& cont) {
     865              :   return span<typename Ptr::element_type>(cont);
     866              : }
     867              : /// @}
     868              : 
     869              : // Specialization of gsl::at for span
     870              : template <class ElementType, std::ptrdiff_t Extent>
     871            0 : constexpr ElementType& at(span<ElementType, Extent> s,
     872              :                           typename span<ElementType, Extent>::index_type i) {
     873              :   // No bounds checking here because it is done in span::operator[] called below
     874              :   return s[i];
     875              : }
     876              : 
     877              : #if __GNUC__ > 6
     878              : #pragma GCC diagnostic pop
     879              : #endif  // __GNUC__ > 6
     880              : 
     881              : template <class ElementType, std::ptrdiff_t Extent>
     882            0 : std::ostream& operator<<(std::ostream& os, const span<ElementType, Extent> t) {
     883              :   os << "(";
     884              :   auto it = t.cbegin();
     885              :   if (it != t.cend()) {
     886              :     os << *it;
     887              :     ++it;
     888              :     for (; it != t.cend(); ++it) {
     889              :       os << ",";
     890              :       os << *it;
     891              :     }
     892              :   }
     893              :   return os << ")";
     894              : }
     895              : }  // namespace gsl
     896              : 
     897              : // The remainder of this file is
     898              : // Distributed under the MIT License.
     899              : // See LICENSE.txt for details.
     900              : 
     901              : /// Construct a not_null from a pointer.  Often this will be done as
     902              : /// an implicit conversion, but it may be necessary to perform the
     903              : /// conversion explicitly when type deduction is desired.
     904              : ///
     905              : /// \note This is not a standard GSL function, and so is not in the
     906              : /// gsl namespace.
     907              : template <typename T>
     908            1 : constexpr gsl::not_null<T*> make_not_null(T* ptr) {
     909              :   return gsl::not_null<T*>(ptr);
     910              : }
        

Generated by: LCOV version 2.0-1