Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[C++] Refactor uint128 #8416

Merged
merged 5 commits into from
Mar 30, 2021
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
[C++] Refactor uint128
This makes it compatible with absl::uint128
Yannic committed Mar 20, 2021
commit 7efa91bd2e5268628e47d9db7f2a8ce7573f08c4
15 changes: 10 additions & 5 deletions src/google/protobuf/stubs/int128.cc
Original file line number Diff line number Diff line change
@@ -33,18 +33,15 @@
#include <iomanip>
#include <ostream> // NOLINT(readability/streams)
#include <sstream>
#include <string>

#include <google/protobuf/stubs/logging.h>

#include <google/protobuf/port_def.inc>

namespace google {
namespace protobuf {

const uint128_pod kuint128max = {
static_cast<uint64>(PROTOBUF_LONGLONG(0xFFFFFFFFFFFFFFFF)),
static_cast<uint64>(PROTOBUF_LONGLONG(0xFFFFFFFFFFFFFFFF))
};
namespace int128_internal {

// Returns the 0-based position of the last set bit (i.e., most significant bit)
// in the given uint64. The argument may not be 0.
@@ -188,6 +185,14 @@ std::ostream& operator<<(std::ostream& o, const uint128& b) {
return o << rep;
}

void VerifyValidShift(std::string op, int amount) {
// Shifting more than 127 is UB in Abseil, just crash for now to verify
// callers don't depend on it returning 0.
GOOGLE_CHECK_LT(amount, 128) << "Error executing operator " << op
<< ": shifts of more than 127 are undefined";
}

} // namespace int128_internal
} // namespace protobuf
} // namespace google

127 changes: 58 additions & 69 deletions src/google/protobuf/stubs/int128.h
Original file line number Diff line number Diff line change
@@ -33,38 +33,33 @@
#include <google/protobuf/stubs/common.h>

#include <iosfwd>
#include <limits>
#include <string>

#include <google/protobuf/port_def.inc>

