SpECTRE Documentation Coverage Report
Current view: top level - Utilities - Algorithm.hpp Hit Total Coverage
Commit: 817e13c5144619b701c7cd870655d8dbf94ab8ce Lines: 38 39 97.4 %
Date: 2024-07-19 22:17:05
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 1.14