Skip to content

Commit

Permalink
Mark c_min_element, c_max_element, and c_minmax_element as constexpr …
Browse files Browse the repository at this point in the history
…in C++17.

This allows them to be used in constant expressions, such as static_asserts.

PiperOrigin-RevId: 649292841
Change-Id: I76e31a94b933fa357276fee534b81c00c28c8b23
  • Loading branch information
Abseil Team authored and copybara-github committed Jul 4, 2024
1 parent eb46a63 commit 074a32a
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 27 deletions.
36 changes: 21 additions & 15 deletions absl/algorithm/container.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,12 +99,12 @@ using ContainerPointerType =
// These are meant for internal use only.

template <typename C>
ABSL_CONSTEXPR_SINCE_CXX17 ContainerIter<C> c_begin(C& c) {
ABSL_INTERNAL_CONSTEXPR_SINCE_CXX17 ContainerIter<C> c_begin(C& c) {
return begin(c);
}

template <typename C>
ABSL_CONSTEXPR_SINCE_CXX17 ContainerIter<C> c_end(C& c) {
ABSL_INTERNAL_CONSTEXPR_SINCE_CXX17 ContainerIter<C> c_end(C& c) {
return end(c);
}

Expand Down Expand Up @@ -147,7 +147,7 @@ bool c_linear_search(const C& c, EqualityComparable&& value) {
// Container-based version of the <iterator> `std::distance()` function to
// return the number of elements within a container.
template <typename C>
ABSL_CONSTEXPR_SINCE_CXX17
ABSL_INTERNAL_CONSTEXPR_SINCE_CXX17
container_algorithm_internal::ContainerDifferenceType<const C>
c_distance(const C& c) {
return std::distance(container_algorithm_internal::c_begin(c),
Expand Down Expand Up @@ -1533,17 +1533,19 @@ c_is_heap_until(RandomAccessContainer& sequence, LessThan&& comp) {
// to return an iterator pointing to the element with the smallest value, using
// `operator<` to make the comparisons.
template <typename Sequence>
container_algorithm_internal::ContainerIter<Sequence> c_min_element(
Sequence& sequence) {
ABSL_INTERNAL_CONSTEXPR_SINCE_CXX17
container_algorithm_internal::ContainerIter<Sequence>
c_min_element(Sequence& sequence) {
return std::min_element(container_algorithm_internal::c_begin(sequence),
container_algorithm_internal::c_end(sequence));
}

// Overload of c_min_element() for performing a `comp` comparison other than
// `operator<`.
template <typename Sequence, typename LessThan>
container_algorithm_internal::ContainerIter<Sequence> c_min_element(
Sequence& sequence, LessThan&& comp) {
ABSL_INTERNAL_CONSTEXPR_SINCE_CXX17
container_algorithm_internal::ContainerIter<Sequence>
c_min_element(Sequence& sequence, LessThan&& comp) {
return std::min_element(container_algorithm_internal::c_begin(sequence),
container_algorithm_internal::c_end(sequence),
std::forward<LessThan>(comp));
Expand All @@ -1555,17 +1557,19 @@ container_algorithm_internal::ContainerIter<Sequence> c_min_element(
// to return an iterator pointing to the element with the largest value, using
// `operator<` to make the comparisons.
template <typename Sequence>
container_algorithm_internal::ContainerIter<Sequence> c_max_element(
Sequence& sequence) {
ABSL_INTERNAL_CONSTEXPR_SINCE_CXX17
container_algorithm_internal::ContainerIter<Sequence>
c_max_element(Sequence& sequence) {
return std::max_element(container_algorithm_internal::c_begin(sequence),
container_algorithm_internal::c_end(sequence));
}

// Overload of c_max_element() for performing a `comp` comparison other than
// `operator<`.
template <typename Sequence, typename LessThan>
container_algorithm_internal::ContainerIter<Sequence> c_max_element(
Sequence& sequence, LessThan&& comp) {
ABSL_INTERNAL_CONSTEXPR_SINCE_CXX17
container_algorithm_internal::ContainerIter<Sequence>
c_max_element(Sequence& sequence, LessThan&& comp) {
return std::max_element(container_algorithm_internal::c_begin(sequence),
container_algorithm_internal::c_end(sequence),
std::forward<LessThan>(comp));
Expand All @@ -1578,17 +1582,19 @@ container_algorithm_internal::ContainerIter<Sequence> c_max_element(
// smallest and largest values, respectively, using `operator<` to make the
// comparisons.
template <typename C>
container_algorithm_internal::ContainerIterPairType<C, C> c_minmax_element(
C& c) {
ABSL_INTERNAL_CONSTEXPR_SINCE_CXX17
container_algorithm_internal::ContainerIterPairType<C, C>
c_minmax_element(C& c) {
return std::minmax_element(container_algorithm_internal::c_begin(c),
container_algorithm_internal::c_end(c));
}

// Overload of c_minmax_element() for performing `comp` comparisons other than
// `operator<`.
template <typename C, typename LessThan>
container_algorithm_internal::ContainerIterPairType<C, C> c_minmax_element(
C& c, LessThan&& comp) {
ABSL_INTERNAL_CONSTEXPR_SINCE_CXX17
container_algorithm_internal::ContainerIterPairType<C, C>
c_minmax_element(C& c, LessThan&& comp) {
return std::minmax_element(container_algorithm_internal::c_begin(c),
container_algorithm_internal::c_end(c),
std::forward<LessThan>(comp));
Expand Down
36 changes: 36 additions & 0 deletions absl/algorithm/container_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1168,6 +1168,42 @@ TEST(ConstexprTest, Distance) {
// Works at compile time with constexpr containers.
static_assert(absl::c_distance(std::array<int, 3>()) == 3);
}

TEST(ConstexprTest, MinElement) {
constexpr std::array<int, 3> kArray = {1, 2, 3};
static_assert(*absl::c_min_element(kArray) == 1);
}

TEST(ConstexprTest, MinElementWithPredicate) {
constexpr std::array<int, 3> kArray = {1, 2, 3};
static_assert(*absl::c_min_element(kArray, std::greater<int>()) == 3);
}

TEST(ConstexprTest, MaxElement) {
constexpr std::array<int, 3> kArray = {1, 2, 3};
static_assert(*absl::c_max_element(kArray) == 3);
}

TEST(ConstexprTest, MaxElementWithPredicate) {
constexpr std::array<int, 3> kArray = {1, 2, 3};
static_assert(*absl::c_max_element(kArray, std::greater<int>()) == 1);
}

TEST(ConstexprTest, MinMaxElement) {
static constexpr std::array<int, 3> kArray = {1, 2, 3};
constexpr auto kMinMaxPair = absl::c_minmax_element(kArray);
static_assert(*kMinMaxPair.first == 1);
static_assert(*kMinMaxPair.second == 3);
}

TEST(ConstexprTest, MinMaxElementWithPredicate) {
static constexpr std::array<int, 3> kArray = {1, 2, 3};
constexpr auto kMinMaxPair =
absl::c_minmax_element(kArray, std::greater<int>());
static_assert(*kMinMaxPair.first == 3);
static_assert(*kMinMaxPair.second == 1);
}

#endif // defined(ABSL_INTERNAL_CPLUSPLUS_LANG) &&
// ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L

Expand Down
24 changes: 12 additions & 12 deletions absl/base/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -941,25 +941,25 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' ||
#define ABSL_HAVE_CONSTANT_EVALUATED 1
#endif

// ABSL_CONSTEXPR_SINCE_CXXYY is used to conditionally define constexpr for
// different C++ versions.
#if defined(ABSL_INTERNAL_CPLUSPLUS_LANG) && \
ABSL_INTERNAL_CPLUSPLUS_LANG >= 201402L
#define ABSL_CONSTEXPR_SINCE_CXX14 constexpr
#else
#define ABSL_CONSTEXPR_SINCE_CXX14
#endif
// ABSL_INTERNAL_CONSTEXPR_SINCE_CXXYY is used to conditionally define constexpr
// for different C++ versions.
//
// These macros are an implementation detail and will be unconditionally removed
// once the minimum supported C++ version catches up to a given version.
//
// For this reason, this symbol is considered INTERNAL and code outside of
// Abseil must not use it.
#if defined(ABSL_INTERNAL_CPLUSPLUS_LANG) && \
ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L
#define ABSL_CONSTEXPR_SINCE_CXX17 constexpr
#define ABSL_INTERNAL_CONSTEXPR_SINCE_CXX17 constexpr
#else
#define ABSL_CONSTEXPR_SINCE_CXX17
#define ABSL_INTERNAL_CONSTEXPR_SINCE_CXX17
#endif
#if defined(ABSL_INTERNAL_CPLUSPLUS_LANG) && \
ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L
#define ABSL_CONSTEXPR_SINCE_CXX20 constexpr
#define ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 constexpr
#else
#define ABSL_CONSTEXPR_SINCE_CXX20
#define ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20
#endif

// ABSL_INTERNAL_EMSCRIPTEN_VERSION combines Emscripten's three version macros
Expand Down

0 comments on commit 074a32a

Please sign in to comment.