oceanbase/unittest/sql/common/wide_integer/test_wide_integer.cpp
chaser-ch 566e920620 Merge branch 'column_store'
Co-authored-by: wangt1xiuyi <13547954130@163.com>
Co-authored-by: yangqise7en <877793735@qq.com>
Co-authored-by: Zach41 <zach_41@163.com>
2023-10-31 15:39:22 +00:00

1333 lines
49 KiB
C++

#define USING_LOG_PREFIX SQL
// #include "lib/wide_integer/ob_wide_integer.h"
#include "share/datum/ob_datum.h"
#include "common/object/ob_object.h"
#include "lib/alloc/alloc_struct.h"
#define private public
#include "lib/wide_integer/ob_wide_integer.h"
#undef private
#include "share/object/ob_obj_cast.h"
#include <gtest/gtest.h>
#include <string>
#include <iostream>
#include <vector>
#include <cstdlib>
#include <type_traits>
#include <utility>
#include <fstream>
#include <random>
#include <chrono>
#include <iterator>
#define CHECK_TOSTR(B) \
do { \
for (int i = 0; i < vals_##B.size(); i++) { \
char buf[256]; \
int64_t pos = 0; \
int ret = wide::to_string(vals_##B[i], buf, sizeof(buf), pos); \
ASSERT_EQ(ret, OB_SUCCESS); \
ASSERT_EQ(strs_##B[i], string(buf, pos)); \
} \
} while (0)
namespace oceanbase
{
namespace common
{
namespace wide
{
using namespace std;
struct MockAllocator: public ObIAllocator
{
void* alloc(const int64_t size) override
{
return malloc(size);
}
void* alloc(const int64_t num, const lib::ObMemAttr &attr) override {
return malloc(num);
}
void free(void *ptr) override {
std::free(ptr);
}
};
template<typename T>
T parse_string(std::string input, ObIAllocator &allocator)
{
ObDecimalInt *decint = nullptr;
int32_t int_bytes = 0;
int16_t scale, precision;
int ret =
wide::from_string(input.c_str(), input.size(), allocator, scale, precision, int_bytes, decint);
switch (int_bytes) {
case sizeof(int64_t):
return *(decint->int64_v_);
case sizeof(int32_t):
return *(decint->int32_v_);
case sizeof(int128_t): {
return *(decint->int128_v_);
}
case sizeof(int256_t): {
return *(decint->int256_v_);
}
case sizeof(int512_t): {
return *(decint->int512_v_);
}
default:
OB_ASSERT("abort");
}
return T();
}
template<>
int64_t parse_string<int64_t>(std::string input, ObIAllocator &allocator)
{
ObDecimalInt *decint = nullptr;
int32_t int_bytes = 0;
int16_t scale, precision;
int ret =
wide::from_string(input.c_str(), input.size(), allocator, scale, precision, int_bytes, decint);
if (int_bytes <= sizeof(int32_t)) {
return *(decint->int32_v_);
} else {
return *(decint->int64_v_);
}
}
bool is_equal_content(std::string lfile, std::string rfile)
{
std::ifstream lh(lfile);
std::ifstream rh(rfile);
EXPECT_TRUE(lh.is_open());
EXPECT_TRUE(rh.is_open());
std::istream_iterator<std::string> l_iter(lh);
std::istream_iterator<std::string> r_iter(rh);
return std::equal(l_iter, std::istream_iterator<std::string>(), r_iter);
}
template<typename T>
T rand_value(const T min_v, const T max_v)
{
return min_v;
}
template<>
int64_t rand_value<int64_t>(const int64_t min_v, const int64_t max_v)
{
std::random_device dev;
std::mt19937 rng(dev());
std::uniform_int_distribution<std::mt19937::result_type> dist(min_v, max_v);
return dist(rng);
}
class TestWideInteger
{
public:
void to_string()
{
vector<int128_t> vals_128 = {int128_t(-12345678),
int128_t(12345678),
Limits<int128_t>::max(),
Limits<int128_t>::min(),
int128_t{1,1}
};
vector<string> strs_128 = {"-12345678",
"12345678",
"170141183460469231731687303715884105727",
"-170141183460469231731687303715884105728",
"18446744073709551617"};
vector<int256_t> vals_256 = {int256_t(-123456789),
int256_t(123456789),
Limits<int256_t>::max(),
Limits<int256_t>::min(),
int256_t{1, 1, 2, 2},
int256_t{1, 2, 2, UINT64_MAX}};
vector<string> strs_256 = {"-123456789",
"123456789",
"57896044618658097711785492504343953926634992332820282019728792003956564819967",
"-57896044618658097711785492504343953926634992332820282019728792003956564819968",
"12554203470773361528352143580257209759149906847865315000321",
"-6277101735386680763155224689365789489138712741453078986751"};
vector<int512_t> vals_512 = {int512_t(-1234567890), int512_t(1234567890),
Limits<int512_t>::max(),
Limits<int512_t>::min()};
vector<string> strs_512 = {
"-1234567890", "1234567890",
"6703903964971298549787012499102923063739682910296196688861780721860882"
"0150367734884009371490834517138450159290932430254268769414059732849732"
"16824503042047",
"-670390396497129854978701249910292306373968291029619668886178072186088"
"2015036773488400937149083451713845015929093243025426876941405973284973"
"216824503042048"};
CHECK_TOSTR(128);
CHECK_TOSTR(256);
CHECK_TOSTR(512);
}
void op_addsub_without_overflow(){
int128_t a = 123456789;
int256_t b = UINT64_MAX;
int512_t c = UINT64_MAX;
vector<int128_t> vals_128 = {a + 1, a + UINT64_MAX, a - 1,
a - UINT64_MAX - UINT64_MAX};
vector<string> strs_128 = {
"123456790",
"18446744073833008404",
"123456788",
"-36893488147295646441"
};
vector<int256_t> vals_256 = {b + 1, b + a, b - 1, b - a, b + b};
vector<string> strs_256 = {"18446744073709551616", "18446744073833008404",
"18446744073709551614", "18446744073586094826",
"36893488147419103230"};
vector<int512_t> vals_512 = {c + 1, c + b, c + a, c + c};
vector<string> strs_512 = {
"18446744073709551616", "36893488147419103230", "18446744073833008404",
"36893488147419103230",
};
CHECK_TOSTR(128);
CHECK_TOSTR(256);
CHECK_TOSTR(512);
}
void op_mul_without_overflow()
{
int128_t a = 1234567890;
int256_t b = UINT64_MAX;
int512_t c = UINT64_MAX;
vector<int128_t> vals_128 = { a * 1234, a * UINT64_MAX, a * a, a * -1234, a * -a};
vector<string> strs_128 = {
"1523456776260",
"22773757908449605610176642350",
"1524157875019052100",
"-1523456776260",
"-1524157875019052100"};
vector<int256_t> vals_256 = { b * 123456789, b * b, b * a * a, b * b * -123456789, b * -1234};
vector<string> strs_256 = {
"2277375790844960561017664235",
"340282366920938463426481119284349108225",
"28115750248405442769487939873324141500",
"-42010168373378879561227296555971718856471989525",
"-22763282186957586692910"
};
vector<int512_t> vals_512 = {c * c, c * 1234, c * -1234, c * a, c * -a, c * b, c * -b};
vector<string> strs_512 = {
"340282366920938463426481119284349108225",
"22763282186957586692910",
"-22763282186957586692910",
"22773757908449605610176642350",
"-22773757908449605610176642350",
"340282366920938463426481119284349108225",
"-340282366920938463426481119284349108225"
};
CHECK_TOSTR(128);
CHECK_TOSTR(256);
CHECK_TOSTR(512);
}
void op_shift()
{
int128_t a = UINT64_MAX;
int256_t b = UINT64_MAX;
int512_t c = UINT64_MAX;
vector<int128_t> vals_128 = {
a >> 1, (a*12345678) >> 64, a >> 128, (-a) >> 2, a << 64, a << 128};
vector<string> strs_128 = {
"9223372036854775807",
"12345677",
"0",
"-4611686018427387904",
"-18446744073709551616",
"0"
};
vector<int256_t> vals_256 = {
b >> 1, (b * b * b * 12345678) >> 128, (b * b * b * b) >> 256, (-b * b) >> 16, b << 120, b << 256};
vector<string> strs_256 = {
"9223372036854775807",
"227737562482426389738478614",
"-1",
"-5192296858534827627967546375798785",
"24519928653854221732404324438620031064996018894657290240",
"0"
};
vector<int512_t> vals_512 = {
c >> 2, (c * c * c * c * c) >> 220, (c * c * c * c * c) >> 512,
(-c) >> 512, (-c * b * a) >> 123, c << 400, c << 512
};
vector<string> strs_512 = {
"4611686018427387903",
"1267650600228229401153105821696",
"0",
"-1",
"-590295810358705651617",
"47634102635436893176458235195661356573744321042001064524"
"278035900673152872968986946564609077560367837960487262708122405616220480360142602240",
"0"
};
CHECK_TOSTR(128);
CHECK_TOSTR(256);
CHECK_TOSTR(512);
}
void op_div_without_overflow()
{
int128_t a = UINT64_MAX;
int256_t b = UINT64_MAX;
int512_t c = UINT64_MAX;
vector<int128_t> vals_128 = {a/123, a%123, a/-123, a%-123, a/int128_t(123), a%(int128_t(123)),
a/int128_t(-123), a%int128_t(-123), -a/123, -a%123, -a/-123, -a%-123};
vector<string> strs_128 = {
"149973529054549200",
"15",
"-149973529054549200",
"15",
"149973529054549200",
"15",
"-149973529054549200",
"15",
"-149973529054549200",
"-15",
"149973529054549200",
"-15"
};
vector<int256_t> vals_256 = {
(b * b * b) / 1234567890123456789,
(b * b * b) % 1234567890123456789,
(b * b * b) / -1234567890123456789,
(b * b * b) % -1234567890123456789,
(b * b * b) / (a + a + 1234),
(b * b * b) % (a + a + 1234),
(b * b * b) / -(a + a + 1234),
(b * b * b) % -(a + a + 1234),
-(b * b * b) / -(a + a + 1234),
-(b * b * b) % -(a + a + 1234)
};
vector<string> strs_256 = {
"5084452451423283485316506379824074720926",
"526538308263466761",
"-5084452451423283485316506379824074720926",
"526538308263466761",
"170141183460469226022420012902778071229",
"18446744073474667119",
"-170141183460469226022420012902778071229",
"18446744073474667119",
"170141183460469226022420012902778071229",
"-18446744073474667119"
};
CHECK_TOSTR(128);
CHECK_TOSTR(256);
}
void op_addsub_overflow()
{
int128_t res_128;
int128_t a = UINT64_MAX;
int128_t max_128 = Limits<int128_t>::max();
int128_t min_128 = Limits<int128_t>::min();
int256_t res_256;
int256_t b = (int256_t(UINT64_MAX) << 64) + UINT64_MAX;
int256_t max_256 = Limits<int256_t>::max();
int256_t min_256 = Limits<int256_t>::min();
int512_t res_512;
int512_t c = int512_t(UINT64_MAX) << 447;
int512_t max_512 = Limits<int512_t>::max();
int512_t min_512 = Limits<int512_t>::min();
int ret = a.add<CheckOverFlow>((a<<63), res_128);
ASSERT_EQ(ret, OB_OPERATE_OVERFLOW);
ret = a.add<CheckOverFlow>(a, res_128);
ASSERT_EQ(ret, 0);
ret = max_128.add<CheckOverFlow>(max_128, res_128);
ASSERT_EQ(ret, OB_OPERATE_OVERFLOW);
ret = max_128.add<CheckOverFlow>(min_128, res_128);
ASSERT_EQ(ret, 0);
ret = min_128.sub<CheckOverFlow>(1, res_128);
ASSERT_EQ(ret, OB_OPERATE_OVERFLOW);
ret = min_128.sub<CheckOverFlow>(-1, res_128);
ASSERT_EQ(ret, 0);
ret = b.add<CheckOverFlow>(b << 127, res_256);
ASSERT_EQ(ret, OB_OPERATE_OVERFLOW);
ret = max_256.add<CheckOverFlow>(1, res_256);
ASSERT_EQ(ret, OB_OPERATE_OVERFLOW);
ret = b.add<CheckOverFlow>(123, res_256);
ASSERT_EQ(ret, 0);
ret = min_256.sub<CheckOverFlow>(1, res_256);
ASSERT_EQ(ret, OB_OPERATE_OVERFLOW);
ret = min_256.sub<CheckOverFlow>(-1, res_256);
ASSERT_EQ(ret, 0);
ret = c.add<CheckOverFlow>(c, res_512);
ASSERT_EQ(ret, OB_OPERATE_OVERFLOW);
ret = c.add<CheckOverFlow>(100, res_512);
ASSERT_EQ(ret, 0);
ret = max_512.add<CheckOverFlow>(1, res_512);
ASSERT_EQ(ret, OB_OPERATE_OVERFLOW);
ret = max_512.sub<CheckOverFlow>(1, res_512);
ASSERT_EQ(ret, 0);
ret = min_512.add<CheckOverFlow>(-1, res_512);
ASSERT_EQ(ret, OB_OPERATE_OVERFLOW);
ret = min_512.sub<CheckOverFlow>(1, res_512);
ASSERT_EQ(ret, OB_OPERATE_OVERFLOW);
ret = min_512.add<CheckOverFlow>(1, res_512);
ASSERT_EQ(ret, 0);
ret = max_512.sub<CheckOverFlow>(-1, res_512);
ASSERT_EQ(ret, OB_OPERATE_OVERFLOW);
}
void op_muldiv128_overflow()
{
int128_t res_128;
int128_t a;
a = int128_t(1) << 64;
int ret = a.multiply<CheckOverFlow>(UINT64_MAX, res_128);
ASSERT_EQ(ret, OB_OPERATE_OVERFLOW);
a = int128_t(1) << 65;
ret = a.multiply<CheckOverFlow>(UINT64_MAX, res_128);
ASSERT_EQ(ret, OB_OPERATE_OVERFLOW);
a = int128_t(1) << 64;
ret = a.multiply<CheckOverFlow>(int128_t(1)<<64, res_128);
ASSERT_EQ(ret, OB_OPERATE_OVERFLOW);
a = int128_t(2) << 64;
ret = a.multiply<CheckOverFlow>(int128_t(UINT64_MAX), res_128);
ASSERT_EQ(ret, OB_OPERATE_OVERFLOW);
a = int128_t(1) << 64;
ret = a.multiply<CheckOverFlow>(int128_t(UINT64_MAX), res_128);
ASSERT_EQ(ret, OB_OPERATE_OVERFLOW);
a = int128_t(1) << 64;
ret = a.multiply<CheckOverFlow>(1234, res_128);
ASSERT_EQ(ret, 0);
char buf[256];
int64_t pos = 0;
ret = wide::to_string(res_128, buf, sizeof(buf), pos);
ASSERT_EQ(ret, 0);
ASSERT_EQ("22763282186957586694144", string(buf, pos));
a = int128_t(1) << 64;
ret = a.multiply<CheckOverFlow>(int128_t(1234), res_128);
pos = 0;
ret = wide::to_string(res_128, buf, sizeof(buf), pos);
ASSERT_EQ(ret, OB_SUCCESS);
ASSERT_EQ("22763282186957586694144", string(buf, pos));
a = -(int128_t(1) << 64);
ret = a.multiply<CheckOverFlow>(UINT64_MAX, res_128);
ASSERT_EQ(ret, OB_OPERATE_OVERFLOW);
a = -(int128_t(1) << 64);
ret = a.multiply<CheckOverFlow>((1ULL<<63) + 1, res_128);
ASSERT_EQ(ret, OB_OPERATE_OVERFLOW);
a = -(int128_t(1) << 64);
ret = a.multiply<CheckOverFlow>(int128_t(UINT64_MAX) << 1,res_128);
ASSERT_EQ(ret, OB_OPERATE_OVERFLOW);
a = -(int128_t(2) << 64);
ret = a.multiply<CheckOverFlow>(int128_t(UINT64_MAX), res_128);
ASSERT_EQ(ret, OB_OPERATE_OVERFLOW);
a = -(int128_t(1) << 64);
ret = a.multiply<CheckOverFlow>(int128_t(UINT64_MAX), res_128);
ASSERT_EQ(ret, OB_OPERATE_OVERFLOW);
a = -(int128_t(1) << 64);
ret = a.multiply<CheckOverFlow>(1234, res_128);
ASSERT_EQ(ret, 0);
pos = 0;
ret = wide::to_string(res_128, buf, sizeof(buf), pos);
ASSERT_EQ(ret, OB_SUCCESS);
ASSERT_EQ("-22763282186957586694144", string(buf, pos));
a = -(int128_t(1) << 64);
ret = a.multiply<CheckOverFlow>(int128_t(1234), res_128);
ASSERT_EQ(ret, 0);
pos = 0;
ret = wide::to_string(res_128, buf, sizeof(buf), pos);
ASSERT_EQ(ret, 0);
ASSERT_EQ("-22763282186957586694144", string(buf, pos));
a = int128_t(1) << 64;
ret = a.divide<CheckOverFlow>(0, res_128);
ASSERT_EQ(ret, OB_OPERATE_OVERFLOW);
a = int128_t(1) << 64;
ret = a.divide<CheckOverFlow>(int128_t(0), res_128);
ASSERT_EQ(ret, OB_OPERATE_OVERFLOW);
a = Limits<int128_t>::min();
ret = a.divide<CheckOverFlow>(-1, res_128);
ASSERT_EQ(ret, OB_OPERATE_OVERFLOW);
a = Limits<int128_t>::min();
ret = a.divide<CheckOverFlow>(int128_t(-1), res_128);
ASSERT_EQ(ret, OB_OPERATE_OVERFLOW);
}
void op_muldiv256_overflow() {
#define chk_overflow(ops_str, lhs, rhs, expected_ret) \
do { \
int ret = (lhs).ops_str <CheckOverFlow>((rhs), res_256); \
ASSERT_EQ(ret, expected_ret); \
} while (0)
int256_t res_256;
chk_overflow(divide, Limits<int256_t>::min(), 0, OB_OPERATE_OVERFLOW);
chk_overflow(divide, Limits<int256_t>::min(), int128_t(0), OB_OPERATE_OVERFLOW);
chk_overflow(divide, Limits<int256_t>::min(), int256_t(0), OB_OPERATE_OVERFLOW);
chk_overflow(divide, Limits<int256_t>::min(), -1, OB_OPERATE_OVERFLOW);
chk_overflow(divide, Limits<int256_t>::max(), -1, 0);
chk_overflow(multiply, (int256_t(1) << 254), UINT64_MAX, OB_OPERATE_OVERFLOW);
chk_overflow(multiply, Limits<int256_t>::min(), -1, OB_OPERATE_OVERFLOW);
chk_overflow(multiply, Limits<int256_t>::max(), 2, OB_OPERATE_OVERFLOW);
chk_overflow(multiply, int256_t(1) << 254, -3, OB_OPERATE_OVERFLOW);
chk_overflow(multiply, (int256_t(1) << 254), int256_t(UINT64_MAX), OB_OPERATE_OVERFLOW);
chk_overflow(multiply, Limits<int256_t>::min(), int256_t(-1), OB_OPERATE_OVERFLOW);
chk_overflow(multiply, Limits<int256_t>::max(), int256_t(2), OB_OPERATE_OVERFLOW);
chk_overflow(multiply, int256_t(1) << 254, int256_t(-3), OB_OPERATE_OVERFLOW);
chk_overflow(multiply, int256_t(1) << 128, int256_t(3)<<50, 0);
#undef chk_overflow
}
void op_muldiv512_overflow() {
#define chk_overflow(ops_str, lhs, rhs, expected_ret) \
do { \
int ret = (lhs).ops_str<CheckOverFlow>((rhs), res_512); \
ASSERT_EQ(ret, expected_ret); \
} while (0)
int512_t res_512;
chk_overflow(divide, Limits<int512_t>::min(), 0, OB_OPERATE_OVERFLOW);
chk_overflow(divide, Limits<int512_t>::min(), int128_t(0), OB_OPERATE_OVERFLOW);
chk_overflow(divide, Limits<int512_t>::min(), int256_t(0), OB_OPERATE_OVERFLOW);
chk_overflow(divide, Limits<int512_t>::min(), -1, OB_OPERATE_OVERFLOW);
chk_overflow(divide, Limits<int512_t>::max(), -1, 0);
chk_overflow(multiply, (int512_t(1) << 510), UINT64_MAX, OB_OPERATE_OVERFLOW);
chk_overflow(multiply, Limits<int512_t>::min(), -1, OB_OPERATE_OVERFLOW);
chk_overflow(multiply, Limits<int512_t>::max(), 2, OB_OPERATE_OVERFLOW);
chk_overflow(multiply, int512_t(1) << 510, -3, OB_OPERATE_OVERFLOW);
chk_overflow(multiply, (int512_t(1) << 510), int256_t(UINT64_MAX), OB_OPERATE_OVERFLOW);
chk_overflow(multiply, Limits<int512_t>::min(), int256_t(-1), OB_OPERATE_OVERFLOW);
chk_overflow(multiply, Limits<int512_t>::max(), int256_t(2), OB_OPERATE_OVERFLOW);
chk_overflow(multiply, int512_t(1) << 510, int256_t(-3), OB_OPERATE_OVERFLOW);
chk_overflow(multiply, int512_t(1) << 256, int256_t(3)<<200, 0);
}
void test_helper_trait()
{
#define check_trait(trait, expected) \
do { \
bool ret = trait::value; \
ASSERT_EQ(expected, ret); \
} while (0)
check_trait(IsWideInteger<int32_t>, false);
check_trait(IsWideInteger<uint32_t>, false);
check_trait(IsWideInteger<int64_t>, false);
check_trait(IsWideInteger<uint64_t>, false);
check_trait(IsWideInteger<int128_t>, true);
check_trait(IsWideInteger<int256_t>, true);
check_trait(IsWideInteger<int512_t>, true);
check_trait(IsWideInteger<int1024_t>, true);
check_trait(IsIntegral<int32_t>, true);
check_trait(IsIntegral<uint32_t>, true);
check_trait(IsIntegral<int64_t>, true);
check_trait(IsIntegral<uint32_t>, true);
check_trait(IsIntegral<int128_t>, true);
check_trait(IsIntegral<int256_t>, true);
check_trait(IsIntegral<int512_t>, true);
check_trait(IsIntegral<float>, false);
check_trait(IsIntegral<double>, false);
check_trait(SignedConcept<int128_t>, true);
check_trait(SignedConcept<int256_t>, true);
check_trait(SignedConcept<int512_t>, true);
check_trait(SignedConcept<int32_t>, true);
check_trait(SignedConcept<int64_t>, true);
check_trait(SignedConcept<uint32_t>, false);
check_trait(SignedConcept<uint64_t>, false);
bool ret = std::is_same<PromotedInteger<int32_t>::type, int64_t>::value;
ASSERT_EQ(true, ret);
ret = std::is_same<PromotedInteger<int64_t>::type, int128_t>::value;
ASSERT_EQ(ret, true);
ret = std::is_same<PromotedInteger<int128_t>::type, int256_t>::value;
ASSERT_EQ(ret, true);
ret = std::is_same<PromotedInteger<int256_t>::type, int512_t>::value;
ASSERT_EQ(ret, true);
}
void op_cmp_objects()
{
std::vector<std::pair<int, int>> defined_cmp_tuple{
{4, 4}, {4, 8}, {4, 16}, {4, 32}, {4, 64},
{8, 4}, {8, 8}, {8, 16}, {8, 32}, {8, 64},
{16, 4}, {16, 8}, {16, 16}, {16, 32}, {16, 64},
{32, 4}, {32, 8}, {32, 16}, {32, 32}, {32, 64},
{64, 4}, {64, 8}, {64, 16}, {64, 32}, {64, 64},
};
for (int i = 0; i < defined_cmp_tuple.size(); i++) {
auto pair = defined_cmp_tuple[i];
auto cmp_fp = ObDecimalIntCmpSet::get_decint_decint_cmp_func(pair.first, pair.second);
ASSERT_TRUE(cmp_fp != nullptr);
}
// cmp int32
int128_t v1 = (int128_t(1) << 80) + UINT64_MAX;
int128_t v2 = (int128_t(1) << 80) + INT64_MAX;
ObObj lhs_obj, rhs_obj;
lhs_obj.set_decimal_int(sizeof(int128_t), 0, (ObDecimalInt *)(&v1));
rhs_obj.set_decimal_int(sizeof(int128_t), 0, (ObDecimalInt *)(&v2));
int cmp_res = 0;
int ret = wide::compare(lhs_obj, rhs_obj, cmp_res);
ASSERT_EQ(ret, 0);
ASSERT_EQ(cmp_res, 1);
}
void op_addsub_diff_results()
{
std::ifstream int128_result("wide_integer_int128_add.result");
ASSERT_TRUE(int128_result.is_open());
MockAllocator allocator;
while(!int128_result.eof()) {
std::string lhs_str, rhs_str, result_str;
int128_result >> lhs_str >> rhs_str >> result_str;
int128_t lhs = parse_string<int128_t>(lhs_str, allocator);
int128_t rhs = parse_string<int128_t>(rhs_str, allocator);
int128_t expected = parse_string<int128_t>(result_str, allocator);
int128_t result = lhs + rhs;
if (result != expected) {
std::cout << lhs_str << ' ' << rhs_str << ' ' << result_str << '\n';
}
ASSERT_EQ(expected, result);
}
int128_result.close();
std::ifstream int256_int128_result("wide_integer_int256_int128_add.result");
ASSERT_TRUE(int256_int128_result.is_open());
while(!int256_int128_result.eof()) {
std::string lhs_str, rhs_str, result_str;
int256_int128_result >> lhs_str >> rhs_str >> result_str;
int256_t lhs = parse_string<int256_t>(lhs_str, allocator);
int128_t rhs = parse_string<int128_t>(rhs_str, allocator);
int256_t expected = lhs + rhs;
int256_t result = lhs + rhs;
if (result != expected) {
std::cout << lhs_str << ' ' << rhs_str << ' ' << result_str << '\n';
}
ASSERT_EQ(expected, result);
}
}
void op_mul_diff_results()
{
// int128 * int64
std::ifstream int128_int64_result("wide_integer_int128_int64_mul.result");
ASSERT_TRUE(int128_int64_result.is_open());
MockAllocator allocator;
while (!int128_int64_result.eof()) {
std::string lhs_str, rhs_str, result_str, overflow;
int128_int64_result >> lhs_str >> rhs_str >> result_str >> overflow;
int128_t lhs = parse_string<int128_t>(lhs_str, allocator);
int64_t rhs = parse_string<int64_t>(rhs_str, allocator);
int128_t result;
int ret = lhs.multiply<CheckOverFlow>(rhs, result);
if (overflow == "overflow") {
if (ret != OB_OPERATE_OVERFLOW) {
std::cout << lhs_str << ' ' << rhs_str << ' ' << result_str << '\n';
}
ASSERT_EQ(ret, OB_OPERATE_OVERFLOW);
} else {
int128_t expected = parse_string<int128_t>(result_str, allocator);
if (expected != result) {
std::cout << lhs_str << ' ' << rhs_str << ' ' << result_str << '\n';
}
ASSERT_EQ(ret, 0);
ASSERT_EQ(result, expected);
}
}
int128_int64_result.close();
// int128 * int128
std::ifstream int128_int128_result("wide_integer_int128_int128_mul.result");
ASSERT_TRUE(int128_int128_result.is_open());
while(!int128_int128_result.eof()) {
std::string lhs_str, rhs_str, result_str, overflow;
int128_int128_result >> lhs_str >> rhs_str >> result_str >> overflow;
int128_t lhs = parse_string<int128_t>(lhs_str, allocator);
int128_t rhs = parse_string<int128_t>(rhs_str, allocator);
int128_t result;
int ret = lhs.multiply<CheckOverFlow>(rhs, result);
if (overflow == "overflow") {
if (ret != OB_OPERATE_OVERFLOW) {
std::cout << lhs_str << ' ' << rhs_str << ' ' << result_str << '\n';
}
ASSERT_EQ(ret, OB_OPERATE_OVERFLOW);
} else {
ASSERT_EQ(ret, 0);
int128_t expected = parse_string<int128_t>(result_str, allocator);
if (expected != result) {
std::cout << lhs_str << ' ' << rhs_str << ' ' << result_str << '\n';
}
ASSERT_EQ(result, expected);
}
}
// int256 * int128
std::ifstream int256_int128_result("wide_integer_int256_int128_mul.result");
ASSERT_TRUE(int256_int128_result.is_open());
while (!int256_int128_result.eof()) {
std::string lhs_str, rhs_str, result_str, overflow;
int256_int128_result >> lhs_str >> rhs_str >> result_str >> overflow;
int256_t lhs = parse_string<int256_t>(lhs_str, allocator);
int128_t rhs = parse_string<int128_t>(rhs_str, allocator);
int256_t result;
int ret = lhs.multiply<CheckOverFlow>(rhs, result);
if (overflow == "overflow") {
if (ret != OB_OPERATE_OVERFLOW) {
std::cout << lhs_str << ' ' << rhs_str << ' ' << result_str << '\n';
}
ASSERT_EQ(ret, OB_OPERATE_OVERFLOW);
} else {
int256_t expected = parse_string<int256_t>(result_str, allocator);
if (expected != result || ret != 0) {
std::cout << lhs_str << ' ' << rhs_str << ' ' << result_str << '\n';
}
ASSERT_EQ(ret, 0);
ASSERT_EQ(result, expected);
}
}
}
void op_div_diff_results()
{
// int128/int64
std::ifstream int128_int64("wide_integer_int128_int64_div.result");
ASSERT_TRUE(int128_int64.is_open());
std::string lhs_str, rhs_str, result_str, rem_str;
MockAllocator allocator;
while (!int128_int64.eof()) {
int128_int64 >> lhs_str >> rhs_str >> result_str >> rem_str;
int128_t lhs = parse_string<int128_t>(lhs_str, allocator);
int64_t rhs = parse_string<int64_t>(rhs_str, allocator);
int128_t expected_quo = parse_string<int128_t>(result_str, allocator);
int128_t expected_rem = parse_string<int128_t>(rem_str, allocator);
int128_t result = lhs / rhs;
int128_t rem = lhs % rhs;
if (expected_quo != result || expected_rem != rem) {
std::cout << lhs_str << ' ' << rhs_str << ' ' << result_str << ' ' << rem_str << '\n';
}
ASSERT_EQ(result, expected_quo);
ASSERT_EQ(rem, expected_rem);
}
int128_int64.close();
// int128/int128
std::ifstream int128_int128("wide_integer_int128_int128_div.result");
ASSERT_TRUE(int128_int128.is_open());
while (!int128_int128.eof()) {
int128_int128 >> lhs_str >> rhs_str >> result_str >> rem_str;
int128_t lhs = parse_string<int128_t>(lhs_str, allocator);
int128_t rhs = parse_string<int128_t>(rhs_str, allocator);
int128_t expected_quo = parse_string<int128_t>(result_str, allocator);
int128_t expected_rem = parse_string<int128_t>(rem_str, allocator);
int128_t quo = lhs / rhs;
int128_t rem = lhs % rhs;
if (expected_quo != quo || expected_rem != rem) {
std::cout << lhs_str << ' ' << rhs_str << ' ' << result_str << ' ' << rem_str << '\n';
}
ASSERT_EQ(rem, expected_rem);
ASSERT_EQ(quo, expected_quo);
}
int128_int128.close();
// int256/int128
std::ifstream int256_int128("wide_integer_int256_int128_div.result");
ASSERT_TRUE(int256_int128.is_open());
while (!int256_int128.eof()) {
int256_int128 >> lhs_str >> rhs_str >> result_str >> rem_str;
int256_t lhs = parse_string<int256_t>(lhs_str, allocator);
int128_t rhs = parse_string<int128_t>(rhs_str, allocator);
int256_t expected_quo = parse_string<int256_t>(result_str, allocator);
int256_t expected_rem = parse_string<int256_t>(rem_str, allocator);
int256_t quo = lhs / rhs;
int256_t rem = lhs % rhs;
if (expected_quo != quo || expected_rem != rem) {
std::cout << lhs_str << ' ' << rhs_str << ' ' << result_str << ' ' << rem_str << '\n';
}
ASSERT_EQ(quo, expected_quo);
ASSERT_EQ(rem, expected_rem);
}
int256_int128.close();
}
void op_cmp_diff_results()
{
std::ifstream cmp_cases("wide_integer_cmp.result");
ASSERT_TRUE(cmp_cases.is_open());
std::string lhs_str, rhs_str, res_str;
ObDecimalInt *lhs_decint = nullptr, *rhs_decint = nullptr;
int32_t lhs_int_bytes, rhs_int_bytes;
int ret = 0;
int cmp_ret = 0;
std::string cmp_ret_str;
MockAllocator alloc;
int16_t scale, precision;
ObDecimalIntBuilder lhs_bld, rhs_bld;
while(!cmp_cases.eof()) {
cmp_cases >> lhs_str >> rhs_str >> res_str;
ret = wide::from_string(lhs_str.c_str(), lhs_str.size(), alloc, scale, precision, lhs_int_bytes, lhs_decint);
ASSERT_EQ(ret, 0);
ret = wide::from_string(rhs_str.c_str(), rhs_str.size(), alloc, scale, precision, rhs_int_bytes, rhs_decint);
ASSERT_EQ(ret, 0);
lhs_bld.from(lhs_decint, lhs_int_bytes);
rhs_bld.from(rhs_decint, rhs_int_bytes);
ret = wide::compare(lhs_bld, rhs_bld, cmp_ret);
ASSERT_EQ(ret, 0);
if (cmp_ret < 0) {
cmp_ret_str = "lt";
} else if (cmp_ret > 0) {
cmp_ret_str = "gt";
} else {
cmp_ret_str = "eq";
}
ASSERT_EQ(res_str, cmp_ret_str);
}
}
void op_from()
{
#define check_val_len(v, expected_len) \
do { \
decint = nullptr; \
val_len = 0; \
int ret = wide::from_integer(v, tmp_alloc, decint, val_len); \
ASSERT_EQ(ret, 0); \
ASSERT_EQ(val_len, expected_len); \
} while (0)
MockAllocator tmp_alloc;
ObDecimalInt *decint = nullptr;
int32_t val_len = 0;
int32_t v0 = 12, v1 = INT32_MAX;
uint32_t v2 = INT32_MAX, v3 = UINT32_MAX;
int64_t k0 = 12, k1 = INT64_MAX;
uint64_t k2 = INT64_MAX, k3 = UINT64_MAX;
check_val_len(v0, 4);
ASSERT_EQ(*reinterpret_cast<int32_t *>(decint), v0);
check_val_len(v1, 4);
ASSERT_EQ(*reinterpret_cast<int32_t *>(decint), v1);
check_val_len(v2, 4);
ASSERT_EQ(*reinterpret_cast<int32_t *>(decint), v2);
check_val_len(v3, 8);
ASSERT_EQ(*reinterpret_cast<int64_t *>(decint), v3);
check_val_len(k0, 8);
ASSERT_EQ(*reinterpret_cast<int64_t *>(decint), k0);
check_val_len(k1, 8);
ASSERT_EQ(*reinterpret_cast<int64_t *>(decint), k1);
check_val_len(k2, 8);
ASSERT_EQ(*reinterpret_cast<int64_t *>(decint), k2);
check_val_len(k3, 16);
int128_t expected_k3 = UINT64_MAX;
ASSERT_EQ(*reinterpret_cast<int128_t *>(decint), expected_k3);
std::string valstr = "0000123.123456";
int16_t scale, precision;
int32_t int_bytes;
ObDecimalInt *decint2;
int ret = wide::from_string(valstr.c_str(), valstr.size(), tmp_alloc, scale, precision, int_bytes, decint2);
ASSERT_EQ(ret, 0);
ASSERT_EQ(int_bytes, 8);
ASSERT_EQ(scale, 6);
ASSERT_EQ(precision, 13);
ASSERT_EQ(*(decint2->int32_v_), 123123456);
valstr = "000001231234.123456789123456789";
ret = wide::from_string(valstr.c_str(), valstr.size(), tmp_alloc, scale, precision, int_bytes, decint2);
ASSERT_EQ(ret, 0);
ASSERT_EQ(int_bytes, 16);
ASSERT_EQ(scale, 18);
ASSERT_EQ(precision, 30);
char buf[256] = {0};
int64_t length = 0;
ret = wide::to_string(decint2, int_bytes, scale, buf, sizeof(buf), length);
ASSERT_EQ(ret, 0);
ASSERT_EQ(std::string(buf, length), "1231234.123456789123456789");
}
void op_from_string()
{
std::ifstream cases("wide_integer_from_string.result");
std::string valstr, precsion_str, scale_str;
MockAllocator alloc;
ObDecimalInt *decint = nullptr;
int32_t int_bytes = 0;
int ret = 0;
int16_t scale = 0, precision = 0;
char buf[256] = {0};
int64_t length = 0;
while (!cases.eof()) {
cases >> valstr >> precsion_str >> scale_str;
int expected_precision = std::atoi(precsion_str.c_str());
int expected_scale = std::atoi(scale_str.c_str());
ret = wide::from_string(valstr.c_str(), valstr.size(), alloc, scale, precision, int_bytes,
decint);
if (ret != 0) {
number::ObNumber tmp_nmb;
int16_t tmp_prec, tmp_scale;
int tmp_ret = tmp_nmb.from_sci_opt(valstr.c_str(), valstr.size(), alloc, &tmp_prec, &tmp_prec);
if (tmp_ret != ret) {
std::cout << valstr << '\n';
}
ASSERT_EQ(tmp_ret, ret);
continue;
}
if (ret != 0) {
std::cout << valstr << '\n';
}
ASSERT_EQ(ret, 0);
if (precision != expected_precision) {
ASSERT_EQ(precision, scale + 1);
}
ASSERT_EQ(scale, expected_scale);
length = 0;
ret = wide::to_string(decint, int_bytes, scale, buf, sizeof(buf), length);
ASSERT_EQ(ret, 0);
ASSERT_EQ(std::string(buf, length), valstr);
}
}
void op_from_integer()
{
std::random_device dev;
std::mt19937 rng(dev());
std::uniform_int_distribution<int64_t> int_gen(INT64_MIN, INT64_MAX);
MockAllocator alloc;
ObDecimalInt *decint = nullptr;
int32_t int_bytes = 0;
for (int i = 0; i < 1000; i++) {
int64_t v = int_gen(rng);
int ret = wide::from_integer(v, alloc, decint, int_bytes);
ASSERT_EQ(ret, 0);
ASSERT_TRUE(int_bytes <= sizeof(int64_t));
if (int_bytes == sizeof(int32_t)) {
ASSERT_TRUE(*(decint->int32_v_) == v);
} else {
ASSERT_TRUE(*(decint->int64_v_) == v);
}
}
}
void op_from_number()
{
std::ifstream from_num_cases("wide_integer_from_number.result");
ASSERT_TRUE(from_num_cases.is_open());
MockAllocator allocator;
ObDecimalInt *decint = nullptr;
int32_t int_bytes = 0;
number::ObNumber nmb;
char buf[256] = {0};
int64_t length = 0;
std::string nmb_str;
int ret = 0;
while (!from_num_cases.eof()) {
from_num_cases >> nmb_str;
ret = nmb.from(nmb_str.c_str(), nmb_str.size(), allocator);
ASSERT_EQ(ret, 0);
ret = wide::from_number(nmb, allocator, nmb.get_scale(), decint, int_bytes);
ASSERT_EQ(ret, 0);
ret = wide::to_string(decint, int_bytes, nmb.get_scale(), buf, sizeof(buf), length);
ASSERT_EQ(ret, 0);
std::string nmb_fmt(nmb.format());
ASSERT_EQ(std::string(buf, length), nmb_fmt);
length = 0;
}
}
void op_to_number()
{
MockAllocator tmp_alloc;
int16_t scale = 0;
int16_t precision = 0;
int32_t int_bytes = 0;
int ret = 0;
ObDecimalInt *decint = nullptr;
std::string valstr;
std::ifstream cases("wide_integer_to_number.result");
ASSERT_TRUE(cases.is_open());
number::ObNumber nmb;
char data_buf[256] = {0};
int64_t length = 0;
while (!cases.eof()) {
cases >> valstr >> precision >> scale;
ret = wide::from_string(valstr.c_str(), valstr.size(), tmp_alloc, scale, precision, int_bytes,
decint);
ASSERT_EQ(ret, 0);
ret = wide::to_number(decint, int_bytes, scale, tmp_alloc, nmb);
if (ret != 0) {
std::cout << valstr << '\n';
std::cout << int_bytes << '\n';
}
ASSERT_EQ(ret, 0);
int ret = nmb.format_v1(data_buf, sizeof(data_buf), length, scale);
// std::string nmb_str(fmt_str);
if (ret != 0) {
std::cout << valstr << '\n';
}
ASSERT_EQ(ret, 0);
ASSERT_EQ(std::string(data_buf, length), valstr);
length = 0;
}
cases.close();
}
void perf_calc()
{
MockAllocator alloc;
std::vector<number::ObNumber> lhs_nmbs;
std::vector<number::ObNumber> rhs_nmbs;
number::ObNumber nmb0, nmb1, nmb2, nmb3;
number::ObNumber res;
int256_t res0;
int128_t res1;
nmb0.from("7266892579576111521134811142732427669749408813191128358981921690067753828", alloc);
nmb1.from("355676015188330345687923", alloc);
nmb2.from("5691091705679464", alloc);
nmb3.from("350113974", alloc);
int256_t l0, r0;
int128_t l1, r1;
l0 = parse_string<int256_t>(
std::string("7266892579576111521134811142732427669749408813191128358981921690067753828"),
alloc);
r0 = parse_string<int256_t>(
std::string("5691091705679464"),
alloc);
l1 = parse_string<int128_t>(std::string("355676015188330345687923"), alloc);
r1 = parse_string<int128_t>(std::string("350113974"), alloc);
int cnt = 100000000;
std::cout << "ObNumber Large Add Cost: ";
auto start = std::chrono::system_clock::now();
for (volatile int i = 0; i < cnt; i++) { nmb0.add(nmb2, res, alloc); }
auto end = std::chrono::system_clock::now();
std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count()
<< "ms\n";
std::cout << "ObNumber Medium Add Cost: ";
start = std::chrono::system_clock::now();
for (volatile int i = 0; i < cnt; i++) { nmb1.add(nmb3, res, alloc); }
end = std::chrono::system_clock::now();
std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count()
<< "ms\n";
std::cout << "ObNumber Large Multiply Cost: ";
start = std::chrono::system_clock::now();
for (volatile int i = 0; i < cnt; i++) { nmb0.mul(nmb2, res, alloc); }
end = std::chrono::system_clock::now();
std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count()
<< "ms\n";
std::cout << "ObNumber Medium Multiply Cost: ";
start = std::chrono::system_clock::now();
for (volatile int i = 0; i < cnt; i++) { nmb1.mul(nmb3, res, alloc); }
end = std::chrono::system_clock::now();
std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count()
<< "ms\n";
std::cout << "ObNumber Large Divide Cost: ";
start = std::chrono::system_clock::now();
for (volatile int i = 0; i < cnt; i++) { nmb0.div(nmb2, res, alloc); }
end = std::chrono::system_clock::now();
std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count()
<< "ms\n";
std::cout << "ObNumber Medium Divide Cost: ";
start = std::chrono::system_clock::now();
for (volatile int i = 0; i < cnt; i++) { nmb1.div(nmb3, res, alloc); }
end = std::chrono::system_clock::now();
std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count()
<< "ms\n";
std::cout << "ObWideInteger Large Add Cost: ";
start = std::chrono::system_clock::now();
for (volatile int i = 0; i < cnt; i++) {
l0.add<CheckOverFlow>(r0, res0);
}
end = std::chrono::system_clock::now();
std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count()
<< "ms\n";
std::cout << "ObWideInteger Medium Add Cost: ";
start = std::chrono::system_clock::now();
for (volatile int i = 0; i < cnt; i++) {
l1.add<CheckOverFlow>(r1, res1);
}
end = std::chrono::system_clock::now();
std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count()
<< "ms\n";
std::cout << "ObWideInteger Large Multiply Cost: ";
start = std::chrono::system_clock::now();
for (volatile int i = 0; i < cnt; i++) {
l0.multiply<CheckOverFlow>(r0, res0);
}
end = std::chrono::system_clock::now();
std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count()
<< "ms\n";
std::cout << "ObWideInteger Medium Multiply Cost: ";
start = std::chrono::system_clock::now();
for (volatile int i = 0; i < cnt; i++) {
l1.multiply<CheckOverFlow>(r1, res1);
}
end = std::chrono::system_clock::now();
std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count()
<< "ms\n";
std::cout << "ObWideInteger Large Divide Cost: ";
start = std::chrono::system_clock::now();
for (volatile int i = 0; i < cnt; i++) {
l0.divide<CheckOverFlow>(r0, res0);
}
end = std::chrono::system_clock::now();
std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count()
<< "ms\n";
std::cout << "ObWideInteger Medium Divide Cost: ";
start = std::chrono::system_clock::now();
for (volatile int i = 0; i < cnt; i++) { auto res = l1 / r1; }
end = std::chrono::system_clock::now();
std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count()
<< "ms\n";
}
// TODO: decimal int cmp unittest
void test_const_value()
{
MockAllocator alloc;
lib::ObMemAttr attr;
int ret = ObDecimalIntConstValue::init_const_values(alloc, attr);
ASSERT_EQ(ret, 0);
std::ofstream out("decimalint_const_val.out");
ASSERT_TRUE(out.is_open());
out << "======== MYSQL ========\n";
char buf[256] = {0};
int64_t length = 0;
for (int16_t precision = OB_MIN_DECIMAL_PRECISION; precision <= OB_MAX_DECIMAL_POSSIBLE_PRECISION; ++precision) {
for (int16_t scale = 0; precision >= scale && scale <= number::ObNumber::MAX_SCALE; ++scale) {
const ObDecimalInt *decint = ObDecimalIntConstValue::get_min_value(precision);
int32_t int_bytes = ObDecimalIntConstValue::get_int_bytes_by_precision(precision);
ret = wide::to_string(decint, int_bytes, scale, buf, sizeof(buf), length);
ASSERT_EQ(ret, 0);
// mysql_check_min
out << "MYSQL_MIN (" << precision << ", " << scale << "): " << std::string(buf, length) << '\n';
length = 0;
// mysql_check_max
decint = ObDecimalIntConstValue::get_max_value(precision);
ret = wide::to_string(decint, int_bytes, scale, buf, sizeof(buf), length);
ASSERT_EQ(ret, 0);
out << "MYSQL_MAX (" << precision << ", " << scale << "): " << std::string(buf, length) << '\n';
length = 0;
}
}
// oracle
out << "======== ORACLE ========\n";
for (int16_t precision = OB_MIN_NUMBER_PRECISION; precision <= OB_MAX_NUMBER_PRECISION; precision++) {
for (int16_t scale = number::ObNumber::MIN_SCALE; scale <= number::ObNumber::MAX_SCALE; scale++) {
int16_t delta_scale = ObDecimalIntConstValue::oracle_delta_scale(scale);
const ObDecimalInt *decint = ObDecimalIntConstValue::get_min_value(precision);
int32_t int_bytes = ObDecimalIntConstValue::get_int_bytes_by_precision(precision);
// oracle_min
ret = wide::to_string(decint, int_bytes, scale, buf, sizeof(buf), length);
ASSERT_EQ(ret, 0);
out << "ORACLE_MIN (" << precision << ", " << scale << "): " << std::string(buf, length) << '\n';
length = 0;
// oracle_max
decint = ObDecimalIntConstValue::get_max_value(precision);
ret = wide::to_string(decint, int_bytes, scale, buf, sizeof(buf), length);
ASSERT_EQ(ret, 0);
out << "ORACLE_MAX (" << precision << ", " << scale << "): " << std::string(buf, length) << '\n';
length = 0;
} // for end
} // for end
ASSERT_TRUE(is_equal_content("decimalint_const_val.out", "nmb_const_value.result"));
}
void test_oracle_to_string()
{
// TODO enrich test cases
const int128_t v0{3136633892082024446ULL,
5421010862427522ULL}; // 99999999999999999999999999999999998
const int128_t v1{12919594847110692862ULL,
54210108624275221ULL}; // 999999999999999999999999999999999998
const int256_t v2{4870020673419870206ULL,
16114848830623546549ULL,
293ULL,
0}; // 99999999999999999999999999999999999999998
const ObDecimalInt *decint0 = reinterpret_cast<const ObDecimalInt *>(&v0);
int32_t int_bytes0 = sizeof(int128_t);
int16_t scale0 = 44;
const ObDecimalInt *decint1 = reinterpret_cast<const ObDecimalInt *>(&v1);
int32_t int_bytes1 = sizeof(int128_t);
int16_t scale1 = 45;
const ObDecimalInt *decint2 = reinterpret_cast<const ObDecimalInt *>(&v2);
int32_t int_bytes2 = sizeof(int256_t);
int16_t scale2 = 0;
int16_t scale3 = 2;
char buf[256] = {0};
int64_t length = 0;
lib::set_compat_mode(lib::Worker::CompatMode::ORACLE);
int ret = wide::to_string(decint0, int_bytes0, scale0, buf, sizeof(buf), length, true);
ASSERT_EQ(ret, 0);
ASSERT_EQ(std::string(buf, length), "9.9999999999999999999999999999999998E-10");
length = 0;
ret = wide::to_string(decint1, int_bytes1, scale1, buf, sizeof(buf), length, true);
ASSERT_EQ(ret, 0);
ASSERT_EQ(std::string(buf, length), "1.00000000000000000000000000000000000E-9");
length = 0;
ret = wide::to_string(decint2, int_bytes2, scale2, buf, sizeof(buf), length, true);
ASSERT_EQ(ret, 0);
ASSERT_EQ(std::string(buf, length), "1.0000000000000000000000000000000000E+41");
length = 0;
ret = wide::to_string(decint2, int_bytes2, scale3, buf, sizeof(buf), length, true);
ASSERT_EQ(ret, 0);
ASSERT_EQ(std::string(buf, length), "1.0000000000000000000000000000000000E+39");
length = 0;
ObDecimalInt *parsed_decint = nullptr;
int32_t parsed_int_bytes = 0;
MockAllocator mock_alloc;
std::string parse_str0("-.00012345");
std::string parse_str1("-1.2345e-3");
std::string parse_str2("1.2345e+18");
int32_t expected_neg_val = -12345;
int32_t expected_pos_val = 12345;
int16_t parsed_scale = 0, parsed_precision = 0;
ret = wide::from_string(parse_str0.c_str(), parse_str0.size(), mock_alloc, parsed_scale,
parsed_precision, parsed_int_bytes, parsed_decint);
ASSERT_EQ(ret, 0);
ASSERT_EQ(parsed_int_bytes, 4);
ASSERT_EQ(parsed_scale, 8);
ASSERT_EQ(*(parsed_decint->int32_v_), expected_neg_val);
ret = wide::from_string(parse_str1.c_str(), parse_str1.size(), mock_alloc, parsed_scale, parsed_precision, parsed_int_bytes, parsed_decint);
ASSERT_EQ(ret, 0);
ASSERT_EQ(parsed_int_bytes, 4);
ASSERT_EQ(parsed_scale, 7);
ASSERT_EQ(*(parsed_decint->int32_v_), expected_neg_val);
ret = wide::from_string(parse_str2.c_str(), parse_str2.size(), mock_alloc, parsed_scale, parsed_precision, parsed_int_bytes, parsed_decint);
ASSERT_EQ(ret, 0);
ASSERT_EQ(parsed_int_bytes, 4);
ASSERT_EQ(parsed_scale, -14);
ASSERT_EQ(*(parsed_decint->int32_v_), expected_pos_val);
}
};
void test_small_decint_to_nmb()
{
const int64_t constexpr test_cases = 100000;
MockAllocator tmp_alloc;
number::ObNumber expect_nmb;
number::ObNumber res_nmb;
uint32_t digits[3] = {0};
int ret = 0;
int64_t rand_v_list[test_cases] = {0};
int64_t rand_s_list[test_cases] = {0};
for (int i = 0; i < test_cases; i++) {
rand_v_list[i] = rand_value<int64_t>(100000000, 99999999999999999);
rand_s_list[i] = rand_value<int64_t>(0, 100) % 10;
}
auto start = std::chrono::system_clock::now();
for (int i = 0; i < test_cases; i++) {
int ret = wide::to_number(rand_v_list[i], rand_s_list[i], tmp_alloc, expect_nmb);
ASSERT_EQ(ret, OB_SUCCESS);
ret = wide::to_number(rand_v_list[i], rand_s_list[i], (uint32_t *)digits, 3, res_nmb);
ASSERT_EQ(ret, OB_SUCCESS);
if (expect_nmb.compare(res_nmb) != 0) {
std::cout << "value: " << rand_v_list[i] << ", scale: " << rand_s_list[i] << '\n';
}
ASSERT_EQ(expect_nmb, res_nmb);
}
}
TEST(TestWideInteger, ALL) {
TestWideInteger test;
test.op_addsub_without_overflow();
test.op_mul_without_overflow();
test.op_div_without_overflow();
test.op_shift();
test.op_addsub_overflow();
test.op_muldiv128_overflow();
test.op_muldiv256_overflow();
test.op_muldiv512_overflow();
test.op_mul_diff_results();
test.op_cmp_objects();
test.op_addsub_diff_results();
test.to_string();
test.op_from_string();
test.op_from();
test.op_to_number();
test.test_helper_trait();
test.op_div_diff_results();
test.op_cmp_diff_results();
test.op_from_integer();
#ifndef DEBUG
// test.perf_calc();
#endif
test.op_from_number();
test.test_const_value();
test.test_oracle_to_string();
test_small_decint_to_nmb();
}
} // endnamespace wide
} // end namespace common
} // end namespace oceanbase
int main(int argc, char **argv)
{
testing::InitGoogleTest(&argc, argv);
system("rm -rf test_wide_integer.log");
OB_LOGGER.set_log_level("DEBUG");
OB_LOGGER.set_file_name("test_wide_integer.log", true);
return RUN_ALL_TESTS();
}