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

Generated by: LCOV version 1.14