SpECTRE Documentation Coverage Report
Current view: top level - Utilities - Algorithm.hpp Coverage Total Hit
Commit: 0d1d717af84a81fb1284a20c4013708fe85cc2f0 Lines: 97.4 % 39 38
Test Date: 2026-10-22 17:29:42
Legend: Lines:     hit not hit

            Line data    Source code
       1            0 : // Distributed under the MIT License.
       2              : // See LICENSE.txt for details.
       3              : #pragma once
       4              : 
       5              : #include <algorithm>
       6              : #include <functional>
       7              : #include <iterator>
       8              : 
       9              : #include "Utilities/Gsl.hpp"
      10              : 
      11            1 : namespace cpp20 {
      12              : /*!
      13              :  * \ingroup UtilitiesGroup
      14              :  * Reimplementation of std::swap that is constexpr;
      15              :  * taken from the LLVM source at
      16              :  * https://github.com/llvm-mirror/libcxx/blob/master/include/type_traits
      17              :  */
      18              : template <class T>
      19            1 : constexpr void swap(T& a, T& b) {
      20              :   T c(std::move(a));
      21              :   a = std::move(b);
      22              :   b = std::move(c);
      23              : }
      24              : 
      25              : /*!
      26              :  * \ingroup UtilitiesGroup
      27              :  * Reimplementation of std::iter_swap that is constexpr;
      28              :  * taken from the LLVM source at
      29              :  * https://github.com/llvm-mirror/libcxx/blob/master/include/type_traits
      30              :  */
      31              : template <class ForwardIt1, class ForwardIt2>
      32            1 : constexpr void iter_swap(ForwardIt1 a, ForwardIt2 b) {
      33              :   swap(*a, *b);
      34              : }
      35              : 
      36              : namespace detail {
      37              : /*!
      38              :  * \ingroup UtilitiesGroup
      39              :  * Reimplementation of std::reverse that is constexpr, for bidirectional
      40              :  * iterators; taken from the LLVM source at
      41              :  * https://github.com/llvm-mirror/libcxx/blob/master/include/algorithm
      42              :  */
      43              : template <class BidirIt>
      44              : constexpr void reverse(BidirIt first, BidirIt last,
      45              :                        std::bidirectional_iterator_tag /* unused */) {
      46              :   while (first != last) {
      47              :     if (first == --last) {
      48              :       break;
      49              :     }
      50              :     cpp20::iter_swap(first, last);
      51              :     ++first;
      52              :   }
      53              : }
      54              : 
      55              : /*!
      56              :  * \ingroup UtilitiesGroup
      57              :  * Reimplementation of std::reverse that is constexpr, for random access
      58              :  * iterators; taken from the LLVM source at
      59              :  * https://github.com/llvm-mirror/libcxx/blob/master/include/algorithm
      60              :  */
      61              : template <class RandomAccessIterator>
      62              : constexpr void reverse(RandomAccessIterator first, RandomAccessIterator last,
      63              :                        std::random_access_iterator_tag /* unused */) {
      64              :   if (first != last) {
      65              :     for (; first < --last; ++first) {
      66              :       cpp20::iter_swap(first, last);
      67              :     }
      68              :   }
      69              : }
      70              : }  // namespace detail
      71              : 
      72              : /*!
      73              :  * \ingroup UtilitiesGroup
      74              :  * Reimplementation of std::reverse that is constexpr;
      75              :  * taken from the LLVM source at
      76              :  * https://github.com/llvm-mirror/libcxx/blob/master/include/algorithm
      77              :  */
      78              : template <class BidirectionalIterator>
      79            1 : constexpr void reverse(BidirectionalIterator first,
      80              :                        BidirectionalIterator last) {
      81              :   cpp20::detail::reverse(first, last,
      82              :                          typename std::iterator_traits<
      83              :                              BidirectionalIterator>::iterator_category());
      84              : }
      85              : 
      86              : /*!
      87              :  * \ingroup UtilitiesGroup
      88              :  * Reimplementation of std::next_permutation that is constexpr,
      89              :  * for a generic comparator; taken from the LLVM source at
      90              :  * https://github.com/llvm-mirror/libcxx/blob/master/include/algorithm
      91              :  */
      92              : template <class Compare, class BidirectionalIterator>
      93            1 : constexpr bool next_permutation(BidirectionalIterator first,
      94              :                                 BidirectionalIterator last, Compare comp) {
      95              :   BidirectionalIterator i = last;
      96              :   if (first == last || first == --i) {
      97              :     return false;
      98              :   }
      99              :   while (true) {
     100              :     BidirectionalIterator ip1 = i;
     101              :     if (comp(*--i, *ip1)) {
     102              :       BidirectionalIterator j = last;
     103              :       while (!comp(*i, *--j)) {
     104              :       }
     105              :       cpp20::swap(*i, *j);
     106              :       cpp20::reverse(ip1, last);
     107              :       return true;
     108              :     }
     109              :     if (i == first) {
     110              :       cpp20::reverse(first, last);
     111              :       return false;
     112              :     }
     113              :   }
     114              : }
     115              : 
     116              : /*!
     117              :  * \ingroup UtilitiesGroup
     118              :  * Reimplementation of std::next_permutation that is constexpr,
     119              :  * with less as the comparator; taken from the LLVM source at
     120              :  * https://github.com/llvm-mirror/libcxx/blob/master/include/algorithm
     121              :  */
     122              : template <class BidirectionalIterator>
     123            1 : constexpr bool next_permutation(BidirectionalIterator first,
     124              :                                 BidirectionalIterator last) {
     125              :   return cpp20::next_permutation(
     126              :       first, last,
     127              :       std::less<
     128              :           typename std::iterator_traits<BidirectionalIterator>::value_type>());
     129              : }
     130              : 
     131              : /*!
     132              :  * \ingroup UtilitiesGroup
     133              :  * Reimplementation of std::find that is constexpr
     134              :  */
     135              : template <class InputIt, class T>
     136            1 : constexpr InputIt find(InputIt first, InputIt last, const T& value) {
     137              :   for (; first != last; ++first) {
     138              :     if (*first == value) {
     139              :       return first;
     140              :     }
     141              :   }
     142              :   return last;
     143              : }
     144              : 
     145              : /*!
     146              :  * \ingroup UtilitiesGroup
     147              :  * Reimplementation of std::find_if that is constexpr
     148              :  */
     149              : template <class InputIt, class UnaryPredicate>
     150            1 : constexpr InputIt find_if(InputIt first, InputIt last, UnaryPredicate p) {
     151              :   for (; first != last; ++first) {
     152              :     if (p(*first)) {
     153              :       return first;
     154              :     }
     155              :   }
     156              :   return last;
     157              : }
     158              : 
     159              : /*!
     160              :  * \ingroup UtilitiesGroup
     161              :  * Reimplementation of std::find_if_not that is constexpr
     162              :  */
     163              : template <class InputIt, class UnaryPredicate>
     164            1 : constexpr InputIt find_if_not(InputIt first, InputIt last, UnaryPredicate q) {
     165              :   for (; first != last; ++first) {
     166              :     if (!q(*first)) {
     167              :       return first;
     168              :     }
     169              :   }
     170              :   return last;
     171              : }
     172              : }  // namespace cpp20
     173              : 
     174              : /*!
     175              :  * \ingroup UtilitiesGroup
     176              :  * \brief Utility functions wrapping STL algorithms and additional algorithms.
     177              :  */
     178            1 : namespace alg {
     179              : /// Convenience wrapper around std::all_of
     180              : template <class Container, class UnaryPredicate>
     181            1 : decltype(auto) all_of(const Container& c, UnaryPredicate&& unary_predicate) {
     182              :   using std::begin;
     183              :   using std::end;
     184              :   return std::all_of(begin(c), end(c),
     185              :                      std::forward<UnaryPredicate>(unary_predicate));
     186              : }
     187              : 
     188              : /// Convenience wrapper around std::any_of
     189              : template <class Container, class UnaryPredicate>
     190            1 : decltype(auto) any_of(const Container& c, UnaryPredicate&& unary_predicate) {
     191              :   using std::begin;
     192              :   using std::end;
     193              :   return std::any_of(begin(c), end(c),
     194              :                      std::forward<UnaryPredicate>(unary_predicate));
     195              : }
     196              : 
     197              : /// Convenience wrapper around std::none_of
     198              : template <class Container, class UnaryPredicate>
     199            1 : decltype(auto) none_of(const Container& c, UnaryPredicate&& unary_predicate) {
     200              :   using std::begin;
     201              :   using std::end;
     202              :   return std::none_of(begin(c), end(c),
     203              :                       std::forward<UnaryPredicate>(unary_predicate));
     204              : }
     205              : 
     206              : /// Convenience wrapper around std::count
     207              : template <class Container, class T>
     208            1 : decltype(auto) count(const Container& c, const T& value) {
     209              :   using std::begin;
     210              :   using std::end;
     211              :   return std::count(begin(c), end(c), value);
     212              : }
     213              : 
     214              : /// Convenience wrapper around std::count_if
     215              : template <class Container, class UnaryPredicate>
     216            1 : decltype(auto) count_if(const Container& c, UnaryPredicate&& unary_predicate) {
     217              :   using std::begin;
     218              :   using std::end;
     219              :   return std::count_if(begin(c), end(c),
     220              :                        std::forward<UnaryPredicate>(unary_predicate));
     221              : }
     222              : 
     223              : /// Convenience wrapper around constexpr reimplementation of std::find
     224              : template <class Container, class T>
     225            1 : constexpr decltype(auto) find(Container&& c, const T& value) {
     226              :   using std::begin;
     227              :   using std::end;
     228              :   return cpp20::find(begin(std::forward<Container>(c)),
     229              :                      end(std::forward<Container>(c)), value);
     230              : }
     231              : 
     232              : /// Convenience wrapper around constexpr reimplementation of std::find_if
     233              : template <class Container, class UnaryPredicate>
     234            1 : constexpr decltype(auto) find_if(Container&& c,
     235              :                                  UnaryPredicate&& unary_predicate) {
     236              :   using std::begin;
     237              :   using std::end;
     238              :   return cpp20::find_if(begin(std::forward<Container>(c)),
     239              :                         end(std::forward<Container>(c)),
     240              :                         std::forward<UnaryPredicate>(unary_predicate));
     241              : }
     242              : 
     243              : /// Convenience wrapper around constexpr reimplementation of std::find_if_not
     244              : template <class Container, class UnaryPredicate>
     245            1 : constexpr decltype(auto) find_if_not(Container&& c,
     246              :                                      UnaryPredicate&& unary_predicate) {
     247              :   using std::begin;
     248              :   using std::end;
     249              :   return cpp20::find_if_not(begin(std::forward<Container>(c)),
     250              :                             end(std::forward<Container>(c)),
     251              :                             std::forward<UnaryPredicate>(unary_predicate));
     252              : }
     253              : 
     254              : /// Convenience wrapper around constexpr reimplementation of std::find, returns
     255              : /// `true` if `value` is in `c`.
     256              : template <class Container, class T>
     257            1 : constexpr bool found(const Container& c, const T& value) {
     258              :   using std::begin;
     259              :   using std::end;
     260              :   return cpp20::find(begin(c), end(c), value) != end(c);
     261              : }
     262              : 
     263              : /// Convenience wrapper around constexpr reimplementation of std::find_if,
     264              : /// returns `true` if the result of `cpp20::find_if` is not equal to `end(c)`.
     265              : template <class Container, class UnaryPredicate>
     266            1 : constexpr bool found_if(const Container& c, UnaryPredicate&& unary_predicate) {
     267              :   using std::begin;
     268              :   using std::end;
     269              :   return cpp20::find_if(begin(c), end(c),
     270              :                         std::forward<UnaryPredicate>(unary_predicate)) !=
     271              :          end(c);
     272              : }
     273              : 
     274              : /// Convenience wrapper around constexpr reimplementation of std::find_if_not,
     275              : /// returns `true` if the result of `cpp20::find_if_not` is not equal to
     276              : /// `end(c)`.
     277              : template <class Container, class UnaryPredicate>
     278            1 : constexpr bool found_if_not(const Container& c,
     279              :                             UnaryPredicate&& unary_predicate) {
     280              :   using std::begin;
     281              :   using std::end;
     282              :   return cpp20::find_if_not(begin(c), end(c),
     283              :                             std::forward<UnaryPredicate>(unary_predicate)) !=
     284              :          end(c);
     285              : }
     286              : 
     287              : /// @{
     288              : /// Convenience wrapper around std::for_each, returns the result of
     289              : /// `std::for_each(begin(c), end(c), f)`.
     290              : template <class Container, class UnaryFunction>
     291            1 : decltype(auto) for_each(const Container& c, UnaryFunction&& f) {
     292              :   using std::begin;
     293              :   using std::end;
     294              :   return std::for_each(begin(c), end(c), std::forward<UnaryFunction>(f));
     295              : }
     296              : 
     297              : template <class Container, class UnaryFunction>
     298            1 : decltype(auto) for_each(Container& c, UnaryFunction&& f) {
     299              :   using std::begin;
     300              :   using std::end;
     301              :   return std::for_each(begin(c), end(c), std::forward<UnaryFunction>(f));
     302              : }
     303              : /// @}
     304              : 
     305              : /// Convenience wrapper around std::equal, assumes containers `lhs` has at least
     306              : /// as many elements as `rhs`.
     307              : template <class Container, class Container2>
     308            1 : decltype(auto) equal(const Container& lhs, const Container2& rhs) {
     309              :   using std::begin;
     310              :   using std::end;
     311              :   return std::equal(begin(lhs), end(lhs), begin(rhs));
     312              : }
     313              : 
     314              : /// Convenience wrapper around std::equal, assumes containers `lhs` has at least
     315              : /// as many elements as `rhs`.
     316              : template <class Container, class Container2, class BinaryPredicate>
     317            1 : decltype(auto) equal(const Container& lhs, const Container2& rhs,
     318              :                      BinaryPredicate&& p) {
     319              :   using std::begin;
     320              :   using std::end;
     321              :   return std::equal(begin(lhs), end(lhs), begin(rhs),
     322              :                     std::forward<BinaryPredicate>(p));
     323              : }
     324              : 
     325              : /// Convenience wrapper around std::max_element
     326              : template <class Container>
     327            1 : constexpr decltype(auto) max_element(const Container& c) {
     328              :   using std::begin;
     329              :   using std::end;
     330              :   return std::max_element(begin(c), end(c));
     331              : }
     332              : 
     333              : /// Convenience wrapper around std::max_element
     334              : template <class Container, class Compare>
     335            1 : constexpr decltype(auto) max_element(const Container& c, Compare&& comp) {
     336              :   using std::begin;
     337              :   using std::end;
     338              :   return std::max_element(begin(c), end(c), std::forward<Compare>(comp));
     339              : }
     340              : 
     341              : /// Convenience wrapper around std::min_element
     342              : template <class Container>
     343            1 : constexpr decltype(auto) min_element(const Container& c) {
     344              :   using std::begin;
     345              :   using std::end;
     346              :   return std::min_element(begin(c), end(c));
     347              : }
     348              : 
     349              : /// Convenience wrapper around std::min_element
     350              : template <class Container, class Compare>
     351            1 : constexpr decltype(auto) min_element(const Container& c, Compare&& comp) {
     352              :   using std::begin;
     353              :   using std::end;
     354              :   return std::min_element(begin(c), end(c), std::forward<Compare>(comp));
     355              : }
     356              : 
     357              : /// Convenience wrapper around std::minmax_element
     358              : template <class Container>
     359            1 : constexpr decltype(auto) minmax_element(const Container& c) {
     360              :   using std::begin;
     361              :   using std::end;
     362              :   return std::minmax_element(begin(c), end(c));
     363              : }
     364              : 
     365              : /// Convenience wrapper around std::minmax_element
     366              : template <class Container, class Compare>
     367            1 : constexpr decltype(auto) minmax_element(const Container& c, Compare&& comp) {
     368              :   using std::begin;
     369              :   using std::end;
     370              :   return std::minmax_element(begin(c), end(c), std::forward<Compare>(comp));
     371              : }
     372              : 
     373              : /// Convenience wrapper around std::remove
     374              : template <class Container, class T>
     375            1 : decltype(auto) remove(Container& c, const T& value) {
     376              :   using std::begin;
     377              :   using std::end;
     378              :   return std::remove(begin(c), end(c), value);
     379              : }
     380              : 
     381              : /// Convenience wrapper around std::remove_if
     382              : template <class Container, class UnaryPredicate>
     383            1 : decltype(auto) remove_if(Container& c, UnaryPredicate&& unary_predicate) {
     384              :   using std::begin;
     385              :   using std::end;
     386              :   return std::remove_if(begin(c), end(c),
     387              :                         std::forward<UnaryPredicate>(unary_predicate));
     388              : }
     389              : 
     390              : /// Convience wrapper around std::sample
     391              : template <class Container, class OutputIt, class Distance, class URBG>
     392            1 : decltype(auto) sample(Container& c, OutputIt out, Distance n, URBG&& g) {
     393              :   using std::begin;
     394              :   using std::end;
     395              :   return std::sample(begin(c), end(c), out, n, g);
     396              : }
     397              : 
     398              : /// Convenience wrapper around std::sort
     399              : template <class Container>
     400            1 : decltype(auto) sort(Container& c) {
     401              :   using std::begin;
     402              :   using std::end;
     403              :   return std::sort(begin(c), end(c));
     404              : }
     405              : 
     406              : /// Convenience wrapper around std::sort
     407              : template <class Container, class Compare>
     408            1 : decltype(auto) sort(Container& c, Compare&& comp) {
     409              :   using std::begin;
     410              :   using std::end;
     411              :   return std::sort(begin(c), end(c), std::forward<Compare>(comp));
     412              : }
     413              : 
     414              : /// Convenience wrapper around std::transform
     415              : template <class Container, class OutputIt, class UnaryOp>
     416            1 : decltype(auto) transform(const Container& c, OutputIt output_first,
     417              :                          UnaryOp&& unary_op) {
     418              :   using std::begin;
     419              :   using std::end;
     420              :   return std::transform(begin(c), end(c), output_first,
     421              :                         std::forward<UnaryOp>(unary_op));
     422              : }
     423              : 
     424              : /// Convenience wrapper around std::transform
     425              : template <class Container1, class Container2, class OutputIt, class BinaryOp>
     426            1 : decltype(auto) transform(const Container1& c1, const Container2& c2,
     427              :                          OutputIt output_first, BinaryOp&& binary_op) {
     428              :   using std::begin;
     429              :   using std::end;
     430              :   return std::transform(begin(c1), end(c1), begin(c2), output_first,
     431              :                         std::forward<BinaryOp>(binary_op));
     432              : }
     433              : }  // namespace alg
        

Generated by: LCOV version 2.0-1