Support for int128 to string type conversion.

PiperOrigin-RevId: 542269673
Change-Id: Ib6f7e9a57f83d73dd6fb9c45fc9f85ff0fdd75fe
diff --git a/absl/numeric/BUILD.bazel b/absl/numeric/BUILD.bazel
index ec0b870..c5aaf72 100644
--- a/absl/numeric/BUILD.bazel
+++ b/absl/numeric/BUILD.bazel
@@ -97,6 +97,7 @@
         "//absl/base",
         "//absl/hash:hash_testing",
         "//absl/meta:type_traits",
+        "//absl/strings",
         "@com_google_googletest//:gtest_main",
     ],
 )
diff --git a/absl/numeric/CMakeLists.txt b/absl/numeric/CMakeLists.txt
index 384c0fc..7181b91 100644
--- a/absl/numeric/CMakeLists.txt
+++ b/absl/numeric/CMakeLists.txt
@@ -72,6 +72,7 @@
     absl::base
     absl::hash_testing
     absl::type_traits
+    absl::strings
     GTest::gmock_main
 )
 
diff --git a/absl/numeric/int128.cc b/absl/numeric/int128.cc
index 6ffe43d..daa32b5 100644
--- a/absl/numeric/int128.cc
+++ b/absl/numeric/int128.cc
@@ -202,6 +202,10 @@
 
 }  // namespace
 
+std::string uint128::ToString() const {
+  return Uint128ToFormattedString(*this, std::ios_base::dec);
+}
+
 std::ostream& operator<<(std::ostream& os, uint128 v) {
   std::ios_base::fmtflags flags = os.flags();
   std::string rep = Uint128ToFormattedString(v, flags);
@@ -285,6 +289,14 @@
 }
 #endif  // ABSL_HAVE_INTRINSIC_INT128
 
+std::string int128::ToString() const {
+  std::string rep;
+  if (Int128High64(*this) < 0) rep = "-";
+  rep.append(Uint128ToFormattedString(UnsignedAbsoluteValue(*this),
+                                      std::ios_base::dec));
+  return rep;
+}
+
 std::ostream& operator<<(std::ostream& os, int128 v) {
   std::ios_base::fmtflags flags = os.flags();
   std::string rep;
diff --git a/absl/numeric/int128.h b/absl/numeric/int128.h
index aa0f86f..7530a79 100644
--- a/absl/numeric/int128.h
+++ b/absl/numeric/int128.h
@@ -32,6 +32,7 @@
 #include <cstring>
 #include <iosfwd>
 #include <limits>
+#include <string>
 #include <utility>
 
 #include "absl/base/config.h"
@@ -217,9 +218,17 @@
     return H::combine(std::move(h), Uint128High64(v), Uint128Low64(v));
   }
 
+  // Support for absl::StrCat() etc.
+  template <typename Sink>
+  friend void AbslStringify(Sink& sink, uint128 v) {
+    sink.Append(v.ToString());
+  }
+
  private:
   constexpr uint128(uint64_t high, uint64_t low);
 
+  std::string ToString() const;
+
   // TODO(strel) Update implementation to use __int128 once all users of
   // uint128 are fixed to not depend on alignof(uint128) == 8. Also add
   // alignas(16) to class definition to keep alignment consistent across
@@ -454,9 +463,17 @@
     return H::combine(std::move(h), Int128High64(v), Int128Low64(v));
   }
 
+  // Support for absl::StrCat() etc.
+  template <typename Sink>
+  friend void AbslStringify(Sink& sink, int128 v) {
+    sink.Append(v.ToString());
+  }
+
  private:
   constexpr int128(int64_t high, uint64_t low);
 
+  std::string ToString() const;
+
 #if defined(ABSL_HAVE_INTRINSIC_INT128)
   __int128 v_;
 #else  // ABSL_HAVE_INTRINSIC_INT128
diff --git a/absl/numeric/int128_stream_test.cc b/absl/numeric/int128_stream_test.cc
index 81d2ade..bd93784 100644
--- a/absl/numeric/int128_stream_test.cc
+++ b/absl/numeric/int128_stream_test.cc
@@ -18,6 +18,7 @@
 #include <string>
 
 #include "gtest/gtest.h"
+#include "absl/strings/str_cat.h"
 
 namespace {
 
@@ -87,6 +88,9 @@
 constexpr std::ios::fmtflags kPos = std::ios::showpos;
 
 void CheckUint128Case(const Uint128TestCase& test_case) {
+  if (test_case.flags == kDec && test_case.width == 0) {
+    EXPECT_EQ(absl::StrCat(test_case.value), test_case.expected);
+  }
   std::ostringstream os;
   os.flags(test_case.flags);
   os.width(test_case.width);
@@ -155,6 +159,9 @@
 };
 
 void CheckInt128Case(const Int128TestCase& test_case) {
+  if (test_case.flags == kDec && test_case.width == 0) {
+    EXPECT_EQ(absl::StrCat(test_case.value), test_case.expected);
+  }
   std::ostringstream os;
   os.flags(test_case.flags);
   os.width(test_case.width);