namespace google {
namespace protobuf {

struct uint128_pod;

// TODO(xiaofeng): Define GOOGLE_PROTOBUF_HAS_CONSTEXPR when constexpr is
// available.
#ifdef GOOGLE_PROTOBUF_HAS_CONSTEXPR
# define UINT128_CONSTEXPR constexpr
#else
# define UINT128_CONSTEXPR
#endif
namespace int128_internal {

// An unsigned 128-bit integer type. Thread-compatible.
class PROTOBUF_EXPORT uint128 {
public:
UINT128_CONSTEXPR uint128(); // Sets to 0, but don't trust on this behavior.
UINT128_CONSTEXPR uint128(uint64 top, uint64 bottom);
uint128() = default;

private:
// Use `MakeUint128` instead.
constexpr uint128(uint64 top, uint64 bottom);

public:
#ifndef SWIG
UINT128_CONSTEXPR uint128(int bottom);
UINT128_CONSTEXPR uint128(uint32 bottom); // Top 96 bits = 0
constexpr uint128(int bottom);
constexpr uint128(uint32 bottom); // Top 96 bits = 0
#endif
UINT128_CONSTEXPR uint128(uint64 bottom); // hi_ = 0
UINT128_CONSTEXPR uint128(const uint128_pod &val);
constexpr uint128(uint64 bottom); // hi_ = 0

// Trivial copy constructor, assignment operator and destructor.

void Initialize(uint64 top, uint64 bottom);

// Arithmetic operators.
uint128& operator+=(const uint128& b);
uint128& operator-=(const uint128& b);
@@ -82,8 +77,10 @@ class PROTOBUF_EXPORT uint128 {
uint128& operator++();
uint128& operator--();

friend uint64 Uint128Low64(const uint128& v);
friend uint64 Uint128High64(const uint128& v);
friend constexpr uint64 Uint128Low64(const uint128& v);
friend constexpr uint64 Uint128High64(const uint128& v);

friend constexpr uint128 MakeUint128(uint64_t high, uint64_t low);

// We add "std::" to avoid including all of port.h.
PROTOBUF_EXPORT friend std::ostream& operator<<(std::ostream& o,
@@ -100,35 +97,25 @@ class PROTOBUF_EXPORT uint128 {
uint64 hi_;

// Not implemented, just declared for catching automatic type conversions.
uint128(uint8);
uint128(uint16);
uint128(float v);
uint128(double v);
};

// This is a POD form of uint128 which can be used for static variables which
// need to be operated on as uint128.
struct uint128_pod {
// Note: The ordering of fields is different than 'class uint128' but the
// same as its 2-arg constructor. This enables more obvious initialization
// of static instances, which is the primary reason for this struct in the
// first place. This does not seem to defeat any optimizations wrt
// operations involving this struct.
uint64 hi;
uint64 lo;
uint128(uint8) = delete;
uint128(uint16) = delete;
uint128(float v) = delete;
uint128(double v) = delete;
};

PROTOBUF_EXPORT extern const uint128_pod kuint128max;

// allow uint128 to be logged
PROTOBUF_EXPORT extern std::ostream& operator<<(std::ostream& o,
const uint128& b);

// Methods to access low and high pieces of 128-bit value.
// Defined externally from uint128 to facilitate conversion
// to native 128-bit types when compilers support them.
inline uint64 Uint128Low64(const uint128& v) { return v.lo_; }
inline uint64 Uint128High64(const uint128& v) { return v.hi_; }
inline constexpr uint64 Uint128Low64(const uint128& v) { return v.lo_; }
inline constexpr uint64 Uint128High64(const uint128& v) { return v.hi_; }

constexpr uint128 MakeUint128(uint64_t high, uint64_t low) {
return uint128(high, low);
}

// TODO: perhaps it would be nice to have int128, a signed 128-bit type?

@@ -143,27 +130,17 @@ inline bool operator!=(const uint128& lhs, const uint128& rhs) {
return !(lhs == rhs);
}

inline UINT128_CONSTEXPR uint128::uint128() : lo_(0), hi_(0) {}
inline UINT128_CONSTEXPR uint128::uint128(uint64 top, uint64 bottom)
inline constexpr uint128::uint128(uint64 top, uint64 bottom)
: lo_(bottom), hi_(top) {}
inline UINT128_CONSTEXPR uint128::uint128(const uint128_pod& v)
: lo_(v.lo), hi_(v.hi) {}
inline UINT128_CONSTEXPR uint128::uint128(uint64 bottom)
inline constexpr uint128::uint128(uint64 bottom)
: lo_(bottom), hi_(0) {}
#ifndef SWIG
inline UINT128_CONSTEXPR uint128::uint128(uint32 bottom)
inline constexpr uint128::uint128(uint32 bottom)
: lo_(bottom), hi_(0) {}
inline UINT128_CONSTEXPR uint128::uint128(int bottom)
inline constexpr uint128::uint128(int bottom)
: lo_(bottom), hi_(static_cast<int64>((bottom < 0) ? -1 : 0)) {}
#endif

#undef UINT128_CONSTEXPR

inline void uint128::Initialize(uint64 top, uint64 bottom) {
hi_ = top;
lo_ = bottom;
}

// Comparison operators.

#define CMP128(op) \
@@ -187,9 +164,9 @@ inline uint128 operator-(const uint128& val) {
const uint64 lo_flip = ~Uint128Low64(val);
const uint64 lo_add = lo_flip + 1;
if (lo_add < lo_flip) {
return uint128(hi_flip + 1, lo_add);
return MakeUint128(hi_flip + 1, lo_add);
}
return uint128(hi_flip, lo_add);
return MakeUint128(hi_flip, lo_add);
}

inline bool operator!(const uint128& val) {
@@ -199,13 +176,13 @@ inline bool operator!(const uint128& val) {
// Logical operators.

inline uint128 operator~(const uint128& val) {
return uint128(~Uint128High64(val), ~Uint128Low64(val));
return MakeUint128(~Uint128High64(val), ~Uint128Low64(val));
}

#define LOGIC128(op) \
inline uint128 operator op(const uint128& lhs, const uint128& rhs) { \
return uint128(Uint128High64(lhs) op Uint128High64(rhs), \
Uint128Low64(lhs) op Uint128Low64(rhs)); \
return MakeUint128(Uint128High64(lhs) op Uint128High64(rhs), \
Uint128Low64(lhs) op Uint128Low64(rhs)); \
}

LOGIC128(|)
@@ -229,7 +206,11 @@ LOGICASSIGN128(^=)

// Shift operators.

void VerifyValidShift(std::string op, int amount);

inline uint128 operator<<(const uint128& val, int amount) {
VerifyValidShift("<<", amount);

// uint64 shifts of >= 64 are undefined, so we will need some special-casing.
if (amount < 64) {
if (amount == 0) {
@@ -238,15 +219,14 @@ inline uint128 operator<<(const uint128& val, int amount) {
uint64 new_hi = (Uint128High64(val) << amount) |
(Uint128Low64(val) >> (64 - amount));
uint64 new_lo = Uint128Low64(val) << amount;
return uint128(new_hi, new_lo);
} else if (amount < 128) {
return uint128(Uint128Low64(val) << (amount - 64), 0);
} else {
return uint128(0, 0);
return MakeUint128(new_hi, new_lo);
}
return MakeUint128(Uint128Low64(val) << (amount - 64), 0);
}

inline uint128 operator>>(const uint128& val, int amount) {
VerifyValidShift(">>", amount);

// uint64 shifts of >= 64 are undefined, so we will need some special-casing.
if (amount < 64) {
if (amount == 0) {
@@ -255,12 +235,10 @@ inline uint128 operator>>(const uint128& val, int amount) {
uint64 new_hi = Uint128High64(val) >> amount;
uint64 new_lo = (Uint128Low64(val) >> amount) |
(Uint128High64(val) << (64 - amount));
return uint128(new_hi, new_lo);
} else if (amount < 128) {
return uint128(0, Uint128High64(val) >> (amount - 64));
} else {
return uint128(0, 0);
return MakeUint128(new_hi, new_lo);
}

return MakeUint128(0, Uint128High64(val) >> (amount - 64));
}

inline uint128& uint128::operator<<=(int amount) {
@@ -379,6 +357,17 @@ inline uint128& uint128::operator--() {
return *this;
}

constexpr uint128 Uint128Max() {
return MakeUint128((std::numeric_limits<uint64>::max)(),
(std::numeric_limits<uint64>::max)());
}

} // namespace int128_internal

using absl::uint128;
Yannic marked this conversation as resolved.
Show resolved Hide resolved
using absl::Uint128Max;
using absl::MakeUint128;

} // namespace protobuf
} // namespace google

195 changes: 58 additions & 137 deletions src/google/protobuf/stubs/int128_unittest.cc
Original file line number Diff line number Diff line change
@@ -44,16 +44,18 @@ namespace protobuf {

TEST(Int128, AllTests) {
Yannic marked this conversation as resolved.
Show resolved Hide resolved
uint128 zero(0);
EXPECT_EQ(zero, uint128());

uint128 one(1);
uint128 one_2arg(0, 1);
uint128 two(0, 2);
uint128 three(0, 3);
uint128 big(2000, 2);
uint128 big_minus_one(2000, 1);
uint128 bigger(2001, 1);
uint128 biggest(kuint128max);
uint128 high_low(1, 0);
uint128 low_high(0, kuint64max);
uint128 one_2arg = MakeUint128(0, 1);
uint128 two = MakeUint128(0, 2);
uint128 three = MakeUint128(0, 3);
uint128 big = MakeUint128(2000, 2);
uint128 big_minus_one = MakeUint128(2000, 1);
uint128 bigger = MakeUint128(2001, 1);
uint128 biggest(Uint128Max());
uint128 high_low = MakeUint128(1, 0);
uint128 low_high = MakeUint128(0, kuint64max);
EXPECT_LT(one, two);
EXPECT_GT(two, one);
EXPECT_LT(one, big);
@@ -92,8 +94,6 @@ TEST(Int128, AllTests) {
EXPECT_EQ(big, (big >> 1) << 1);
EXPECT_EQ(one, (one << 80) >> 80);
EXPECT_EQ(zero, (one >> 80) << 80);
EXPECT_EQ(zero, big >> 128);
EXPECT_EQ(zero, big << 128);

// Shift assignments.
uint128 big_copy = big;
@@ -117,9 +117,9 @@ TEST(Int128, AllTests) {
big_copy = big;
EXPECT_EQ(big >> 73, big_copy >>= 73);
big_copy = big;
EXPECT_EQ(big << 128, big_copy <<= 128);
EXPECT_EQ(big << 127, big_copy <<= 127);
big_copy = big;
EXPECT_EQ(big >> 128, big_copy >>= 128);
EXPECT_EQ(big >> 127, big_copy >>= 127);

EXPECT_EQ(Uint128High64(biggest), kuint64max);
EXPECT_EQ(Uint128Low64(biggest), kuint64max);
@@ -170,92 +170,13 @@ TEST(Int128, AllTests) {

EXPECT_EQ(big, -(-big));
EXPECT_EQ(two, -((-one) - 1));
EXPECT_EQ(kuint128max, -one);
EXPECT_EQ(Uint128Max(), -one);
EXPECT_EQ(zero, -zero);

GOOGLE_LOG(INFO) << one;
GOOGLE_LOG(INFO) << big_minus_one;
}

TEST(Int128, PodTests) {
uint128_pod pod = { 12345, 67890 };
uint128 from_pod(pod);
EXPECT_EQ(12345, Uint128High64(from_pod));
EXPECT_EQ(67890, Uint128Low64(from_pod));

uint128 zero(0);
uint128_pod zero_pod = {0, 0};
uint128 one(1);
uint128_pod one_pod = {0, 1};
uint128 two(2);
uint128_pod two_pod = {0, 2};
uint128 three(3);
uint128_pod three_pod = {0, 3};
uint128 big(1, 0);
uint128_pod big_pod = {1, 0};

EXPECT_EQ(zero, zero_pod);
EXPECT_EQ(zero_pod, zero);
EXPECT_EQ(zero_pod, zero_pod);
EXPECT_EQ(one, one_pod);
EXPECT_EQ(one_pod, one);
EXPECT_EQ(one_pod, one_pod);
EXPECT_EQ(two, two_pod);
EXPECT_EQ(two_pod, two);
EXPECT_EQ(two_pod, two_pod);

EXPECT_NE(one, two_pod);
EXPECT_NE(one_pod, two);
EXPECT_NE(one_pod, two_pod);

EXPECT_LT(one, two_pod);
EXPECT_LT(one_pod, two);
EXPECT_LT(one_pod, two_pod);
EXPECT_LE(one, one_pod);
EXPECT_LE(one_pod, one);
EXPECT_LE(one_pod, one_pod);
EXPECT_LE(one, two_pod);
EXPECT_LE(one_pod, two);
EXPECT_LE(one_pod, two_pod);

EXPECT_GT(two, one_pod);
EXPECT_GT(two_pod, one);
EXPECT_GT(two_pod, one_pod);
EXPECT_GE(two, two_pod);
EXPECT_GE(two_pod, two);
EXPECT_GE(two_pod, two_pod);
EXPECT_GE(two, one_pod);
EXPECT_GE(two_pod, one);
EXPECT_GE(two_pod, one_pod);

EXPECT_EQ(three, one | two_pod);
EXPECT_EQ(three, one_pod | two);
EXPECT_EQ(three, one_pod | two_pod);
EXPECT_EQ(one, three & one_pod);
EXPECT_EQ(one, three_pod & one);
EXPECT_EQ(one, three_pod & one_pod);
EXPECT_EQ(two, three ^ one_pod);
EXPECT_EQ(two, three_pod ^ one);
EXPECT_EQ(two, three_pod ^ one_pod);
EXPECT_EQ(two, three & (~one));
EXPECT_EQ(three, ~~three);

EXPECT_EQ(two, two_pod << 0);
EXPECT_EQ(two, one_pod << 1);
EXPECT_EQ(big, one_pod << 64);
EXPECT_EQ(zero, one_pod << 128);
EXPECT_EQ(two, two_pod >> 0);
EXPECT_EQ(one, two_pod >> 1);
EXPECT_EQ(one, big_pod >> 64);

EXPECT_EQ(one, zero + one_pod);
EXPECT_EQ(one, zero_pod + one);
EXPECT_EQ(one, zero_pod + one_pod);
EXPECT_EQ(one, two - one_pod);
EXPECT_EQ(one, two_pod - one);
EXPECT_EQ(one, two_pod - one_pod);
}

TEST(Int128, OperatorAssignReturnRef) {
uint128 v(1);
(v += 4) -= 3;
@@ -293,38 +214,38 @@ TEST(Int128, Multiply) {
}

// Verified with dc.
a = uint128(PROTOBUF_ULONGLONG(0xffffeeeeddddcccc),
PROTOBUF_ULONGLONG(0xbbbbaaaa99998888));
b = uint128(PROTOBUF_ULONGLONG(0x7777666655554444),
PROTOBUF_ULONGLONG(0x3333222211110000));
a = MakeUint128(PROTOBUF_ULONGLONG(0xffffeeeeddddcccc),
PROTOBUF_ULONGLONG(0xbbbbaaaa99998888));
b = MakeUint128(PROTOBUF_ULONGLONG(0x7777666655554444),
PROTOBUF_ULONGLONG(0x3333222211110000));
c = a * b;
EXPECT_EQ(uint128(PROTOBUF_ULONGLONG(0x530EDA741C71D4C3),
PROTOBUF_ULONGLONG(0xBF25975319080000)),
EXPECT_EQ(MakeUint128(PROTOBUF_ULONGLONG(0x530EDA741C71D4C3),
PROTOBUF_ULONGLONG(0xBF25975319080000)),
c);
EXPECT_EQ(0, c - b * a);
EXPECT_EQ(a * a - b * b, (a + b) * (a - b));

// Verified with dc.
a = uint128(PROTOBUF_ULONGLONG(0x0123456789abcdef),
PROTOBUF_ULONGLONG(0xfedcba9876543210));
b = uint128(PROTOBUF_ULONGLONG(0x02468ace13579bdf),
PROTOBUF_ULONGLONG(0xfdb97531eca86420));
a = MakeUint128(PROTOBUF_ULONGLONG(0x0123456789abcdef),
PROTOBUF_ULONGLONG(0xfedcba9876543210));
b = MakeUint128(PROTOBUF_ULONGLONG(0x02468ace13579bdf),
PROTOBUF_ULONGLONG(0xfdb97531eca86420));
c = a * b;
EXPECT_EQ(uint128(PROTOBUF_ULONGLONG(0x97a87f4f261ba3f2),
PROTOBUF_ULONGLONG(0x342d0bbf48948200)),
EXPECT_EQ(MakeUint128(PROTOBUF_ULONGLONG(0x97a87f4f261ba3f2),
PROTOBUF_ULONGLONG(0x342d0bbf48948200)),
c);
EXPECT_EQ(0, c - b * a);
EXPECT_EQ(a*a - b*b, (a+b) * (a-b));
}

TEST(Int128, AliasTests) {
uint128 x1(1, 2);
uint128 x2(2, 4);
uint128 x1 = MakeUint128(1, 2);
uint128 x2 = MakeUint128(2, 4);
x1 += x1;
EXPECT_EQ(x2, x1);

uint128 x3(1, static_cast<uint64>(1) << 63);
uint128 x4(3, 0);
uint128 x3 = MakeUint128(1, static_cast<uint64>(1) << 63);
uint128 x4 = MakeUint128(3, 0);
x3 += x3;
EXPECT_EQ(x4, x3);
}
@@ -345,6 +266,12 @@ TEST(Int128, ModByZeroCheckFails) {
a = 123;
EXPECT_DEATH(a % b, "Division or mod by zero:");
}

TEST(Int128, ShiftGreater128) {
uint128 a;
EXPECT_DEATH(a << 128, "Left-shift greater or equal 128");
EXPECT_DEATH(a >> 128, "Right-shift greater or equal 128");
}
#endif // PROTOBUF_HAS_DEATH_TEST

TEST(Int128, DivideAndMod) {
@@ -359,10 +286,10 @@ TEST(Int128, DivideAndMod) {
EXPECT_EQ(0, q);
EXPECT_EQ(0, r);

a = uint128(PROTOBUF_ULONGLONG(0x530eda741c71d4c3),
PROTOBUF_ULONGLONG(0xbf25975319080000));
q = uint128(PROTOBUF_ULONGLONG(0x4de2cab081),
PROTOBUF_ULONGLONG(0x14c34ab4676e4bab));
a = MakeUint128(PROTOBUF_ULONGLONG(0x530eda741c71d4c3),
PROTOBUF_ULONGLONG(0xbf25975319080000));
q = MakeUint128(PROTOBUF_ULONGLONG(0x4de2cab081),
PROTOBUF_ULONGLONG(0x14c34ab4676e4bab));
b = uint128(0x1110001);
r = uint128(0x3eb455);
ASSERT_EQ(a, q * b + r); // Sanity-check.
@@ -400,8 +327,8 @@ TEST(Int128, DivideAndMod) {

// Try a large remainder.
b = a / 2 + 1;
uint128 expected_r(PROTOBUF_ULONGLONG(0x29876d3a0e38ea61),
PROTOBUF_ULONGLONG(0xdf92cba98c83ffff));
uint128 expected_r = MakeUint128(PROTOBUF_ULONGLONG(0x29876d3a0e38ea61),
PROTOBUF_ULONGLONG(0xdf92cba98c83ffff));
// Sanity checks.
ASSERT_EQ(a / 2 - 1, expected_r);
ASSERT_EQ(a, b + expected_r);
@@ -421,8 +348,8 @@ static uint64 RandomUint64() {
TEST(Int128, DivideAndModRandomInputs) {
const int kNumIters = 1 << 18;
for (int i = 0; i < kNumIters; ++i) {
const uint128 a(RandomUint64(), RandomUint64());
const uint128 b(RandomUint64(), RandomUint64());
const uint128 a = MakeUint128(RandomUint64(), RandomUint64());
const uint128 b = MakeUint128(RandomUint64(), RandomUint64());
if (b == 0) {
continue; // Avoid a div-by-zero.
}
@@ -432,24 +359,18 @@ TEST(Int128, DivideAndModRandomInputs) {
}
}

#ifdef GOOGLE_PROTOBUF_HAS_CONSTEXPR
TEST(Int128, ConstexprTest) {
constexpr uint128 zero;
constexpr uint128 one = 1;
constexpr uint128_pod pod = {2, 3};
constexpr uint128 from_pod = pod;
constexpr uint128 minus_two = -2;
EXPECT_EQ(one, uint128(1));
EXPECT_EQ(from_pod, uint128(2, 3));
EXPECT_EQ(minus_two, uint128(-1ULL, -2ULL));
EXPECT_EQ(minus_two, MakeUint128(-1ULL, -2ULL));
}

TEST(Int128, Traits) {
EXPECT_TRUE(std::is_trivially_copy_constructible<uint128>::value);
EXPECT_TRUE(std::is_trivially_copy_assignable<uint128>::value);
EXPECT_TRUE(std::is_trivially_destructible<uint128>::value);
}
#endif // GOOGLE_PROTOBUF_HAS_CONSTEXPR

TEST(Int128, OStream) {
struct {
@@ -464,28 +385,28 @@ TEST(Int128, OStream) {
{uint128(0), std::ios::oct, 0, '_', "0"},
{uint128(0), std::ios::hex, 0, '_', "0"},
// crossover between lo_ and hi_
{uint128(0, -1), std::ios::dec, 0, '_', "18446744073709551615"},
{uint128(0, -1), std::ios::oct, 0, '_', "1777777777777777777777"},
{uint128(0, -1), std::ios::hex, 0, '_', "ffffffffffffffff"},
{uint128(1, 0), std::ios::dec, 0, '_', "18446744073709551616"},
{uint128(1, 0), std::ios::oct, 0, '_', "2000000000000000000000"},
{uint128(1, 0), std::ios::hex, 0, '_', "10000000000000000"},
{MakeUint128(0, -1), std::ios::dec, 0, '_', "18446744073709551615"},
{MakeUint128(0, -1), std::ios::oct, 0, '_', "1777777777777777777777"},
{MakeUint128(0, -1), std::ios::hex, 0, '_', "ffffffffffffffff"},
{MakeUint128(1, 0), std::ios::dec, 0, '_', "18446744073709551616"},
{MakeUint128(1, 0), std::ios::oct, 0, '_', "2000000000000000000000"},
{MakeUint128(1, 0), std::ios::hex, 0, '_', "10000000000000000"},
// just the top bit
{uint128(PROTOBUF_ULONGLONG(0x8000000000000000), 0), std::ios::dec, 0,
{MakeUint128(PROTOBUF_ULONGLONG(0x8000000000000000), 0), std::ios::dec, 0,
'_', "170141183460469231731687303715884105728"},
{uint128(PROTOBUF_ULONGLONG(0x8000000000000000), 0), std::ios::oct, 0,
{MakeUint128(PROTOBUF_ULONGLONG(0x8000000000000000), 0), std::ios::oct, 0,
'_', "2000000000000000000000000000000000000000000"},
{uint128(PROTOBUF_ULONGLONG(0x8000000000000000), 0), std::ios::hex, 0,
{MakeUint128(PROTOBUF_ULONGLONG(0x8000000000000000), 0), std::ios::hex, 0,
'_', "80000000000000000000000000000000"},
// maximum uint128 value
{uint128(-1, -1), std::ios::dec, 0, '_',
{MakeUint128(-1, -1), std::ios::dec, 0, '_',
"340282366920938463463374607431768211455"},
{uint128(-1, -1), std::ios::oct, 0, '_',
{MakeUint128(-1, -1), std::ios::oct, 0, '_',
"3777777777777777777777777777777777777777777"},
{uint128(-1, -1), std::ios::hex, 0, '_',
{MakeUint128(-1, -1), std::ios::hex, 0, '_',
"ffffffffffffffffffffffffffffffff"},
// uppercase
{uint128(-1, -1), std::ios::hex | std::ios::uppercase, 0, '_',
{MakeUint128(-1, -1), std::ios::hex | std::ios::uppercase, 0, '_',
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"},
// showbase
{uint128(1), std::ios::dec | std::ios::showbase, 0, '_', "1"},
2 changes: 1 addition & 1 deletion src/google/protobuf/stubs/logging.h
Original file line number Diff line number Diff line change
@@ -31,6 +31,7 @@
#ifndef GOOGLE_PROTOBUF_STUBS_LOGGING_H_
#define GOOGLE_PROTOBUF_STUBS_LOGGING_H_

#include <google/protobuf/stubs/int128.h>
#include <google/protobuf/stubs/macros.h>
#include <google/protobuf/stubs/port.h>
#include <google/protobuf/stubs/status.h>
@@ -65,7 +66,6 @@ enum LogLevel {
};

class StringPiece;
class uint128;
namespace internal {

class LogFinisher;