Commit 00478de3 by Abseil Team Committed by Copybara-Service

Mark non-modifying container algorithms as constexpr for C++20.

This change marks Abseil's non-modifying sequence operations including
absl::linear_search and absl::c_linear_search as constexpr when building with
C++20.
PiperOrigin-RevId: 659812405
Change-Id: I8dc2cee873f30531b2eb8fb3da12085505a43a1a
parent 809e5de7
...@@ -53,8 +53,8 @@ using std::rotate; ...@@ -53,8 +53,8 @@ using std::rotate;
// n = (`last` - `first`) comparisons. A linear search over short containers // n = (`last` - `first`) comparisons. A linear search over short containers
// may be faster than a binary search, even when the container is sorted. // may be faster than a binary search, even when the container is sorted.
template <typename InputIterator, typename EqualityComparable> template <typename InputIterator, typename EqualityComparable>
bool linear_search(InputIterator first, InputIterator last, ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool linear_search(
const EqualityComparable& value) { InputIterator first, InputIterator last, const EqualityComparable& value) {
return std::find(first, last, value) != last; return std::find(first, last, value) != last;
} }
......
...@@ -14,11 +14,9 @@ ...@@ -14,11 +14,9 @@
#include "absl/algorithm/algorithm.h" #include "absl/algorithm/algorithm.h"
#include <algorithm> #include <array>
#include <list>
#include <vector> #include <vector>
#include "gmock/gmock.h"
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "absl/base/config.h" #include "absl/base/config.h"
...@@ -47,4 +45,16 @@ TEST_F(LinearSearchTest, linear_searchConst) { ...@@ -47,4 +45,16 @@ TEST_F(LinearSearchTest, linear_searchConst) {
absl::linear_search(const_container->begin(), const_container->end(), 4)); absl::linear_search(const_container->begin(), const_container->end(), 4));
} }
#if defined(ABSL_INTERNAL_CPLUSPLUS_LANG) && \
ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L
TEST_F(LinearSearchTest, Constexpr) {
static constexpr std::array<int, 3> kArray = {1, 2, 3};
static_assert(absl::linear_search(kArray.begin(), kArray.end(), 3));
static_assert(!absl::linear_search(kArray.begin(), kArray.end(), 4));
}
#endif // defined(ABSL_INTERNAL_CPLUSPLUS_LANG) &&
// ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L
} // namespace } // namespace
...@@ -132,7 +132,8 @@ struct IsUnorderedContainer<std::unordered_set<Key, Hash, KeyEqual, Allocator>> ...@@ -132,7 +132,8 @@ struct IsUnorderedContainer<std::unordered_set<Key, Hash, KeyEqual, Allocator>>
// Container-based version of absl::linear_search() for performing a linear // Container-based version of absl::linear_search() for performing a linear
// search within a container. // search within a container.
template <typename C, typename EqualityComparable> template <typename C, typename EqualityComparable>
bool c_linear_search(const C& c, EqualityComparable&& value) { ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool c_linear_search(
const C& c, EqualityComparable&& value) {
return linear_search(container_algorithm_internal::c_begin(c), return linear_search(container_algorithm_internal::c_begin(c),
container_algorithm_internal::c_end(c), container_algorithm_internal::c_end(c),
std::forward<EqualityComparable>(value)); std::forward<EqualityComparable>(value));
...@@ -163,7 +164,7 @@ ABSL_INTERNAL_CONSTEXPR_SINCE_CXX17 ...@@ -163,7 +164,7 @@ ABSL_INTERNAL_CONSTEXPR_SINCE_CXX17
// Container-based version of the <algorithm> `std::all_of()` function to // Container-based version of the <algorithm> `std::all_of()` function to
// test if all elements within a container satisfy a condition. // test if all elements within a container satisfy a condition.
template <typename C, typename Pred> template <typename C, typename Pred>
bool c_all_of(const C& c, Pred&& pred) { ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool c_all_of(const C& c, Pred&& pred) {
return std::all_of(container_algorithm_internal::c_begin(c), return std::all_of(container_algorithm_internal::c_begin(c),
container_algorithm_internal::c_end(c), container_algorithm_internal::c_end(c),
std::forward<Pred>(pred)); std::forward<Pred>(pred));
...@@ -174,7 +175,7 @@ bool c_all_of(const C& c, Pred&& pred) { ...@@ -174,7 +175,7 @@ bool c_all_of(const C& c, Pred&& pred) {
// Container-based version of the <algorithm> `std::any_of()` function to // Container-based version of the <algorithm> `std::any_of()` function to
// test if any element in a container fulfills a condition. // test if any element in a container fulfills a condition.
template <typename C, typename Pred> template <typename C, typename Pred>
bool c_any_of(const C& c, Pred&& pred) { ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool c_any_of(const C& c, Pred&& pred) {
return std::any_of(container_algorithm_internal::c_begin(c), return std::any_of(container_algorithm_internal::c_begin(c),
container_algorithm_internal::c_end(c), container_algorithm_internal::c_end(c),
std::forward<Pred>(pred)); std::forward<Pred>(pred));
...@@ -185,7 +186,7 @@ bool c_any_of(const C& c, Pred&& pred) { ...@@ -185,7 +186,7 @@ bool c_any_of(const C& c, Pred&& pred) {
// Container-based version of the <algorithm> `std::none_of()` function to // Container-based version of the <algorithm> `std::none_of()` function to
// test if no elements in a container fulfill a condition. // test if no elements in a container fulfill a condition.
template <typename C, typename Pred> template <typename C, typename Pred>
bool c_none_of(const C& c, Pred&& pred) { ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool c_none_of(const C& c, Pred&& pred) {
return std::none_of(container_algorithm_internal::c_begin(c), return std::none_of(container_algorithm_internal::c_begin(c),
container_algorithm_internal::c_end(c), container_algorithm_internal::c_end(c),
std::forward<Pred>(pred)); std::forward<Pred>(pred));
...@@ -196,7 +197,8 @@ bool c_none_of(const C& c, Pred&& pred) { ...@@ -196,7 +197,8 @@ bool c_none_of(const C& c, Pred&& pred) {
// Container-based version of the <algorithm> `std::for_each()` function to // Container-based version of the <algorithm> `std::for_each()` function to
// apply a function to a container's elements. // apply a function to a container's elements.
template <typename C, typename Function> template <typename C, typename Function>
decay_t<Function> c_for_each(C&& c, Function&& f) { ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 decay_t<Function> c_for_each(C&& c,
Function&& f) {
return std::for_each(container_algorithm_internal::c_begin(c), return std::for_each(container_algorithm_internal::c_begin(c),
container_algorithm_internal::c_end(c), container_algorithm_internal::c_end(c),
std::forward<Function>(f)); std::forward<Function>(f));
...@@ -207,7 +209,9 @@ decay_t<Function> c_for_each(C&& c, Function&& f) { ...@@ -207,7 +209,9 @@ decay_t<Function> c_for_each(C&& c, Function&& f) {
// Container-based version of the <algorithm> `std::find()` function to find // Container-based version of the <algorithm> `std::find()` function to find
// the first element containing the passed value within a container value. // the first element containing the passed value within a container value.
template <typename C, typename T> template <typename C, typename T>
container_algorithm_internal::ContainerIter<C> c_find(C& c, T&& value) { ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20
container_algorithm_internal::ContainerIter<C>
c_find(C& c, T&& value) {
return std::find(container_algorithm_internal::c_begin(c), return std::find(container_algorithm_internal::c_begin(c),
container_algorithm_internal::c_end(c), container_algorithm_internal::c_end(c),
std::forward<T>(value)); std::forward<T>(value));
...@@ -218,7 +222,8 @@ container_algorithm_internal::ContainerIter<C> c_find(C& c, T&& value) { ...@@ -218,7 +222,8 @@ container_algorithm_internal::ContainerIter<C> c_find(C& c, T&& value) {
// Container-based version of the <algorithm> `std::ranges::contains()` C++23 // Container-based version of the <algorithm> `std::ranges::contains()` C++23
// function to search a container for a value. // function to search a container for a value.
template <typename Sequence, typename T> template <typename Sequence, typename T>
bool c_contains(const Sequence& sequence, T&& value) { ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool c_contains(const Sequence& sequence,
T&& value) {
return absl::c_find(sequence, std::forward<T>(value)) != return absl::c_find(sequence, std::forward<T>(value)) !=
container_algorithm_internal::c_end(sequence); container_algorithm_internal::c_end(sequence);
} }
...@@ -228,7 +233,9 @@ bool c_contains(const Sequence& sequence, T&& value) { ...@@ -228,7 +233,9 @@ bool c_contains(const Sequence& sequence, T&& value) {
// Container-based version of the <algorithm> `std::find_if()` function to find // Container-based version of the <algorithm> `std::find_if()` function to find
// the first element in a container matching the given condition. // the first element in a container matching the given condition.
template <typename C, typename Pred> template <typename C, typename Pred>
container_algorithm_internal::ContainerIter<C> c_find_if(C& c, Pred&& pred) { ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20
container_algorithm_internal::ContainerIter<C>
c_find_if(C& c, Pred&& pred) {
return std::find_if(container_algorithm_internal::c_begin(c), return std::find_if(container_algorithm_internal::c_begin(c),
container_algorithm_internal::c_end(c), container_algorithm_internal::c_end(c),
std::forward<Pred>(pred)); std::forward<Pred>(pred));
...@@ -239,8 +246,9 @@ container_algorithm_internal::ContainerIter<C> c_find_if(C& c, Pred&& pred) { ...@@ -239,8 +246,9 @@ container_algorithm_internal::ContainerIter<C> c_find_if(C& c, Pred&& pred) {
// Container-based version of the <algorithm> `std::find_if_not()` function to // Container-based version of the <algorithm> `std::find_if_not()` function to
// find the first element in a container not matching the given condition. // find the first element in a container not matching the given condition.
template <typename C, typename Pred> template <typename C, typename Pred>
container_algorithm_internal::ContainerIter<C> c_find_if_not(C& c, ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20
Pred&& pred) { container_algorithm_internal::ContainerIter<C>
c_find_if_not(C& c, Pred&& pred) {
return std::find_if_not(container_algorithm_internal::c_begin(c), return std::find_if_not(container_algorithm_internal::c_begin(c),
container_algorithm_internal::c_end(c), container_algorithm_internal::c_end(c),
std::forward<Pred>(pred)); std::forward<Pred>(pred));
...@@ -251,8 +259,9 @@ container_algorithm_internal::ContainerIter<C> c_find_if_not(C& c, ...@@ -251,8 +259,9 @@ container_algorithm_internal::ContainerIter<C> c_find_if_not(C& c,
// Container-based version of the <algorithm> `std::find_end()` function to // Container-based version of the <algorithm> `std::find_end()` function to
// find the last subsequence within a container. // find the last subsequence within a container.
template <typename Sequence1, typename Sequence2> template <typename Sequence1, typename Sequence2>
container_algorithm_internal::ContainerIter<Sequence1> c_find_end( ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20
Sequence1& sequence, Sequence2& subsequence) { container_algorithm_internal::ContainerIter<Sequence1>
c_find_end(Sequence1& sequence, Sequence2& subsequence) {
return std::find_end(container_algorithm_internal::c_begin(sequence), return std::find_end(container_algorithm_internal::c_begin(sequence),
container_algorithm_internal::c_end(sequence), container_algorithm_internal::c_end(sequence),
container_algorithm_internal::c_begin(subsequence), container_algorithm_internal::c_begin(subsequence),
...@@ -262,8 +271,10 @@ container_algorithm_internal::ContainerIter<Sequence1> c_find_end( ...@@ -262,8 +271,10 @@ container_algorithm_internal::ContainerIter<Sequence1> c_find_end(
// Overload of c_find_end() for using a predicate evaluation other than `==` as // Overload of c_find_end() for using a predicate evaluation other than `==` as
// the function's test condition. // the function's test condition.
template <typename Sequence1, typename Sequence2, typename BinaryPredicate> template <typename Sequence1, typename Sequence2, typename BinaryPredicate>
container_algorithm_internal::ContainerIter<Sequence1> c_find_end( ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20
Sequence1& sequence, Sequence2& subsequence, BinaryPredicate&& pred) { container_algorithm_internal::ContainerIter<Sequence1>
c_find_end(Sequence1& sequence, Sequence2& subsequence,
BinaryPredicate&& pred) {
return std::find_end(container_algorithm_internal::c_begin(sequence), return std::find_end(container_algorithm_internal::c_begin(sequence),
container_algorithm_internal::c_end(sequence), container_algorithm_internal::c_end(sequence),
container_algorithm_internal::c_begin(subsequence), container_algorithm_internal::c_begin(subsequence),
...@@ -277,8 +288,9 @@ container_algorithm_internal::ContainerIter<Sequence1> c_find_end( ...@@ -277,8 +288,9 @@ container_algorithm_internal::ContainerIter<Sequence1> c_find_end(
// find the first element within the container that is also within the options // find the first element within the container that is also within the options
// container. // container.
template <typename C1, typename C2> template <typename C1, typename C2>
container_algorithm_internal::ContainerIter<C1> c_find_first_of(C1& container, ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20
C2& options) { container_algorithm_internal::ContainerIter<C1>
c_find_first_of(C1& container, C2& options) {
return std::find_first_of(container_algorithm_internal::c_begin(container), return std::find_first_of(container_algorithm_internal::c_begin(container),
container_algorithm_internal::c_end(container), container_algorithm_internal::c_end(container),
container_algorithm_internal::c_begin(options), container_algorithm_internal::c_begin(options),
...@@ -288,8 +300,9 @@ container_algorithm_internal::ContainerIter<C1> c_find_first_of(C1& container, ...@@ -288,8 +300,9 @@ container_algorithm_internal::ContainerIter<C1> c_find_first_of(C1& container,
// Overload of c_find_first_of() for using a predicate evaluation other than // Overload of c_find_first_of() for using a predicate evaluation other than
// `==` as the function's test condition. // `==` as the function's test condition.
template <typename C1, typename C2, typename BinaryPredicate> template <typename C1, typename C2, typename BinaryPredicate>
container_algorithm_internal::ContainerIter<C1> c_find_first_of( ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20
C1& container, C2& options, BinaryPredicate&& pred) { container_algorithm_internal::ContainerIter<C1>
c_find_first_of(C1& container, C2& options, BinaryPredicate&& pred) {
return std::find_first_of(container_algorithm_internal::c_begin(container), return std::find_first_of(container_algorithm_internal::c_begin(container),
container_algorithm_internal::c_end(container), container_algorithm_internal::c_end(container),
container_algorithm_internal::c_begin(options), container_algorithm_internal::c_begin(options),
...@@ -302,8 +315,9 @@ container_algorithm_internal::ContainerIter<C1> c_find_first_of( ...@@ -302,8 +315,9 @@ container_algorithm_internal::ContainerIter<C1> c_find_first_of(
// Container-based version of the <algorithm> `std::adjacent_find()` function to // Container-based version of the <algorithm> `std::adjacent_find()` function to
// find equal adjacent elements within a container. // find equal adjacent elements within a container.
template <typename Sequence> template <typename Sequence>
container_algorithm_internal::ContainerIter<Sequence> c_adjacent_find( ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20
Sequence& sequence) { container_algorithm_internal::ContainerIter<Sequence>
c_adjacent_find(Sequence& sequence) {
return std::adjacent_find(container_algorithm_internal::c_begin(sequence), return std::adjacent_find(container_algorithm_internal::c_begin(sequence),
container_algorithm_internal::c_end(sequence)); container_algorithm_internal::c_end(sequence));
} }
...@@ -311,8 +325,9 @@ container_algorithm_internal::ContainerIter<Sequence> c_adjacent_find( ...@@ -311,8 +325,9 @@ container_algorithm_internal::ContainerIter<Sequence> c_adjacent_find(
// Overload of c_adjacent_find() for using a predicate evaluation other than // Overload of c_adjacent_find() for using a predicate evaluation other than
// `==` as the function's test condition. // `==` as the function's test condition.
template <typename Sequence, typename BinaryPredicate> template <typename Sequence, typename BinaryPredicate>
container_algorithm_internal::ContainerIter<Sequence> c_adjacent_find( ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20
Sequence& sequence, BinaryPredicate&& pred) { container_algorithm_internal::ContainerIter<Sequence>
c_adjacent_find(Sequence& sequence, BinaryPredicate&& pred) {
return std::adjacent_find(container_algorithm_internal::c_begin(sequence), return std::adjacent_find(container_algorithm_internal::c_begin(sequence),
container_algorithm_internal::c_end(sequence), container_algorithm_internal::c_end(sequence),
std::forward<BinaryPredicate>(pred)); std::forward<BinaryPredicate>(pred));
...@@ -323,8 +338,9 @@ container_algorithm_internal::ContainerIter<Sequence> c_adjacent_find( ...@@ -323,8 +338,9 @@ container_algorithm_internal::ContainerIter<Sequence> c_adjacent_find(
// Container-based version of the <algorithm> `std::count()` function to count // Container-based version of the <algorithm> `std::count()` function to count
// values that match within a container. // values that match within a container.
template <typename C, typename T> template <typename C, typename T>
container_algorithm_internal::ContainerDifferenceType<const C> c_count( ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20
const C& c, T&& value) { container_algorithm_internal::ContainerDifferenceType<const C>
c_count(const C& c, T&& value) {
return std::count(container_algorithm_internal::c_begin(c), return std::count(container_algorithm_internal::c_begin(c),
container_algorithm_internal::c_end(c), container_algorithm_internal::c_end(c),
std::forward<T>(value)); std::forward<T>(value));
...@@ -335,8 +351,9 @@ container_algorithm_internal::ContainerDifferenceType<const C> c_count( ...@@ -335,8 +351,9 @@ container_algorithm_internal::ContainerDifferenceType<const C> c_count(
// Container-based version of the <algorithm> `std::count_if()` function to // Container-based version of the <algorithm> `std::count_if()` function to
// count values matching a condition within a container. // count values matching a condition within a container.
template <typename C, typename Pred> template <typename C, typename Pred>
container_algorithm_internal::ContainerDifferenceType<const C> c_count_if( ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20
const C& c, Pred&& pred) { container_algorithm_internal::ContainerDifferenceType<const C>
c_count_if(const C& c, Pred&& pred) {
return std::count_if(container_algorithm_internal::c_begin(c), return std::count_if(container_algorithm_internal::c_begin(c),
container_algorithm_internal::c_end(c), container_algorithm_internal::c_end(c),
std::forward<Pred>(pred)); std::forward<Pred>(pred));
...@@ -348,8 +365,9 @@ container_algorithm_internal::ContainerDifferenceType<const C> c_count_if( ...@@ -348,8 +365,9 @@ container_algorithm_internal::ContainerDifferenceType<const C> c_count_if(
// return the first element where two ordered containers differ. Applies `==` to // return the first element where two ordered containers differ. Applies `==` to
// the first N elements of `c1` and `c2`, where N = min(size(c1), size(c2)). // the first N elements of `c1` and `c2`, where N = min(size(c1), size(c2)).
template <typename C1, typename C2> template <typename C1, typename C2>
container_algorithm_internal::ContainerIterPairType<C1, C2> c_mismatch(C1& c1, ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20
C2& c2) { container_algorithm_internal::ContainerIterPairType<C1, C2>
c_mismatch(C1& c1, C2& c2) {
return std::mismatch(container_algorithm_internal::c_begin(c1), return std::mismatch(container_algorithm_internal::c_begin(c1),
container_algorithm_internal::c_end(c1), container_algorithm_internal::c_end(c1),
container_algorithm_internal::c_begin(c2), container_algorithm_internal::c_begin(c2),
...@@ -360,8 +378,9 @@ container_algorithm_internal::ContainerIterPairType<C1, C2> c_mismatch(C1& c1, ...@@ -360,8 +378,9 @@ container_algorithm_internal::ContainerIterPairType<C1, C2> c_mismatch(C1& c1,
// the function's test condition. Applies `pred`to the first N elements of `c1` // the function's test condition. Applies `pred`to the first N elements of `c1`
// and `c2`, where N = min(size(c1), size(c2)). // and `c2`, where N = min(size(c1), size(c2)).
template <typename C1, typename C2, typename BinaryPredicate> template <typename C1, typename C2, typename BinaryPredicate>
container_algorithm_internal::ContainerIterPairType<C1, C2> c_mismatch( ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20
C1& c1, C2& c2, BinaryPredicate pred) { container_algorithm_internal::ContainerIterPairType<C1, C2>
c_mismatch(C1& c1, C2& c2, BinaryPredicate pred) {
return std::mismatch(container_algorithm_internal::c_begin(c1), return std::mismatch(container_algorithm_internal::c_begin(c1),
container_algorithm_internal::c_end(c1), container_algorithm_internal::c_end(c1),
container_algorithm_internal::c_begin(c2), container_algorithm_internal::c_begin(c2),
...@@ -373,7 +392,7 @@ container_algorithm_internal::ContainerIterPairType<C1, C2> c_mismatch( ...@@ -373,7 +392,7 @@ container_algorithm_internal::ContainerIterPairType<C1, C2> c_mismatch(
// Container-based version of the <algorithm> `std::equal()` function to // Container-based version of the <algorithm> `std::equal()` function to
// test whether two containers are equal. // test whether two containers are equal.
template <typename C1, typename C2> template <typename C1, typename C2>
bool c_equal(const C1& c1, const C2& c2) { ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool c_equal(const C1& c1, const C2& c2) {
return std::equal(container_algorithm_internal::c_begin(c1), return std::equal(container_algorithm_internal::c_begin(c1),
container_algorithm_internal::c_end(c1), container_algorithm_internal::c_end(c1),
container_algorithm_internal::c_begin(c2), container_algorithm_internal::c_begin(c2),
...@@ -383,7 +402,8 @@ bool c_equal(const C1& c1, const C2& c2) { ...@@ -383,7 +402,8 @@ bool c_equal(const C1& c1, const C2& c2) {
// Overload of c_equal() for using a predicate evaluation other than `==` as // Overload of c_equal() for using a predicate evaluation other than `==` as
// the function's test condition. // the function's test condition.
template <typename C1, typename C2, typename BinaryPredicate> template <typename C1, typename C2, typename BinaryPredicate>
bool c_equal(const C1& c1, const C2& c2, BinaryPredicate&& pred) { ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool c_equal(const C1& c1, const C2& c2,
BinaryPredicate&& pred) {
return std::equal(container_algorithm_internal::c_begin(c1), return std::equal(container_algorithm_internal::c_begin(c1),
container_algorithm_internal::c_end(c1), container_algorithm_internal::c_end(c1),
container_algorithm_internal::c_begin(c2), container_algorithm_internal::c_begin(c2),
...@@ -396,7 +416,8 @@ bool c_equal(const C1& c1, const C2& c2, BinaryPredicate&& pred) { ...@@ -396,7 +416,8 @@ bool c_equal(const C1& c1, const C2& c2, BinaryPredicate&& pred) {
// Container-based version of the <algorithm> `std::is_permutation()` function // Container-based version of the <algorithm> `std::is_permutation()` function
// to test whether a container is a permutation of another. // to test whether a container is a permutation of another.
template <typename C1, typename C2> template <typename C1, typename C2>
bool c_is_permutation(const C1& c1, const C2& c2) { ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool c_is_permutation(const C1& c1,
const C2& c2) {
return std::is_permutation(container_algorithm_internal::c_begin(c1), return std::is_permutation(container_algorithm_internal::c_begin(c1),
container_algorithm_internal::c_end(c1), container_algorithm_internal::c_end(c1),
container_algorithm_internal::c_begin(c2), container_algorithm_internal::c_begin(c2),
...@@ -406,7 +427,8 @@ bool c_is_permutation(const C1& c1, const C2& c2) { ...@@ -406,7 +427,8 @@ bool c_is_permutation(const C1& c1, const C2& c2) {
// Overload of c_is_permutation() for using a predicate evaluation other than // Overload of c_is_permutation() for using a predicate evaluation other than
// `==` as the function's test condition. // `==` as the function's test condition.
template <typename C1, typename C2, typename BinaryPredicate> template <typename C1, typename C2, typename BinaryPredicate>
bool c_is_permutation(const C1& c1, const C2& c2, BinaryPredicate&& pred) { ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool c_is_permutation(
const C1& c1, const C2& c2, BinaryPredicate&& pred) {
return std::is_permutation(container_algorithm_internal::c_begin(c1), return std::is_permutation(container_algorithm_internal::c_begin(c1),
container_algorithm_internal::c_end(c1), container_algorithm_internal::c_end(c1),
container_algorithm_internal::c_begin(c2), container_algorithm_internal::c_begin(c2),
...@@ -419,8 +441,9 @@ bool c_is_permutation(const C1& c1, const C2& c2, BinaryPredicate&& pred) { ...@@ -419,8 +441,9 @@ bool c_is_permutation(const C1& c1, const C2& c2, BinaryPredicate&& pred) {
// Container-based version of the <algorithm> `std::search()` function to search // Container-based version of the <algorithm> `std::search()` function to search
// a container for a subsequence. // a container for a subsequence.
template <typename Sequence1, typename Sequence2> template <typename Sequence1, typename Sequence2>
container_algorithm_internal::ContainerIter<Sequence1> c_search( ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20
Sequence1& sequence, Sequence2& subsequence) { container_algorithm_internal::ContainerIter<Sequence1>
c_search(Sequence1& sequence, Sequence2& subsequence) {
return std::search(container_algorithm_internal::c_begin(sequence), return std::search(container_algorithm_internal::c_begin(sequence),
container_algorithm_internal::c_end(sequence), container_algorithm_internal::c_end(sequence),
container_algorithm_internal::c_begin(subsequence), container_algorithm_internal::c_begin(subsequence),
...@@ -430,8 +453,10 @@ container_algorithm_internal::ContainerIter<Sequence1> c_search( ...@@ -430,8 +453,10 @@ container_algorithm_internal::ContainerIter<Sequence1> c_search(
// Overload of c_search() for using a predicate evaluation other than // Overload of c_search() for using a predicate evaluation other than
// `==` as the function's test condition. // `==` as the function's test condition.
template <typename Sequence1, typename Sequence2, typename BinaryPredicate> template <typename Sequence1, typename Sequence2, typename BinaryPredicate>
container_algorithm_internal::ContainerIter<Sequence1> c_search( ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20
Sequence1& sequence, Sequence2& subsequence, BinaryPredicate&& pred) { container_algorithm_internal::ContainerIter<Sequence1>
c_search(Sequence1& sequence, Sequence2& subsequence,
BinaryPredicate&& pred) {
return std::search(container_algorithm_internal::c_begin(sequence), return std::search(container_algorithm_internal::c_begin(sequence),
container_algorithm_internal::c_end(sequence), container_algorithm_internal::c_end(sequence),
container_algorithm_internal::c_begin(subsequence), container_algorithm_internal::c_begin(subsequence),
...@@ -444,7 +469,8 @@ container_algorithm_internal::ContainerIter<Sequence1> c_search( ...@@ -444,7 +469,8 @@ container_algorithm_internal::ContainerIter<Sequence1> c_search(
// Container-based version of the <algorithm> `std::ranges::contains_subrange()` // Container-based version of the <algorithm> `std::ranges::contains_subrange()`
// C++23 function to search a container for a subsequence. // C++23 function to search a container for a subsequence.
template <typename Sequence1, typename Sequence2> template <typename Sequence1, typename Sequence2>
bool c_contains_subrange(Sequence1& sequence, Sequence2& subsequence) { ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool c_contains_subrange(
Sequence1& sequence, Sequence2& subsequence) {
return absl::c_search(sequence, subsequence) != return absl::c_search(sequence, subsequence) !=
container_algorithm_internal::c_end(sequence); container_algorithm_internal::c_end(sequence);
} }
...@@ -452,8 +478,8 @@ bool c_contains_subrange(Sequence1& sequence, Sequence2& subsequence) { ...@@ -452,8 +478,8 @@ bool c_contains_subrange(Sequence1& sequence, Sequence2& subsequence) {
// Overload of c_contains_subrange() for using a predicate evaluation other than // Overload of c_contains_subrange() for using a predicate evaluation other than
// `==` as the function's test condition. // `==` as the function's test condition.
template <typename Sequence1, typename Sequence2, typename BinaryPredicate> template <typename Sequence1, typename Sequence2, typename BinaryPredicate>
bool c_contains_subrange(Sequence1& sequence, Sequence2& subsequence, ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool c_contains_subrange(
BinaryPredicate&& pred) { Sequence1& sequence, Sequence2& subsequence, BinaryPredicate&& pred) {
return absl::c_search(sequence, subsequence, return absl::c_search(sequence, subsequence,
std::forward<BinaryPredicate>(pred)) != std::forward<BinaryPredicate>(pred)) !=
container_algorithm_internal::c_end(sequence); container_algorithm_internal::c_end(sequence);
...@@ -464,8 +490,9 @@ bool c_contains_subrange(Sequence1& sequence, Sequence2& subsequence, ...@@ -464,8 +490,9 @@ bool c_contains_subrange(Sequence1& sequence, Sequence2& subsequence,
// Container-based version of the <algorithm> `std::search_n()` function to // Container-based version of the <algorithm> `std::search_n()` function to
// search a container for the first sequence of N elements. // search a container for the first sequence of N elements.
template <typename Sequence, typename Size, typename T> template <typename Sequence, typename Size, typename T>
container_algorithm_internal::ContainerIter<Sequence> c_search_n( ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20
Sequence& sequence, Size count, T&& value) { container_algorithm_internal::ContainerIter<Sequence>
c_search_n(Sequence& sequence, Size count, T&& value) {
return std::search_n(container_algorithm_internal::c_begin(sequence), return std::search_n(container_algorithm_internal::c_begin(sequence),
container_algorithm_internal::c_end(sequence), count, container_algorithm_internal::c_end(sequence), count,
std::forward<T>(value)); std::forward<T>(value));
...@@ -475,8 +502,10 @@ container_algorithm_internal::ContainerIter<Sequence> c_search_n( ...@@ -475,8 +502,10 @@ container_algorithm_internal::ContainerIter<Sequence> c_search_n(
// `==` as the function's test condition. // `==` as the function's test condition.
template <typename Sequence, typename Size, typename T, template <typename Sequence, typename Size, typename T,
typename BinaryPredicate> typename BinaryPredicate>
container_algorithm_internal::ContainerIter<Sequence> c_search_n( ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20
Sequence& sequence, Size count, T&& value, BinaryPredicate&& pred) { container_algorithm_internal::ContainerIter<Sequence>
c_search_n(Sequence& sequence, Size count, T&& value,
BinaryPredicate&& pred) {
return std::search_n(container_algorithm_internal::c_begin(sequence), return std::search_n(container_algorithm_internal::c_begin(sequence),
container_algorithm_internal::c_end(sequence), count, container_algorithm_internal::c_end(sequence), count,
std::forward<T>(value), std::forward<T>(value),
......
...@@ -1164,6 +1164,7 @@ TEST(MutatingTest, PermutationOperations) { ...@@ -1164,6 +1164,7 @@ TEST(MutatingTest, PermutationOperations) {
#if defined(ABSL_INTERNAL_CPLUSPLUS_LANG) && \ #if defined(ABSL_INTERNAL_CPLUSPLUS_LANG) && \
ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L
TEST(ConstexprTest, Distance) { TEST(ConstexprTest, Distance) {
// Works at compile time with constexpr containers. // Works at compile time with constexpr containers.
static_assert(absl::c_distance(std::array<int, 3>()) == 3); static_assert(absl::c_distance(std::array<int, 3>()) == 3);
...@@ -1203,8 +1204,216 @@ TEST(ConstexprTest, MinMaxElementWithPredicate) { ...@@ -1203,8 +1204,216 @@ TEST(ConstexprTest, MinMaxElementWithPredicate) {
static_assert(*kMinMaxPair.first == 3); static_assert(*kMinMaxPair.first == 3);
static_assert(*kMinMaxPair.second == 1); static_assert(*kMinMaxPair.second == 1);
} }
#endif // defined(ABSL_INTERNAL_CPLUSPLUS_LANG) && #endif // defined(ABSL_INTERNAL_CPLUSPLUS_LANG) &&
// ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L // ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L
#if defined(ABSL_INTERNAL_CPLUSPLUS_LANG) && \
ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L
TEST(ConstexprTest, LinearSearch) {
static constexpr std::array<int, 3> kArray = {1, 2, 3};
static_assert(absl::c_linear_search(kArray, 3));
static_assert(!absl::c_linear_search(kArray, 4));
}
TEST(ConstexprTest, AllOf) {
static constexpr std::array<int, 3> kArray = {1, 2, 3};
static_assert(!absl::c_all_of(kArray, [](int x) { return x > 1; }));
static_assert(absl::c_all_of(kArray, [](int x) { return x > 0; }));
}
TEST(ConstexprTest, AnyOf) {
static constexpr std::array<int, 3> kArray = {1, 2, 3};
static_assert(absl::c_any_of(kArray, [](int x) { return x > 2; }));
static_assert(!absl::c_any_of(kArray, [](int x) { return x > 5; }));
}
TEST(ConstexprTest, NoneOf) {
static constexpr std::array<int, 3> kArray = {1, 2, 3};
static_assert(!absl::c_none_of(kArray, [](int x) { return x > 2; }));
static_assert(absl::c_none_of(kArray, [](int x) { return x > 5; }));
}
TEST(ConstexprTest, ForEach) {
static constexpr std::array<int, 3> kArray = [] {
std::array<int, 3> array = {1, 2, 3};
absl::c_for_each(array, [](int& x) { x += 1; });
return array;
}();
static_assert(kArray == std::array{2, 3, 4});
}
TEST(ConstexprTest, Find) {
static constexpr std::array<int, 3> kArray = {1, 2, 3};
static_assert(absl::c_find(kArray, 1) == kArray.begin());
static_assert(absl::c_find(kArray, 4) == kArray.end());
}
TEST(ConstexprTest, Contains) {
static constexpr std::array<int, 3> kArray = {1, 2, 3};
static_assert(absl::c_contains(kArray, 1));
static_assert(!absl::c_contains(kArray, 4));
}
TEST(ConstexprTest, FindIf) {
static constexpr std::array<int, 3> kArray = {1, 2, 3};
static_assert(absl::c_find_if(kArray, [](int x) { return x > 2; }) ==
kArray.begin() + 2);
static_assert(absl::c_find_if(kArray, [](int x) { return x > 5; }) ==
kArray.end());
}
TEST(ConstexprTest, FindIfNot) {
static constexpr std::array<int, 3> kArray = {1, 2, 3};
static_assert(absl::c_find_if_not(kArray, [](int x) { return x > 1; }) ==
kArray.begin());
static_assert(absl::c_find_if_not(kArray, [](int x) { return x > 0; }) ==
kArray.end());
}
TEST(ConstexprTest, FindEnd) {
static constexpr std::array<int, 5> kHaystack = {1, 2, 3, 2, 3};
static constexpr std::array<int, 2> kNeedle = {2, 3};
static_assert(absl::c_find_end(kHaystack, kNeedle) == kHaystack.begin() + 3);
}
TEST(ConstexprTest, FindFirstOf) {
static constexpr std::array<int, 3> kArray = {1, 2, 3};
static_assert(absl::c_find_first_of(kArray, kArray) == kArray.begin());
}
TEST(ConstexprTest, AdjacentFind) {
static constexpr std::array<int, 4> kArray = {1, 2, 2, 3};
static_assert(absl::c_adjacent_find(kArray) == kArray.begin() + 1);
}
TEST(ConstexprTest, AdjacentFindWithPredicate) {
static constexpr std::array<int, 3> kArray = {1, 2, 3};
static_assert(absl::c_adjacent_find(kArray, std::less<int>()) ==
kArray.begin());
}
TEST(ConstexprTest, Count) {
static constexpr std::array<int, 3> kArray = {1, 2, 3};
static_assert(absl::c_count(kArray, 1) == 1);
static_assert(absl::c_count(kArray, 2) == 1);
static_assert(absl::c_count(kArray, 3) == 1);
static_assert(absl::c_count(kArray, 4) == 0);
}
TEST(ConstexprTest, CountIf) {
static constexpr std::array<int, 3> kArray = {1, 2, 3};
static_assert(absl::c_count_if(kArray, [](int x) { return x > 0; }) == 3);
static_assert(absl::c_count_if(kArray, [](int x) { return x > 1; }) == 2);
}
TEST(ConstexprTest, Mismatch) {
static constexpr std::array<int, 3> kArray1 = {1, 2, 3};
static constexpr std::array<int, 3> kArray2 = {1, 2, 3};
static constexpr std::array<int, 3> kArray3 = {2, 3, 4};
static_assert(absl::c_mismatch(kArray1, kArray2) ==
std::pair{kArray1.end(), kArray2.end()});
static_assert(absl::c_mismatch(kArray1, kArray3) ==
std::pair{kArray1.begin(), kArray3.begin()});
}
TEST(ConstexprTest, MismatchWithPredicate) {
static constexpr std::array<int, 3> kArray1 = {1, 2, 3};
static constexpr std::array<int, 3> kArray2 = {1, 2, 3};
static constexpr std::array<int, 3> kArray3 = {2, 3, 4};
static_assert(absl::c_mismatch(kArray1, kArray2, std::not_equal_to<int>()) ==
std::pair{kArray1.begin(), kArray2.begin()});
static_assert(absl::c_mismatch(kArray1, kArray3, std::not_equal_to<int>()) ==
std::pair{kArray1.end(), kArray3.end()});
}
TEST(ConstexprTest, Equal) {
static constexpr std::array<int, 3> kArray1 = {1, 2, 3};
static constexpr std::array<int, 3> kArray2 = {1, 2, 3};
static constexpr std::array<int, 3> kArray3 = {2, 3, 4};
static_assert(absl::c_equal(kArray1, kArray2));
static_assert(!absl::c_equal(kArray1, kArray3));
}
TEST(ConstexprTest, EqualWithPredicate) {
static constexpr std::array<int, 3> kArray1 = {1, 2, 3};
static constexpr std::array<int, 3> kArray2 = {1, 2, 3};
static constexpr std::array<int, 3> kArray3 = {2, 3, 4};
static_assert(!absl::c_equal(kArray1, kArray2, std::not_equal_to<int>()));
static_assert(absl::c_equal(kArray1, kArray3, std::not_equal_to<int>()));
}
TEST(ConstexprTest, IsPermutation) {
static constexpr std::array<int, 3> kArray1 = {1, 2, 3};
static constexpr std::array<int, 3> kArray2 = {3, 2, 1};
static constexpr std::array<int, 3> kArray3 = {2, 3, 4};
static_assert(absl::c_is_permutation(kArray1, kArray2));
static_assert(!absl::c_is_permutation(kArray1, kArray3));
}
TEST(ConstexprTest, IsPermutationWithPredicate) {
static constexpr std::array<int, 3> kArray1 = {1, 2, 3};
static constexpr std::array<int, 3> kArray2 = {3, 2, 1};
static constexpr std::array<int, 3> kArray3 = {2, 3, 4};
static_assert(absl::c_is_permutation(kArray1, kArray2, std::equal_to<int>()));
static_assert(
!absl::c_is_permutation(kArray1, kArray3, std::equal_to<int>()));
}
TEST(ConstexprTest, Search) {
static constexpr std::array<int, 3> kArray1 = {1, 2, 3};
static constexpr std::array<int, 3> kArray2 = {1, 2, 3};
static constexpr std::array<int, 3> kArray3 = {2, 3, 4};
static_assert(absl::c_search(kArray1, kArray2) == kArray1.begin());
static_assert(absl::c_search(kArray1, kArray3) == kArray1.end());
}
TEST(ConstexprTest, SearchWithPredicate) {
static constexpr std::array<int, 3> kArray1 = {1, 2, 3};
static constexpr std::array<int, 3> kArray2 = {1, 2, 3};
static constexpr std::array<int, 3> kArray3 = {2, 3, 4};
static_assert(absl::c_search(kArray1, kArray2, std::not_equal_to<int>()) ==
kArray1.end());
static_assert(absl::c_search(kArray1, kArray3, std::not_equal_to<int>()) ==
kArray1.begin());
}
TEST(ConstexprTest, ContainsSubrange) {
static constexpr std::array<int, 3> kArray1 = {1, 2, 3};
static constexpr std::array<int, 3> kArray2 = {1, 2, 3};
static constexpr std::array<int, 3> kArray3 = {2, 3, 4};
static_assert(absl::c_contains_subrange(kArray1, kArray2));
static_assert(!absl::c_contains_subrange(kArray1, kArray3));
}
TEST(ConstexprTest, ContainsSubrangeWithPredicate) {
static constexpr std::array<int, 3> kArray1 = {1, 2, 3};
static constexpr std::array<int, 3> kArray2 = {1, 2, 3};
static constexpr std::array<int, 3> kArray3 = {2, 3, 4};
static_assert(
!absl::c_contains_subrange(kArray1, kArray2, std::not_equal_to<>()));
static_assert(
absl::c_contains_subrange(kArray1, kArray3, std::not_equal_to<>()));
}
TEST(ConstexprTest, SearchN) {
static constexpr std::array<int, 4> kArray = {1, 2, 2, 3};
static_assert(absl::c_search_n(kArray, 1, 1) == kArray.begin());
static_assert(absl::c_search_n(kArray, 2, 2) == kArray.begin() + 1);
static_assert(absl::c_search_n(kArray, 1, 4) == kArray.end());
}
TEST(ConstexprTest, SearchNWithPredicate) {
static constexpr std::array<int, 4> kArray = {1, 2, 2, 3};
static_assert(absl::c_search_n(kArray, 1, 1, std::not_equal_to<int>()) ==
kArray.begin() + 1);
static_assert(absl::c_search_n(kArray, 2, 2, std::not_equal_to<int>()) ==
kArray.end());
static_assert(absl::c_search_n(kArray, 1, 4, std::not_equal_to<int>()) ==
kArray.begin());
}
#endif // defined(ABSL_INTERNAL_CPLUSPLUS_LANG) &&
// ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L
} // namespace } // namespace
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment