SpECTRE Documentation Coverage Report
Current view: top level - Utilities - Array.hpp Hit Total Coverage
Commit: 3ffcbc8ecf43797401b60bcca17d6040ee06f013 Lines: 2 46 4.3 %
Date: 2026-03-03 02:01:44
Legend: Lines: hit not hit

          Line data    Source code
       1           0 : // Distributed under the MIT License.
       2             : // See LICENSE.txt for details.
       3             : 
       4             : #pragma once
       5             : 
       6             : #include <array>
       7             : #include <cstddef>
       8             : #include <functional>
       9             : #include <iterator>
      10             : #include <ostream>
      11             : #include <utility>
      12             : 
      13             : #include "Utilities/Requires.hpp"
      14             : #include "Utilities/TMPL.hpp"
      15             : #include "Utilities/TypeTraits/IsA.hpp"
      16             : 
      17             : namespace cpp20 {
      18             : namespace detail {
      19             : template <typename T, size_t Size, size_t... Is>
      20             : constexpr std::array<T, Size> convert_to_array(
      21             :     // NOLINTNEXTLINE(modernize-avoid-c-arrays)
      22             :     const T (&t)[Size], std::index_sequence<Is...> /*meta*/) {
      23             :   return {{t[Is]...}};
      24             : }
      25             : }  // namespace detail
      26             : 
      27             : /// \brief A `std::array` implementation with partial C++20 support
      28             : ///
      29             : /// \warning This is not a standard-compliant C++20 `std::array` implementation.
      30             : /// We provide this implementation because we need the `constexpr operator==`
      31             : /// from C++20. Note that other C++20 changes, such as the replacement of the
      32             : /// other comparison operators in favor of `operator<=>`, are not implemented.
      33             : /// This class can be removed when we support C++20.
      34             : template <typename T, size_t Size>
      35           1 : struct array {
      36           0 :   using value_type = T;
      37           0 :   using reference = value_type&;
      38           0 :   using const_reference = const value_type&;
      39           0 :   using iterator = value_type*;
      40           0 :   using const_iterator = const value_type*;
      41           0 :   using pointer = value_type*;
      42           0 :   using const_pointer = const value_type*;
      43           0 :   using size_type = size_t;
      44           0 :   using difference_type = std::ptrdiff_t;
      45           0 :   using reverse_iterator = std::reverse_iterator<iterator>;
      46           0 :   using const_reverse_iterator = std::reverse_iterator<const_iterator>;
      47             : 
      48             :   // clang-tidy: mark explicit. We want implicit conversion
      49             :   constexpr operator std::array<T, Size>() const {  // NOLINT
      50             :     return detail::convert_to_array(data_, std::make_index_sequence<Size>{});
      51             :   }
      52             : 
      53           0 :   constexpr iterator begin() {
      54             :     return iterator(data_);  // NOLINT
      55             :   }
      56           0 :   constexpr const_iterator begin() const {
      57             :     return const_iterator(data_);  // NOLINT
      58             :   }
      59           0 :   constexpr iterator end() {
      60             :     return iterator(data_ + Size);  // NOLINT
      61             :   }
      62           0 :   constexpr const_iterator end() const {
      63             :     return const_iterator(data_ + Size);  // NOLINT
      64             :   }
      65             : 
      66           0 :   constexpr const_iterator cbegin() const { return begin(); }
      67           0 :   constexpr const_iterator cend() const { return end(); }
      68             : 
      69           0 :   constexpr size_type size() const { return Size; }
      70           0 :   constexpr size_type max_size() const { return Size; }
      71           0 :   constexpr bool empty() const { return Size == 0; }
      72             : 
      73           0 :   constexpr reference operator[](const size_type i) {
      74             :     return data_[i];  // NOLINT
      75             :   }
      76           0 :   constexpr const_reference operator[](const size_type i) const {
      77             :     return data_[i];  // NOLINT
      78             :   }
      79             : 
      80           0 :   constexpr reference at(const size_type i) {
      81             :     return data_[i];  // NOLINT
      82             :   }
      83           0 :   constexpr const_reference at(const size_type i) const {
      84             :     return data_[i];  // NOLINT
      85             :   }
      86             : 
      87           0 :   constexpr reference front() { return data_[0]; }
      88           0 :   constexpr const_reference front() const { return data_[0]; }
      89           0 :   constexpr reference back() { return data_[Size > 0 ? Size - 1 : 0]; }
      90           0 :   constexpr const_reference back() const {
      91             :     return data_[Size > 0 ? Size - 1 : 0];
      92             :   }
      93             : 
      94           0 :   constexpr value_type* data() { return data_; }
      95           0 :   constexpr const value_type* data() const { return data_; }
      96             : 
      97             :   // NOLINTNEXTLINE(modernize-avoid-c-arrays)
      98           0 :   value_type data_[Size > 0 ? Size : 1];
      99             : };
     100             : namespace detail {
     101             : template <typename T = void>
     102             : struct Equal {
     103             :   constexpr bool inline operator()(const T& lhs, const T& rhs) const {
     104             :     return lhs == rhs;
     105             :   }
     106             : };
     107             : 
     108             : template <>
     109             : struct Equal<void> {
     110             :   template <class T0, class T1>
     111             :   constexpr bool inline operator()(T0&& lhs, T1&& rhs) const {
     112             :     return std::forward<T0>(lhs) == std::forward<T1>(rhs);
     113             :   }
     114             : };
     115             : }  // namespace detail
     116             : 
     117             : template <typename InputIter1, typename InputIter2,
     118             :           typename BinaryPred = detail::Equal<>>
     119           0 : constexpr bool equal(InputIter1 first1, InputIter1 last1, InputIter2 first2,
     120             :                      BinaryPred pred = detail::Equal<>{}) {
     121             :   for (; first1 != last1; ++first1, ++first2) {
     122             :     if (not pred(*first1, *first2)) {
     123             :       return false;
     124             :     }
     125             :   }
     126             :   return true;
     127             : }
     128             : 
     129             : template <typename InputIter1, typename InputIter2,
     130             :           typename BinaryPred = std::less_equal<>>
     131           0 : constexpr bool lexicographical_compare(InputIter1 first1, InputIter1 last1,
     132             :                                        InputIter2 first2, InputIter2 last2,
     133             :                                        BinaryPred pred = std::less_equal<>{}) {
     134             :   for (; first2 != last2; ++first1, ++first2) {
     135             :     if (first1 == last1 or pred(*first1, *first2)) {
     136             :       return true;
     137             :     } else if (pred(*first2, *first1)) {
     138             :       return false;
     139             :     }
     140             :   }
     141             :   return false;
     142             : }
     143             : 
     144             : template <class T, size_t Size>
     145           0 : inline constexpr bool operator==(const array<T, Size>& x,
     146             :                                  const array<T, Size>& y) {
     147             :   return equal(x.data_, x.data_ + Size, y.data_);  // NOLINT
     148             : }
     149             : 
     150             : template <class T, size_t Size>
     151           0 : inline constexpr bool operator!=(const array<T, Size>& lhs,
     152             :                                  const array<T, Size>& rhs) {
     153             :   return not(lhs == rhs);
     154             : }
     155             : 
     156             : template <class T, size_t Size>
     157           0 : inline constexpr bool operator<(const array<T, Size>& lhs,
     158             :                                 const array<T, Size>& rhs) {
     159             :   return lexicographical_compare(lhs.__elems_, lhs.__elems_ + Size,
     160             :                                  rhs.__elems_, rhs.__elems_ + Size);
     161             : }
     162             : 
     163             : template <class T, size_t Size>
     164           0 : inline constexpr bool operator>(const array<T, Size>& lhs,
     165             :                                 const array<T, Size>& rhs) {
     166             :   return rhs < lhs;
     167             : }
     168             : 
     169             : template <class T, size_t Size>
     170           0 : inline constexpr bool operator<=(const array<T, Size>& lhs,
     171             :                                  const array<T, Size>& rhs) {
     172             :   return not(rhs < lhs);
     173             : }
     174             : 
     175             : template <class T, size_t Size>
     176           0 : inline constexpr bool operator>=(const array<T, Size>& lhs,
     177             :                                  const array<T, Size>& rhs) {
     178             :   return not(lhs < rhs);
     179             : }
     180             : 
     181             : template <typename T>
     182           0 : inline std::ostream& operator<<(std::ostream& os, const array<T, 0>& /*a*/) {
     183             :   return os << "()";
     184             : }
     185             : 
     186             : template <typename T, size_t N>
     187           0 : inline std::ostream& operator<<(std::ostream& os, const array<T, N>& a) {
     188             :   os << '(';
     189             :   for (size_t i = 0; i < N - 1; ++i) {
     190             :     os << a[i] << ',';
     191             :   }
     192             :   if (N > 0) {
     193             :     os << a[N - 1];
     194             :   }
     195             :   os << ')';
     196             :   return os;
     197             : }
     198             : }  // namespace cpp20
     199             : 
     200             : namespace detail {
     201             : template <typename List, size_t... indices,
     202             :           Requires<not tt::is_a_v<tmpl::list, tmpl::front<List>>> = nullptr>
     203             : inline constexpr auto make_cpp20_array_from_list_helper(
     204             :     std::integer_sequence<size_t, indices...> /*meta*/)
     205             :     -> cpp20::array<std::decay_t<decltype(tmpl::front<List>::value)>,
     206             :                     tmpl::size<List>::value> {
     207             :   return cpp20::array<std::decay_t<decltype(tmpl::front<List>::value)>,
     208             :                       tmpl::size<List>::value>{
     209             :       {tmpl::at<List, tmpl::size_t<indices>>::value...}};
     210             : }
     211             : }  // namespace detail
     212             : 
     213             : /// \ingroup ConstantExpressionsGroup
     214             : /// Make an array from a typelist that holds std::integral_constant's all of
     215             : /// which have the same `value_type`
     216             : ///
     217             : /// \tparam List the typelist of std::integral_constant's
     218             : /// \return array of integral values from the typelist
     219             : template <typename List,
     220             :           Requires<not tt::is_a_v<tmpl::list, tmpl::front<List>>> = nullptr>
     221           1 : inline constexpr auto make_cpp20_array_from_list()
     222             :     -> cpp20::array<std::decay_t<decltype(tmpl::front<List>::value)>,
     223             :                     tmpl::size<List>::value> {
     224             :   return detail::make_cpp20_array_from_list_helper<List>(
     225             :       std::make_integer_sequence<size_t, tmpl::size<List>::value>{});
     226             : }
     227             : 
     228             : template <typename TypeForZero,
     229             :           Requires<not tt::is_a_v<tmpl::list, TypeForZero>> = nullptr>
     230             : inline constexpr cpp20::array<std::decay_t<TypeForZero>, 0>
     231           0 : make_cpp20_array_from_list() {
     232             :   return cpp20::array<std::decay_t<TypeForZero>, 0>{{}};
     233             : }
     234             : 
     235             : namespace detail {
     236             : template <typename T, size_t Size, size_t... Is>
     237             : inline constexpr cpp20::array<T, Size> convert_to_cpp20_array_impl(
     238             :     const std::array<T, Size>& t, std::index_sequence<Is...> /*meta*/) {
     239             :   return {{t[Is]...}};
     240             : }
     241             : }  // namespace detail
     242             : 
     243             : template <typename T, size_t Size, size_t... Is>
     244           0 : inline constexpr cpp20::array<T, Size> convert_to_cpp20_array(
     245             :     const std::array<T, Size>& t) {
     246             :   return detail::convert_to_cpp20_array_impl(t,
     247             :                                              std::make_index_sequence<Size>{});
     248             : }

Generated by: LCOV version 1.14