diff options
Diffstat (limited to 'absl/types')
-rw-r--r-- | absl/types/BUILD.bazel | 24 | ||||
-rw-r--r-- | absl/types/CMakeLists.txt | 26 | ||||
-rw-r--r-- | absl/types/compare.h | 506 | ||||
-rw-r--r-- | absl/types/compare_test.cc | 315 |
4 files changed, 871 insertions, 0 deletions
diff --git a/absl/types/BUILD.bazel b/absl/types/BUILD.bazel index a25487184bc1..134f9f227e33 100644 --- a/absl/types/BUILD.bazel +++ b/absl/types/BUILD.bazel @@ -308,3 +308,27 @@ cc_test( "@com_google_googletest//:gtest_main", ], ) + +cc_library( + name = "compare", + hdrs = ["compare.h"], + copts = ABSL_DEFAULT_COPTS, + deps = [ + "//absl/base:core_headers", + "//absl/meta:type_traits", + ], +) + +cc_test( + name = "compare_test", + size = "small", + srcs = [ + "compare_test.cc", + ], + copts = ABSL_TEST_COPTS, + deps = [ + ":compare", + "//absl/base", + "@com_google_googletest//:gtest_main", + ], +) diff --git a/absl/types/CMakeLists.txt b/absl/types/CMakeLists.txt index 9da94eb56120..4ce685da4e6c 100644 --- a/absl/types/CMakeLists.txt +++ b/absl/types/CMakeLists.txt @@ -299,6 +299,32 @@ absl_cc_test( gmock_main ) +absl_cc_library( + NAME + compare + HDRS + "compare.h" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::core_headers + absl::type_traits + PUBLIC +) + +absl_cc_test( + NAME + compare_test + SRCS + "compare_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::base + absl::compare + gmock_main +) + # TODO(cohenjon,zhangxy) Figure out why this test is failing on gcc 4.8 if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9) else() diff --git a/absl/types/compare.h b/absl/types/compare.h new file mode 100644 index 000000000000..7fed30814050 --- /dev/null +++ b/absl/types/compare.h @@ -0,0 +1,506 @@ +// Copyright 2018 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// ----------------------------------------------------------------------------- +// compare.h +// ----------------------------------------------------------------------------- +// +// This header file defines the `absl::weak_equality`, `absl::strong_equality`, +// `absl::partial_ordering`, `absl::weak_ordering`, and `absl::strong_ordering` +// types for storing the results of three way comparisons. +// +// Example: +// absl::weak_ordering compare(const std::string& a, const std::string& b); +// +// These are C++11 compatible versions of the C++20 corresponding types +// (`std::weak_equality`, etc.) and are designed to be drop-in replacements +// for code compliant with C++20. + +#ifndef ABSL_TYPES_COMPARE_H_ +#define ABSL_TYPES_COMPARE_H_ + +#include <cstddef> +#include <cstdint> +#include <cstdlib> +#include <type_traits> + +#include "absl/base/attributes.h" +#include "absl/meta/type_traits.h" + +namespace absl { +namespace compare_internal { + +using value_type = int8_t; + +template <typename T> +struct Fail { + static_assert(sizeof(T) < 0, "Only literal `0` is allowed."); +}; + +// We need the NullPtrT template to avoid triggering the modernize-use-nullptr +// ClangTidy warning in user code. +template <typename NullPtrT = std::nullptr_t> +struct OnlyLiteralZero { + constexpr OnlyLiteralZero(NullPtrT) noexcept {} // NOLINT + + // Fails compilation when `nullptr` or integral type arguments other than + // `int` are passed. This constructor doesn't accept `int` because literal `0` + // has type `int`. Literal `0` arguments will be implicitly converted to + // `std::nullptr_t` and accepted by the above constructor, while other `int` + // arguments will fail to be converted and cause compilation failure. + template < + typename T, + typename = typename std::enable_if< + std::is_same<T, std::nullptr_t>::value || + (std::is_integral<T>::value && !std::is_same<T, int>::value)>::type, + typename = typename Fail<T>::type> + OnlyLiteralZero(T); // NOLINT +}; + +enum class eq : value_type { + equal = 0, + equivalent = equal, + nonequal = 1, + nonequivalent = nonequal, +}; + +enum class ord : value_type { less = -1, greater = 1 }; + +enum class ncmp : value_type { unordered = -127 }; + +// These template base classes allow for defining the values of the constants +// in the header file (for performance) without using inline variables (which +// aren't available in C++11). +template <typename T> +struct weak_equality_base { + ABSL_CONST_INIT static const T equivalent; + ABSL_CONST_INIT static const T nonequivalent; +}; +template <typename T> +const T weak_equality_base<T>::equivalent(eq::equivalent); +template <typename T> +const T weak_equality_base<T>::nonequivalent(eq::nonequivalent); + +template <typename T> +struct strong_equality_base { + ABSL_CONST_INIT static const T equal; + ABSL_CONST_INIT static const T nonequal; + ABSL_CONST_INIT static const T equivalent; + ABSL_CONST_INIT static const T nonequivalent; +}; +template <typename T> +const T strong_equality_base<T>::equal(eq::equal); +template <typename T> +const T strong_equality_base<T>::nonequal(eq::nonequal); +template <typename T> +const T strong_equality_base<T>::equivalent(eq::equivalent); +template <typename T> +const T strong_equality_base<T>::nonequivalent(eq::nonequivalent); + +template <typename T> +struct partial_ordering_base { + ABSL_CONST_INIT static const T less; + ABSL_CONST_INIT static const T equivalent; + ABSL_CONST_INIT static const T greater; + ABSL_CONST_INIT static const T unordered; +}; +template <typename T> +const T partial_ordering_base<T>::less(ord::less); +template <typename T> +const T partial_ordering_base<T>::equivalent(eq::equivalent); +template <typename T> +const T partial_ordering_base<T>::greater(ord::greater); +template <typename T> +const T partial_ordering_base<T>::unordered(ncmp::unordered); + +template <typename T> +struct weak_ordering_base { + ABSL_CONST_INIT static const T less; + ABSL_CONST_INIT static const T equivalent; + ABSL_CONST_INIT static const T greater; +}; +template <typename T> +const T weak_ordering_base<T>::less(ord::less); +template <typename T> +const T weak_ordering_base<T>::equivalent(eq::equivalent); +template <typename T> +const T weak_ordering_base<T>::greater(ord::greater); + +template <typename T> +struct strong_ordering_base { + ABSL_CONST_INIT static const T less; + ABSL_CONST_INIT static const T equal; + ABSL_CONST_INIT static const T equivalent; + ABSL_CONST_INIT static const T greater; +}; +template <typename T> +const T strong_ordering_base<T>::less(ord::less); +template <typename T> +const T strong_ordering_base<T>::equal(eq::equal); +template <typename T> +const T strong_ordering_base<T>::equivalent(eq::equivalent); +template <typename T> +const T strong_ordering_base<T>::greater(ord::greater); + +} // namespace compare_internal + +class weak_equality + : public compare_internal::weak_equality_base<weak_equality> { + explicit constexpr weak_equality(compare_internal::eq v) noexcept + : value_(static_cast<compare_internal::value_type>(v)) {} + friend struct compare_internal::weak_equality_base<weak_equality>; + + public: + // Comparisons + friend constexpr bool operator==( + weak_equality v, compare_internal::OnlyLiteralZero<>) noexcept { + return v.value_ == 0; + } + friend constexpr bool operator!=( + weak_equality v, compare_internal::OnlyLiteralZero<>) noexcept { + return v.value_ != 0; + } + friend constexpr bool operator==(compare_internal::OnlyLiteralZero<>, + weak_equality v) noexcept { + return 0 == v.value_; + } + friend constexpr bool operator!=(compare_internal::OnlyLiteralZero<>, + weak_equality v) noexcept { + return 0 != v.value_; + } + + private: + compare_internal::value_type value_; +}; + +class strong_equality + : public compare_internal::strong_equality_base<strong_equality> { + explicit constexpr strong_equality(compare_internal::eq v) noexcept + : value_(static_cast<compare_internal::value_type>(v)) {} + friend struct compare_internal::strong_equality_base<strong_equality>; + + public: + // Conversion + constexpr operator weak_equality() const noexcept { // NOLINT + return value_ == 0 ? weak_equality::equivalent + : weak_equality::nonequivalent; + } + // Comparisons + friend constexpr bool operator==( + strong_equality v, compare_internal::OnlyLiteralZero<>) noexcept { + return v.value_ == 0; + } + friend constexpr bool operator!=( + strong_equality v, compare_internal::OnlyLiteralZero<>) noexcept { + return v.value_ != 0; + } + friend constexpr bool operator==(compare_internal::OnlyLiteralZero<>, + strong_equality v) noexcept { + return 0 == v.value_; + } + friend constexpr bool operator!=(compare_internal::OnlyLiteralZero<>, + strong_equality v) noexcept { + return 0 != v.value_; + } + + private: + compare_internal::value_type value_; +}; + +class partial_ordering + : public compare_internal::partial_ordering_base<partial_ordering> { + explicit constexpr partial_ordering(compare_internal::eq v) noexcept + : value_(static_cast<compare_internal::value_type>(v)) {} + explicit constexpr partial_ordering(compare_internal::ord v) noexcept + : value_(static_cast<compare_internal::value_type>(v)) {} + explicit constexpr partial_ordering(compare_internal::ncmp v) noexcept + : value_(static_cast<compare_internal::value_type>(v)) {} + friend struct compare_internal::partial_ordering_base<partial_ordering>; + + constexpr bool is_ordered() const noexcept { + return value_ != + compare_internal::value_type(compare_internal::ncmp::unordered); + } + + public: + // Conversion + constexpr operator weak_equality() const noexcept { // NOLINT + return value_ == 0 ? weak_equality::equivalent + : weak_equality::nonequivalent; + } + // Comparisons + friend constexpr bool operator==( + partial_ordering v, compare_internal::OnlyLiteralZero<>) noexcept { + return v.is_ordered() && v.value_ == 0; + } + friend constexpr bool operator!=( + partial_ordering v, compare_internal::OnlyLiteralZero<>) noexcept { + return !v.is_ordered() || v.value_ != 0; + } + friend constexpr bool operator<( + partial_ordering v, compare_internal::OnlyLiteralZero<>) noexcept { + return v.is_ordered() && v.value_ < 0; + } + friend constexpr bool operator<=( + partial_ordering v, compare_internal::OnlyLiteralZero<>) noexcept { + return v.is_ordered() && v.value_ <= 0; + } + friend constexpr bool operator>( + partial_ordering v, compare_internal::OnlyLiteralZero<>) noexcept { + return v.is_ordered() && v.value_ > 0; + } + friend constexpr bool operator>=( + partial_ordering v, compare_internal::OnlyLiteralZero<>) noexcept { + return v.is_ordered() && v.value_ >= 0; + } + friend constexpr bool operator==(compare_internal::OnlyLiteralZero<>, + partial_ordering v) noexcept { + return v.is_ordered() && 0 == v.value_; + } + friend constexpr bool operator!=(compare_internal::OnlyLiteralZero<>, + partial_ordering v) noexcept { + return !v.is_ordered() || 0 != v.value_; + } + friend constexpr bool operator<(compare_internal::OnlyLiteralZero<>, + partial_ordering v) noexcept { + return v.is_ordered() && 0 < v.value_; + } + friend constexpr bool operator<=(compare_internal::OnlyLiteralZero<>, + partial_ordering v) noexcept { + return v.is_ordered() && 0 <= v.value_; + } + friend constexpr bool operator>(compare_internal::OnlyLiteralZero<>, + partial_ordering v) noexcept { + return v.is_ordered() && 0 > v.value_; + } + friend constexpr bool operator>=(compare_internal::OnlyLiteralZero<>, + partial_ordering v) noexcept { + return v.is_ordered() && 0 >= v.value_; + } + + private: + compare_internal::value_type value_; +}; + +class weak_ordering + : public compare_internal::weak_ordering_base<weak_ordering> { + explicit constexpr weak_ordering(compare_internal::eq v) noexcept + : value_(static_cast<compare_internal::value_type>(v)) {} + explicit constexpr weak_ordering(compare_internal::ord v) noexcept + : value_(static_cast<compare_internal::value_type>(v)) {} + friend struct compare_internal::weak_ordering_base<weak_ordering>; + + public: + // Conversions + constexpr operator weak_equality() const noexcept { // NOLINT + return value_ == 0 ? weak_equality::equivalent + : weak_equality::nonequivalent; + } + constexpr operator partial_ordering() const noexcept { // NOLINT + return value_ == 0 ? partial_ordering::equivalent + : (value_ < 0 ? partial_ordering::less + : partial_ordering::greater); + } + // Comparisons + friend constexpr bool operator==( + weak_ordering v, compare_internal::OnlyLiteralZero<>) noexcept { + return v.value_ == 0; + } + friend constexpr bool operator!=( + weak_ordering v, compare_internal::OnlyLiteralZero<>) noexcept { + return v.value_ != 0; + } + friend constexpr bool operator<( + weak_ordering v, compare_internal::OnlyLiteralZero<>) noexcept { + return v.value_ < 0; + } + friend constexpr bool operator<=( + weak_ordering v, compare_internal::OnlyLiteralZero<>) noexcept { + return v.value_ <= 0; + } + friend constexpr bool operator>( + weak_ordering v, compare_internal::OnlyLiteralZero<>) noexcept { + return v.value_ > 0; + } + friend constexpr bool operator>=( + weak_ordering v, compare_internal::OnlyLiteralZero<>) noexcept { + return v.value_ >= 0; + } + friend constexpr bool operator==(compare_internal::OnlyLiteralZero<>, + weak_ordering v) noexcept { + return 0 == v.value_; + } + friend constexpr bool operator!=(compare_internal::OnlyLiteralZero<>, + weak_ordering v) noexcept { + return 0 != v.value_; + } + friend constexpr bool operator<(compare_internal::OnlyLiteralZero<>, + weak_ordering v) noexcept { + return 0 < v.value_; + } + friend constexpr bool operator<=(compare_internal::OnlyLiteralZero<>, + weak_ordering v) noexcept { + return 0 <= v.value_; + } + friend constexpr bool operator>(compare_internal::OnlyLiteralZero<>, + weak_ordering v) noexcept { + return 0 > v.value_; + } + friend constexpr bool operator>=(compare_internal::OnlyLiteralZero<>, + weak_ordering v) noexcept { + return 0 >= v.value_; + } + + private: + compare_internal::value_type value_; +}; + +class strong_ordering + : public compare_internal::strong_ordering_base<strong_ordering> { + explicit constexpr strong_ordering(compare_internal::eq v) noexcept + : value_(static_cast<compare_internal::value_type>(v)) {} + explicit constexpr strong_ordering(compare_internal::ord v) noexcept + : value_(static_cast<compare_internal::value_type>(v)) {} + friend struct compare_internal::strong_ordering_base<strong_ordering>; + + public: + // Conversions + constexpr operator weak_equality() const noexcept { // NOLINT + return value_ == 0 ? weak_equality::equivalent + : weak_equality::nonequivalent; + } + constexpr operator strong_equality() const noexcept { // NOLINT + return value_ == 0 ? strong_equality::equal : strong_equality::nonequal; + } + constexpr operator partial_ordering() const noexcept { // NOLINT + return value_ == 0 ? partial_ordering::equivalent + : (value_ < 0 ? partial_ordering::less + : partial_ordering::greater); + } + constexpr operator weak_ordering() const noexcept { // NOLINT + return value_ == 0 + ? weak_ordering::equivalent + : (value_ < 0 ? weak_ordering::less : weak_ordering::greater); + } + // Comparisons + friend constexpr bool operator==( + strong_ordering v, compare_internal::OnlyLiteralZero<>) noexcept { + return v.value_ == 0; + } + friend constexpr bool operator!=( + strong_ordering v, compare_internal::OnlyLiteralZero<>) noexcept { + return v.value_ != 0; + } + friend constexpr bool operator<( + strong_ordering v, compare_internal::OnlyLiteralZero<>) noexcept { + return v.value_ < 0; + } + friend constexpr bool operator<=( + strong_ordering v, compare_internal::OnlyLiteralZero<>) noexcept { + return v.value_ <= 0; + } + friend constexpr bool operator>( + strong_ordering v, compare_internal::OnlyLiteralZero<>) noexcept { + return v.value_ > 0; + } + friend constexpr bool operator>=( + strong_ordering v, compare_internal::OnlyLiteralZero<>) noexcept { + return v.value_ >= 0; + } + friend constexpr bool operator==(compare_internal::OnlyLiteralZero<>, + strong_ordering v) noexcept { + return 0 == v.value_; + } + friend constexpr bool operator!=(compare_internal::OnlyLiteralZero<>, + strong_ordering v) noexcept { + return 0 != v.value_; + } + friend constexpr bool operator<(compare_internal::OnlyLiteralZero<>, + strong_ordering v) noexcept { + return 0 < v.value_; + } + friend constexpr bool operator<=(compare_internal::OnlyLiteralZero<>, + strong_ordering v) noexcept { + return 0 <= v.value_; + } + friend constexpr bool operator>(compare_internal::OnlyLiteralZero<>, + strong_ordering v) noexcept { + return 0 > v.value_; + } + friend constexpr bool operator>=(compare_internal::OnlyLiteralZero<>, + strong_ordering v) noexcept { + return 0 >= v.value_; + } + + private: + compare_internal::value_type value_; +}; + +namespace compare_internal { +// We also provide these comparator adapter functions for internal absl use. + +// Helper functions to do a boolean comparison of two keys given a boolean +// or three-way comparator. +constexpr bool compare_result_as_less_than(const bool r) { return r; } +constexpr bool compare_result_as_less_than(const int r) { return r < 0; } +constexpr bool compare_result_as_less_than(const absl::weak_ordering r) { + return r < 0; +} + +template <typename Compare, typename K, typename LK> +constexpr bool do_less_than_comparison(const Compare &compare, const K &x, + const LK &y) { + return compare_result_as_less_than(compare(x, y)); +} + +// Helper functions to do a three-way comparison of two keys given a boolean or +// three-way comparator. +// SFINAE prevents implicit conversions to int (such as from bool). +template <typename Int, + absl::enable_if_t<std::is_same<int, Int>::value, int> = 0> +constexpr absl::weak_ordering compare_result_as_ordering(const Int c) { + return c < 0 ? absl::weak_ordering::less + : c == 0 ? absl::weak_ordering::equivalent + : absl::weak_ordering::greater; +} +constexpr absl::weak_ordering compare_result_as_ordering( + const absl::weak_ordering c) { + return c; +} + +template < + typename Compare, typename K, typename LK, + absl::enable_if_t<!std::is_same<bool, absl::result_of_t<Compare( + const K &, const LK &)>>::value, + int> = 0> +constexpr absl::weak_ordering do_three_way_comparison(const Compare &compare, + const K &x, const LK &y) { + return compare_result_as_ordering(compare(x, y)); +} +template < + typename Compare, typename K, typename LK, + absl::enable_if_t<std::is_same<bool, absl::result_of_t<Compare( + const K &, const LK &)>>::value, + int> = 0> +constexpr absl::weak_ordering do_three_way_comparison(const Compare &compare, + const K &x, const LK &y) { + return compare(x, y) ? absl::weak_ordering::less + : compare(y, x) ? absl::weak_ordering::greater + : absl::weak_ordering::equivalent; +} + +} // namespace compare_internal +} // namespace absl + +#endif // ABSL_TYPES_COMPARE_H_ diff --git a/absl/types/compare_test.cc b/absl/types/compare_test.cc new file mode 100644 index 000000000000..dd0388c1543d --- /dev/null +++ b/absl/types/compare_test.cc @@ -0,0 +1,315 @@ +// Copyright 2018 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/types/compare.h" + +#include "gtest/gtest.h" +#include "absl/base/casts.h" + +namespace absl { +namespace { + +// This is necessary to avoid a bunch of lint warnings suggesting that we use +// EXPECT_EQ/etc., which doesn't work in this case because they convert the `0` +// to an int, which can't be converted to the unspecified zero type. +bool Identity(bool b) { return b; } + +TEST(Compare, WeakEquality) { + EXPECT_TRUE(Identity(weak_equality::equivalent == 0)); + EXPECT_TRUE(Identity(0 == weak_equality::equivalent)); + EXPECT_TRUE(Identity(weak_equality::nonequivalent != 0)); + EXPECT_TRUE(Identity(0 != weak_equality::nonequivalent)); +} + +TEST(Compare, StrongEquality) { + EXPECT_TRUE(Identity(strong_equality::equal == 0)); + EXPECT_TRUE(Identity(0 == strong_equality::equal)); + EXPECT_TRUE(Identity(strong_equality::nonequal != 0)); + EXPECT_TRUE(Identity(0 != strong_equality::nonequal)); + EXPECT_TRUE(Identity(strong_equality::equivalent == 0)); + EXPECT_TRUE(Identity(0 == strong_equality::equivalent)); + EXPECT_TRUE(Identity(strong_equality::nonequivalent != 0)); + EXPECT_TRUE(Identity(0 != strong_equality::nonequivalent)); +} + +TEST(Compare, PartialOrdering) { + EXPECT_TRUE(Identity(partial_ordering::less < 0)); + EXPECT_TRUE(Identity(0 > partial_ordering::less)); + EXPECT_TRUE(Identity(partial_ordering::less <= 0)); + EXPECT_TRUE(Identity(0 >= partial_ordering::less)); + EXPECT_TRUE(Identity(partial_ordering::equivalent == 0)); + EXPECT_TRUE(Identity(0 == partial_ordering::equivalent)); + EXPECT_TRUE(Identity(partial_ordering::greater > 0)); + EXPECT_TRUE(Identity(0 < partial_ordering::greater)); + EXPECT_TRUE(Identity(partial_ordering::greater >= 0)); + EXPECT_TRUE(Identity(0 <= partial_ordering::greater)); + EXPECT_TRUE(Identity(partial_ordering::unordered != 0)); + EXPECT_TRUE(Identity(0 != partial_ordering::unordered)); + EXPECT_FALSE(Identity(partial_ordering::unordered < 0)); + EXPECT_FALSE(Identity(0 < partial_ordering::unordered)); + EXPECT_FALSE(Identity(partial_ordering::unordered <= 0)); + EXPECT_FALSE(Identity(0 <= partial_ordering::unordered)); + EXPECT_FALSE(Identity(partial_ordering::unordered > 0)); + EXPECT_FALSE(Identity(0 > partial_ordering::unordered)); + EXPECT_FALSE(Identity(partial_ordering::unordered >= 0)); + EXPECT_FALSE(Identity(0 >= partial_ordering::unordered)); +} + +TEST(Compare, WeakOrdering) { + EXPECT_TRUE(Identity(weak_ordering::less < 0)); + EXPECT_TRUE(Identity(0 > weak_ordering::less)); + EXPECT_TRUE(Identity(weak_ordering::less <= 0)); + EXPECT_TRUE(Identity(0 >= weak_ordering::less)); + EXPECT_TRUE(Identity(weak_ordering::equivalent == 0)); + EXPECT_TRUE(Identity(0 == weak_ordering::equivalent)); + EXPECT_TRUE(Identity(weak_ordering::greater > 0)); + EXPECT_TRUE(Identity(0 < weak_ordering::greater)); + EXPECT_TRUE(Identity(weak_ordering::greater >= 0)); + EXPECT_TRUE(Identity(0 <= weak_ordering::greater)); +} + +TEST(Compare, StrongOrdering) { + EXPECT_TRUE(Identity(strong_ordering::less < 0)); + EXPECT_TRUE(Identity(0 > strong_ordering::less)); + EXPECT_TRUE(Identity(strong_ordering::less <= 0)); + EXPECT_TRUE(Identity(0 >= strong_ordering::less)); + EXPECT_TRUE(Identity(strong_ordering::equal == 0)); + EXPECT_TRUE(Identity(0 == strong_ordering::equal)); + EXPECT_TRUE(Identity(strong_ordering::equivalent == 0)); + EXPECT_TRUE(Identity(0 == strong_ordering::equivalent)); + EXPECT_TRUE(Identity(strong_ordering::greater > 0)); + EXPECT_TRUE(Identity(0 < strong_ordering::greater)); + EXPECT_TRUE(Identity(strong_ordering::greater >= 0)); + EXPECT_TRUE(Identity(0 <= strong_ordering::greater)); +} + +TEST(Compare, Conversions) { + EXPECT_TRUE( + Identity(implicit_cast<weak_equality>(strong_equality::equal) == 0)); + EXPECT_TRUE( + Identity(implicit_cast<weak_equality>(strong_equality::nonequal) != 0)); + EXPECT_TRUE( + Identity(implicit_cast<weak_equality>(strong_equality::equivalent) == 0)); + EXPECT_TRUE(Identity( + implicit_cast<weak_equality>(strong_equality::nonequivalent) != 0)); + + EXPECT_TRUE( + Identity(implicit_cast<weak_equality>(partial_ordering::less) != 0)); + EXPECT_TRUE(Identity( + implicit_cast<weak_equality>(partial_ordering::equivalent) == 0)); + EXPECT_TRUE( + Identity(implicit_cast<weak_equality>(partial_ordering::greater) != 0)); + EXPECT_TRUE( + Identity(implicit_cast<weak_equality>(partial_ordering::unordered) != 0)); + + EXPECT_TRUE(implicit_cast<weak_equality>(weak_ordering::less) != 0); + EXPECT_TRUE( + Identity(implicit_cast<weak_equality>(weak_ordering::equivalent) == 0)); + EXPECT_TRUE( + Identity(implicit_cast<weak_equality>(weak_ordering::greater) != 0)); + + EXPECT_TRUE( + Identity(implicit_cast<partial_ordering>(weak_ordering::less) != 0)); + EXPECT_TRUE( + Identity(implicit_cast<partial_ordering>(weak_ordering::less) < 0)); + EXPECT_TRUE( + Identity(implicit_cast<partial_ordering>(weak_ordering::less) <= 0)); + EXPECT_TRUE(Identity( + implicit_cast<partial_ordering>(weak_ordering::equivalent) == 0)); + EXPECT_TRUE( + Identity(implicit_cast<partial_ordering>(weak_ordering::greater) != 0)); + EXPECT_TRUE( + Identity(implicit_cast<partial_ordering>(weak_ordering::greater) > 0)); + EXPECT_TRUE( + Identity(implicit_cast<partial_ordering>(weak_ordering::greater) >= 0)); + + EXPECT_TRUE( + Identity(implicit_cast<weak_equality>(strong_ordering::less) != 0)); + EXPECT_TRUE( + Identity(implicit_cast<weak_equality>(strong_ordering::equal) == 0)); + EXPECT_TRUE( + Identity(implicit_cast<weak_equality>(strong_ordering::equivalent) == 0)); + EXPECT_TRUE( + Identity(implicit_cast<weak_equality>(strong_ordering::greater) != 0)); + + EXPECT_TRUE( + Identity(implicit_cast<strong_equality>(strong_ordering::less) != 0)); + EXPECT_TRUE( + Identity(implicit_cast<strong_equality>(strong_ordering::equal) == 0)); + EXPECT_TRUE(Identity( + implicit_cast<strong_equality>(strong_ordering::equivalent) == 0)); + EXPECT_TRUE( + Identity(implicit_cast<strong_equality>(strong_ordering::greater) != 0)); + + EXPECT_TRUE( + Identity(implicit_cast<partial_ordering>(strong_ordering::less) != 0)); + EXPECT_TRUE( + Identity(implicit_cast<partial_ordering>(strong_ordering::less) < 0)); + EXPECT_TRUE( + Identity(implicit_cast<partial_ordering>(strong_ordering::less) <= 0)); + EXPECT_TRUE( + Identity(implicit_cast<partial_ordering>(strong_ordering::equal) == 0)); + EXPECT_TRUE(Identity( + implicit_cast<partial_ordering>(strong_ordering::equivalent) == 0)); + EXPECT_TRUE( + Identity(implicit_cast<partial_ordering>(strong_ordering::greater) != 0)); + EXPECT_TRUE( + Identity(implicit_cast<partial_ordering>(strong_ordering::greater) > 0)); + EXPECT_TRUE( + Identity(implicit_cast<partial_ordering>(strong_ordering::greater) >= 0)); + + EXPECT_TRUE( + Identity(implicit_cast<weak_ordering>(strong_ordering::less) != 0)); + EXPECT_TRUE( + Identity(implicit_cast<weak_ordering>(strong_ordering::less) < 0)); + EXPECT_TRUE( + Identity(implicit_cast<weak_ordering>(strong_ordering::less) <= 0)); + EXPECT_TRUE( + Identity(implicit_cast<weak_ordering>(strong_ordering::equal) == 0)); + EXPECT_TRUE( + Identity(implicit_cast<weak_ordering>(strong_ordering::equivalent) == 0)); + EXPECT_TRUE( + Identity(implicit_cast<weak_ordering>(strong_ordering::greater) != 0)); + EXPECT_TRUE( + Identity(implicit_cast<weak_ordering>(strong_ordering::greater) > 0)); + EXPECT_TRUE( + Identity(implicit_cast<weak_ordering>(strong_ordering::greater) >= 0)); +} + +struct WeakOrderingLess { + template <typename T> + absl::weak_ordering operator()(const T &a, const T &b) const { + return a < b ? absl::weak_ordering::less + : a == b ? absl::weak_ordering::equivalent + : absl::weak_ordering::greater; + } +}; + +TEST(CompareResultAsLessThan, SanityTest) { + EXPECT_FALSE(absl::compare_internal::compare_result_as_less_than(false)); + EXPECT_TRUE(absl::compare_internal::compare_result_as_less_than(true)); + + EXPECT_TRUE(absl::compare_internal::compare_result_as_less_than(-1)); + EXPECT_FALSE(absl::compare_internal::compare_result_as_less_than(0)); + EXPECT_FALSE(absl::compare_internal::compare_result_as_less_than(1)); + + EXPECT_TRUE( + absl::compare_internal::compare_result_as_less_than(weak_ordering::less)); + EXPECT_FALSE(absl::compare_internal::compare_result_as_less_than( + weak_ordering::equivalent)); + EXPECT_FALSE(absl::compare_internal::compare_result_as_less_than( + weak_ordering::greater)); +} + +TEST(DoLessThanComparison, SanityTest) { + std::less<int> less; + WeakOrderingLess weak; + + EXPECT_TRUE(absl::compare_internal::do_less_than_comparison(less, -1, 0)); + EXPECT_TRUE(absl::compare_internal::do_less_than_comparison(weak, -1, 0)); + + EXPECT_FALSE(absl::compare_internal::do_less_than_comparison(less, 10, 10)); + EXPECT_FALSE(absl::compare_internal::do_less_than_comparison(weak, 10, 10)); + + EXPECT_FALSE(absl::compare_internal::do_less_than_comparison(less, 10, 5)); + EXPECT_FALSE(absl::compare_internal::do_less_than_comparison(weak, 10, 5)); +} + +TEST(CompareResultAsOrdering, SanityTest) { + EXPECT_TRUE(Identity( + absl::compare_internal::compare_result_as_ordering(-1) < 0)); + EXPECT_FALSE(Identity( + absl::compare_internal::compare_result_as_ordering(-1) == 0)); + EXPECT_FALSE( + Identity(absl::compare_internal::compare_result_as_ordering(-1) > 0)); + EXPECT_TRUE(Identity(absl::compare_internal::compare_result_as_ordering( + weak_ordering::less) < 0)); + EXPECT_FALSE(Identity(absl::compare_internal::compare_result_as_ordering( + weak_ordering::less) == 0)); + EXPECT_FALSE(Identity(absl::compare_internal::compare_result_as_ordering( + weak_ordering::less) > 0)); + + EXPECT_FALSE(Identity( + absl::compare_internal::compare_result_as_ordering(0) < 0)); + EXPECT_TRUE(Identity( + absl::compare_internal::compare_result_as_ordering(0) == 0)); + EXPECT_FALSE(Identity( + absl::compare_internal::compare_result_as_ordering(0) > 0)); + EXPECT_FALSE(Identity(absl::compare_internal::compare_result_as_ordering( + weak_ordering::equivalent) < 0)); + EXPECT_TRUE(Identity(absl::compare_internal::compare_result_as_ordering( + weak_ordering::equivalent) == 0)); + EXPECT_FALSE(Identity(absl::compare_internal::compare_result_as_ordering( + weak_ordering::equivalent) > 0)); + + EXPECT_FALSE(Identity( + absl::compare_internal::compare_result_as_ordering(1) < 0)); + EXPECT_FALSE(Identity( + absl::compare_internal::compare_result_as_ordering(1) == 0)); + EXPECT_TRUE(Identity( + absl::compare_internal::compare_result_as_ordering(1) > 0)); + EXPECT_FALSE(Identity(absl::compare_internal::compare_result_as_ordering( + weak_ordering::greater) < 0)); + EXPECT_FALSE(Identity(absl::compare_internal::compare_result_as_ordering( + weak_ordering::greater) == 0)); + EXPECT_TRUE(Identity(absl::compare_internal::compare_result_as_ordering( + weak_ordering::greater) > 0)); +} + +TEST(DoThreeWayComparison, SanityTest) { + std::less<int> less; + WeakOrderingLess weak; + + EXPECT_TRUE(Identity( + absl::compare_internal::do_three_way_comparison(less, -1, 0) < 0)); + EXPECT_FALSE(Identity( + absl::compare_internal::do_three_way_comparison(less, -1, 0) == 0)); + EXPECT_FALSE(Identity( + absl::compare_internal::do_three_way_comparison(less, -1, 0) > 0)); + EXPECT_TRUE(Identity( + absl::compare_internal::do_three_way_comparison(weak, -1, 0) < 0)); + EXPECT_FALSE(Identity( + absl::compare_internal::do_three_way_comparison(weak, -1, 0) == 0)); + EXPECT_FALSE(Identity( + absl::compare_internal::do_three_way_comparison(weak, -1, 0) > 0)); + + EXPECT_FALSE(Identity( + absl::compare_internal::do_three_way_comparison(less, 10, 10) < 0)); + EXPECT_TRUE(Identity( + absl::compare_internal::do_three_way_comparison(less, 10, 10) == 0)); + EXPECT_FALSE(Identity( + absl::compare_internal::do_three_way_comparison(less, 10, 10) > 0)); + EXPECT_FALSE(Identity( + absl::compare_internal::do_three_way_comparison(weak, 10, 10) < 0)); + EXPECT_TRUE(Identity( + absl::compare_internal::do_three_way_comparison(weak, 10, 10) == 0)); + EXPECT_FALSE(Identity( + absl::compare_internal::do_three_way_comparison(weak, 10, 10) > 0)); + + EXPECT_FALSE(Identity( + absl::compare_internal::do_three_way_comparison(less, 10, 5) < 0)); + EXPECT_FALSE(Identity( + absl::compare_internal::do_three_way_comparison(less, 10, 5) == 0)); + EXPECT_TRUE(Identity( + absl::compare_internal::do_three_way_comparison(less, 10, 5) > 0)); + EXPECT_FALSE(Identity( + absl::compare_internal::do_three_way_comparison(weak, 10, 5) < 0)); + EXPECT_FALSE(Identity( + absl::compare_internal::do_three_way_comparison(weak, 10, 5) == 0)); + EXPECT_TRUE(Identity( + absl::compare_internal::do_three_way_comparison(weak, 10, 5) > 0)); +} + +} // namespace +} // namespace absl |