Skip to content

Commit

Permalink
Make Span's relational operators constexpr since C++20.
Browse files Browse the repository at this point in the history
_The implementation has not changed, only constexpr markers have been added._

PiperOrigin-RevId: 695435063
Change-Id: I66cd03195e429534c0e58c330f1019c89025abed
  • Loading branch information
Abseil Team authored and copybara-github committed Nov 11, 2024
1 parent feb6aab commit 8d272b2
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 35 deletions.
5 changes: 3 additions & 2 deletions absl/types/internal/span.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <type_traits>

#include "absl/algorithm/algorithm.h"
#include "absl/base/config.h"
#include "absl/base/internal/throw_delegate.h"
#include "absl/meta/type_traits.h"

Expand Down Expand Up @@ -86,13 +87,13 @@ using EnableIfMutable =
typename std::enable_if<!std::is_const<T>::value, int>::type;

template <template <typename> class SpanT, typename T>
bool EqualImpl(SpanT<T> a, SpanT<T> b) {
ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool EqualImpl(SpanT<T> a, SpanT<T> b) {
static_assert(std::is_const<T>::value, "");
return std::equal(a.begin(), a.end(), b.begin(), b.end());
}

template <template <typename> class SpanT, typename T>
bool LessThanImpl(SpanT<T> a, SpanT<T> b) {
ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool LessThanImpl(SpanT<T> a, SpanT<T> b) {
// We can't use value_type since that is remove_cv_t<T>, so we go the long way
// around.
static_assert(std::is_const<T>::value, "");
Expand Down
68 changes: 38 additions & 30 deletions absl/types/span.h
Original file line number Diff line number Diff line change
Expand Up @@ -522,157 +522,165 @@ const typename Span<T>::size_type Span<T>::npos;

// operator==
template <typename T>
bool operator==(Span<T> a, Span<T> b) {
ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator==(Span<T> a, Span<T> b) {
return span_internal::EqualImpl<Span, const T>(a, b);
}
template <typename T>
bool operator==(Span<const T> a, Span<T> b) {
ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator==(Span<const T> a,
Span<T> b) {
return span_internal::EqualImpl<Span, const T>(a, b);
}
template <typename T>
bool operator==(Span<T> a, Span<const T> b) {
ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator==(Span<T> a,
Span<const T> b) {
return span_internal::EqualImpl<Span, const T>(a, b);
}
template <
typename T, typename U,
typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>>
bool operator==(const U& a, Span<T> b) {
ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator==(const U& a, Span<T> b) {
return span_internal::EqualImpl<Span, const T>(a, b);
}
template <
typename T, typename U,
typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>>
bool operator==(Span<T> a, const U& b) {
ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator==(Span<T> a, const U& b) {
return span_internal::EqualImpl<Span, const T>(a, b);
}

// operator!=
template <typename T>
bool operator!=(Span<T> a, Span<T> b) {
ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator!=(Span<T> a, Span<T> b) {
return !(a == b);
}
template <typename T>
bool operator!=(Span<const T> a, Span<T> b) {
ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator!=(Span<const T> a,
Span<T> b) {
return !(a == b);
}
template <typename T>
bool operator!=(Span<T> a, Span<const T> b) {
ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator!=(Span<T> a,
Span<const T> b) {
return !(a == b);
}
template <
typename T, typename U,
typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>>
bool operator!=(const U& a, Span<T> b) {
ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator!=(const U& a, Span<T> b) {
return !(a == b);
}
template <
typename T, typename U,
typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>>
bool operator!=(Span<T> a, const U& b) {
ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator!=(Span<T> a, const U& b) {
return !(a == b);
}

// operator<
template <typename T>
bool operator<(Span<T> a, Span<T> b) {
ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator<(Span<T> a, Span<T> b) {
return span_internal::LessThanImpl<Span, const T>(a, b);
}
template <typename T>
bool operator<(Span<const T> a, Span<T> b) {
ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator<(Span<const T> a, Span<T> b) {
return span_internal::LessThanImpl<Span, const T>(a, b);
}
template <typename T>
bool operator<(Span<T> a, Span<const T> b) {
ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator<(Span<T> a, Span<const T> b) {
return span_internal::LessThanImpl<Span, const T>(a, b);
}
template <
typename T, typename U,
typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>>
bool operator<(const U& a, Span<T> b) {
ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator<(const U& a, Span<T> b) {
return span_internal::LessThanImpl<Span, const T>(a, b);
}
template <
typename T, typename U,
typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>>
bool operator<(Span<T> a, const U& b) {
ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator<(Span<T> a, const U& b) {
return span_internal::LessThanImpl<Span, const T>(a, b);
}

// operator>
template <typename T>
bool operator>(Span<T> a, Span<T> b) {
ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator>(Span<T> a, Span<T> b) {
return b < a;
}
template <typename T>
bool operator>(Span<const T> a, Span<T> b) {
ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator>(Span<const T> a, Span<T> b) {
return b < a;
}
template <typename T>
bool operator>(Span<T> a, Span<const T> b) {
ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator>(Span<T> a, Span<const T> b) {
return b < a;
}
template <
typename T, typename U,
typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>>
bool operator>(const U& a, Span<T> b) {
ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator>(const U& a, Span<T> b) {
return b < a;
}
template <
typename T, typename U,
typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>>
bool operator>(Span<T> a, const U& b) {
ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator>(Span<T> a, const U& b) {
return b < a;
}

// operator<=
template <typename T>
bool operator<=(Span<T> a, Span<T> b) {
ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator<=(Span<T> a, Span<T> b) {
return !(b < a);
}
template <typename T>
bool operator<=(Span<const T> a, Span<T> b) {
ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator<=(Span<const T> a,
Span<T> b) {
return !(b < a);
}
template <typename T>
bool operator<=(Span<T> a, Span<const T> b) {
ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator<=(Span<T> a,
Span<const T> b) {
return !(b < a);
}
template <
typename T, typename U,
typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>>
bool operator<=(const U& a, Span<T> b) {
ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator<=(const U& a, Span<T> b) {
return !(b < a);
}
template <
typename T, typename U,
typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>>
bool operator<=(Span<T> a, const U& b) {
ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator<=(Span<T> a, const U& b) {
return !(b < a);
}

// operator>=
template <typename T>
bool operator>=(Span<T> a, Span<T> b) {
ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator>=(Span<T> a, Span<T> b) {
return !(a < b);
}
template <typename T>
bool operator>=(Span<const T> a, Span<T> b) {
ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator>=(Span<const T> a,
Span<T> b) {
return !(a < b);
}
template <typename T>
bool operator>=(Span<T> a, Span<const T> b) {
ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator>=(Span<T> a,
Span<const T> b) {
return !(a < b);
}
template <
typename T, typename U,
typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>>
bool operator>=(const U& a, Span<T> b) {
ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator>=(const U& a, Span<T> b) {
return !(a < b);
}
template <
typename T, typename U,
typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>>
bool operator>=(Span<T> a, const U& b) {
ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator>=(Span<T> a, const U& b) {
return !(a < b);
}

Expand Down
41 changes: 38 additions & 3 deletions absl/types/span_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -787,9 +787,9 @@ TEST(IntSpan, NoexceptTest) {
template <int i>
struct ConstexprTester {};

#define ABSL_TEST_CONSTEXPR(expr) \
do { \
ABSL_ATTRIBUTE_UNUSED ConstexprTester<(expr, 1)> t; \
#define ABSL_TEST_CONSTEXPR(expr) \
do { \
ABSL_ATTRIBUTE_UNUSED ConstexprTester<(static_cast<void>(expr), 1)> t; \
} while (0)

struct ContainerWithConstexprMethods {
Expand Down Expand Up @@ -826,6 +826,41 @@ TEST(ConstIntSpan, ConstexprTest) {
ABSL_TEST_CONSTEXPR(span[0]);
}

#if defined(ABSL_INTERNAL_CPLUSPLUS_LANG) && \
ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L

TEST(ConstIntSpan, ConstexprRelOpsTest) {
static constexpr int lhs_data[] = {1, 2, 3};
static constexpr int rhs_data[] = {1, 2, 3};

constexpr absl::Span<const int> lhs = absl::MakeConstSpan(lhs_data, 3);
constexpr absl::Span<const int> rhs = absl::MakeConstSpan(rhs_data, 3);

ABSL_TEST_CONSTEXPR(lhs_data == rhs);
ABSL_TEST_CONSTEXPR(lhs_data != rhs);
ABSL_TEST_CONSTEXPR(lhs_data < rhs);
ABSL_TEST_CONSTEXPR(lhs_data <= rhs);
ABSL_TEST_CONSTEXPR(lhs_data > rhs);
ABSL_TEST_CONSTEXPR(lhs_data >= rhs);

ABSL_TEST_CONSTEXPR(lhs == rhs);
ABSL_TEST_CONSTEXPR(lhs != rhs);
ABSL_TEST_CONSTEXPR(lhs < rhs);
ABSL_TEST_CONSTEXPR(lhs <= rhs);
ABSL_TEST_CONSTEXPR(lhs > rhs);
ABSL_TEST_CONSTEXPR(lhs >= rhs);

ABSL_TEST_CONSTEXPR(lhs == rhs_data);
ABSL_TEST_CONSTEXPR(lhs != rhs_data);
ABSL_TEST_CONSTEXPR(lhs < rhs_data);
ABSL_TEST_CONSTEXPR(lhs <= rhs_data);
ABSL_TEST_CONSTEXPR(lhs > rhs_data);
ABSL_TEST_CONSTEXPR(lhs >= rhs_data);
}

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

struct BigStruct {
char bytes[10000];
};
Expand Down

0 comments on commit 8d272b2

Please sign in to comment.