Add `operator<=>` support to `absl::int128` and `absl::uint128`

PiperOrigin-RevId: 626080616
Change-Id: If434be2371c1e28f9fd0133f411596bdc38bd222
diff --git a/absl/numeric/BUILD.bazel b/absl/numeric/BUILD.bazel
index 41c015d..f202c6e 100644
--- a/absl/numeric/BUILD.bazel
+++ b/absl/numeric/BUILD.bazel
@@ -89,6 +89,7 @@
         ":bits",
         "//absl/base:config",
         "//absl/base:core_headers",
+        "//absl/types:compare",
     ],
 )
 
@@ -107,6 +108,7 @@
         "//absl/hash:hash_testing",
         "//absl/meta:type_traits",
         "//absl/strings",
+        "//absl/types:compare",
         "@com_google_googletest//:gtest",
         "@com_google_googletest//:gtest_main",
     ],
diff --git a/absl/numeric/CMakeLists.txt b/absl/numeric/CMakeLists.txt
index 7181b91..da3b6ef 100644
--- a/absl/numeric/CMakeLists.txt
+++ b/absl/numeric/CMakeLists.txt
@@ -53,6 +53,7 @@
   COPTS
     ${ABSL_DEFAULT_COPTS}
   DEPS
+    absl::compare
     absl::config
     absl::core_headers
     absl::bits
@@ -70,6 +71,7 @@
   DEPS
     absl::int128
     absl::base
+    absl::compare
     absl::hash_testing
     absl::type_traits
     absl::strings
diff --git a/absl/numeric/int128.h b/absl/numeric/int128.h
index a17d0e1..562d5e5 100644
--- a/absl/numeric/int128.h
+++ b/absl/numeric/int128.h
@@ -38,6 +38,7 @@
 #include "absl/base/config.h"
 #include "absl/base/macros.h"
 #include "absl/base/port.h"
+#include "absl/types/compare.h"
 
 #if defined(_MSC_VER)
 // In very old versions of MSVC and when the /Zc:wchar_t flag is off, wchar_t is
@@ -819,6 +820,36 @@
 
 constexpr bool operator>=(uint128 lhs, uint128 rhs) { return !(lhs < rhs); }
 
+#ifdef __cpp_impl_three_way_comparison
+constexpr absl::strong_ordering operator<=>(uint128 lhs, uint128 rhs) {
+#if defined(ABSL_HAVE_INTRINSIC_INT128)
+  if (auto lhs_128 = static_cast<unsigned __int128>(lhs),
+      rhs_128 = static_cast<unsigned __int128>(rhs);
+      lhs_128 < rhs_128) {
+    return absl::strong_ordering::less;
+  } else if (lhs_128 > rhs_128) {
+    return absl::strong_ordering::greater;
+  } else {
+    return absl::strong_ordering::equal;
+  }
+#else
+  if (uint64_t lhs_high = Uint128High64(lhs), rhs_high = Uint128High64(rhs);
+      lhs_high < rhs_high) {
+    return absl::strong_ordering::less;
+  } else if (lhs_high > rhs_high) {
+    return absl::strong_ordering::greater;
+  } else if (uint64_t lhs_low = Uint128Low64(lhs), rhs_low = Uint128Low64(rhs);
+             lhs_low < rhs_low) {
+    return absl::strong_ordering::less;
+  } else if (lhs_low > rhs_low) {
+    return absl::strong_ordering::greater;
+  } else {
+    return absl::strong_ordering::equal;
+  }
+#endif
+}
+#endif
+
 // Unary operators.
 
 constexpr inline uint128 operator+(uint128 val) { return val; }
diff --git a/absl/numeric/int128_have_intrinsic.inc b/absl/numeric/int128_have_intrinsic.inc
index 6f1ac64..51e4b9d 100644
--- a/absl/numeric/int128_have_intrinsic.inc
+++ b/absl/numeric/int128_have_intrinsic.inc
@@ -220,6 +220,20 @@
   return static_cast<__int128>(lhs) >= static_cast<__int128>(rhs);
 }
 
+#ifdef __cpp_impl_three_way_comparison
+constexpr absl::strong_ordering operator<=>(int128 lhs, int128 rhs) {
+  if (auto lhs_128 = static_cast<__int128>(lhs),
+      rhs_128 = static_cast<__int128>(rhs);
+      lhs_128 < rhs_128) {
+    return absl::strong_ordering::less;
+  } else if (lhs_128 > rhs_128) {
+    return absl::strong_ordering::greater;
+  } else {
+    return absl::strong_ordering::equal;
+  }
+}
+#endif
+
 // Unary operators.
 
 constexpr int128 operator-(int128 v) { return -static_cast<__int128>(v); }
diff --git a/absl/numeric/int128_no_intrinsic.inc b/absl/numeric/int128_no_intrinsic.inc
index 6f5d837..195b745 100644
--- a/absl/numeric/int128_no_intrinsic.inc
+++ b/absl/numeric/int128_no_intrinsic.inc
@@ -186,6 +186,24 @@
 
 constexpr bool operator>=(int128 lhs, int128 rhs) { return !(lhs < rhs); }
 
+#ifdef __cpp_impl_three_way_comparison
+constexpr absl::strong_ordering operator<=>(int128 lhs, int128 rhs) {
+  if (int64_t lhs_high = Int128High64(lhs), rhs_high = Int128High64(rhs);
+      lhs_high < rhs_high) {
+    return absl::strong_ordering::less;
+  } else if (lhs_high > rhs_high) {
+    return absl::strong_ordering::greater;
+  } else if (uint64_t lhs_low = Uint128Low64(lhs), rhs_low = Uint128Low64(rhs);
+             lhs_low < rhs_low) {
+    return absl::strong_ordering::less;
+  } else if (lhs_low > rhs_low) {
+    return absl::strong_ordering::greater;
+  } else {
+    return absl::strong_ordering::equal;
+  }
+}
+#endif
+
 // Unary operators.
 
 constexpr int128 operator-(int128 v) {
diff --git a/absl/numeric/int128_test.cc b/absl/numeric/int128_test.cc
index f17a5f6..3f16e05 100644
--- a/absl/numeric/int128_test.cc
+++ b/absl/numeric/int128_test.cc
@@ -25,6 +25,7 @@
 #include "absl/base/internal/cycleclock.h"
 #include "absl/hash/hash_testing.h"
 #include "absl/meta/type_traits.h"
+#include "absl/types/compare.h"
 
 #define MAKE_INT128(HI, LO) absl::MakeInt128(static_cast<int64_t>(HI), LO)
 
@@ -784,6 +785,13 @@
     EXPECT_FALSE(pair.smaller >= pair.larger);  // NOLINT(readability/check)
     EXPECT_TRUE(pair.smaller >= pair.smaller);  // NOLINT(readability/check)
     EXPECT_TRUE(pair.larger >= pair.larger);    // NOLINT(readability/check)
+
+#ifdef __cpp_impl_three_way_comparison
+    EXPECT_EQ(pair.smaller <=> pair.larger, absl::strong_ordering::less);
+    EXPECT_EQ(pair.larger <=> pair.smaller, absl::strong_ordering::greater);
+    EXPECT_EQ(pair.smaller <=> pair.smaller, absl::strong_ordering::equal);
+    EXPECT_EQ(pair.larger <=> pair.larger, absl::strong_ordering::equal);
+#endif
   }
 }