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

Generated by: LCOV version 2.0-1