Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
19 changes: 19 additions & 0 deletions clickhouse/types/bignum.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@
#include <string>
#include <string_view>


#if defined(__SIZEOF_INT128__)
#define CH_CPP_HAS_INT128 1
#else
#define CH_CPP_HAS_INT128 0
#endif

/**
* This file contains declarations and definitions of the types and API used for wide
* (128-, 256- bit) integers. It first declares the Int128 and UInt128, implementation of which
Expand Down Expand Up @@ -66,6 +73,12 @@ struct UInt128 {
bool operator<=(const UInt128& other) const { return !(other < *this); }
bool operator>=(const UInt128& other) const { return !(*this < other); }

#if CH_CPP_HAS_INT128
explicit operator unsigned __int128() const {
return ((unsigned __int128)limbs[1] << 64 | limbs[0]);
}
#endif

// The value as two 64-bit limbs in little-endian order:
// `limbs[0]` is the low 64 bits and `limbs[1]` is the high 64 bits
uint64_t limbs[2];
Expand Down Expand Up @@ -104,6 +117,12 @@ struct Int128 {
bool operator<=(const Int128& other) const { return !(other < *this); }
bool operator>=(const Int128& other) const { return !(*this < other); }

#if CH_CPP_HAS_INT128
explicit operator __int128() const {
return (__int128)((unsigned __int128)limbs[1] << 64 | limbs[0]);
}
#endif

// The value as two 64-bit limbs in little-endian order:
// `limbs[0]` is the low 64 bits and `limbs[1]` is the high 64 bits
uint64_t limbs[2];
Expand Down
55 changes: 55 additions & 0 deletions ut/bignum_ut.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include <gtest/gtest.h>

#include <limits>
#include <vector>

using clickhouse::Bignum;
using clickhouse::Int128;
Expand Down Expand Up @@ -135,3 +136,57 @@ TEST(BignumCompare, Int128Limits) {
EXPECT_TRUE(min <= min);
EXPECT_TRUE(max >= max);
}

#if CH_CPP_HAS_INT128

using i128 = __int128;
using u128 = unsigned __int128;

constexpr u128 u128_max = ~u128{0};
constexpr i128 i128_max = static_cast<i128>(u128_max >> 1);
constexpr i128 i128_min = -i128_max - 1;

TEST(BignumCompare, Int128CastToNative) {

struct TestSample {
std::string str;
i128 expect;
};

std::vector<TestSample> samples {
{"0", 0},
{"-1", -1},
{"1", 1},
{"99999999999999999999999999999999999999", (i128)10000000000000000000UL * 10000000000000000000UL - 1},
{"-99999999999999999999999999999999999999", -(i128)10000000000000000000UL * 10000000000000000000UL + 1},
{"170141183460469231731687303715884105727", i128_max},
{"-170141183460469231731687303715884105728", i128_min},
};

for (size_t i = 0; i < samples.size(); ++i) {
auto x = Bignum::StringToInt128(samples[i].str);
EXPECT_TRUE(static_cast<i128>(x) == samples[i].expect);
}
}

TEST(BignumCompare, UInt128CastToNative) {

struct TestSample {
std::string str;
u128 expect;
};

std::vector<TestSample> samples {
{"0", 0},
{"1", 1},
{"99999999999999999999999999999999999999", (i128)10000000000000000000UL * 10000000000000000000UL - 1},
{"170141183460469231731687303715884105727", (u128)i128_max},
{"340282366920938463463374607431768211455", u128_max},
};

for (size_t i = 0; i < samples.size(); ++i) {
auto x = Bignum::StringToUInt128(samples[i].str);
EXPECT_TRUE(static_cast<u128>(x) == samples[i].expect);
}
}
#endif
Loading