// Copyright 2023 Matt Borland // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt #include #ifdef BOOST_HAS_INT128 // We need to define these operator<< overloads before // including boost/core/lightweight_test.hpp, or they // won't be visible to BOOST_TEST_EQ // LCOV_EXCL_START #include static char* mini_to_chars( char (&buffer)[ 64 ], boost::uint128_type v ) { char* p = buffer + 64; *--p = '\0'; do { *--p = "0123456789"[ v % 10 ]; v /= 10; } while ( v != 0 ); return p; } std::ostream& operator<<( std::ostream& os, boost::uint128_type v ) { char buffer[ 64 ]; os << mini_to_chars( buffer, v ); return os; } std::ostream& operator<<( std::ostream& os, boost::int128_type v ) { char buffer[ 64 ]; char* p; if( v >= 0 ) { p = mini_to_chars( buffer, static_cast(v) ); } else { p = mini_to_chars( buffer, -static_cast(v) ); *--p = '-'; } os << p; return os; } // LCOV_EXCL_STOP #endif // #ifdef BOOST_HAS_INT128 #include #include #include #include #include #include using boost::charconv::detail::uint128; using boost::charconv::detail::trivial_uint128; template void test_relational_operators(T val = (std::numeric_limits::max)()) { uint128 test_val = UINT64_MAX; test_val += 1; BOOST_TEST(test_val > val); BOOST_TEST(!(test_val < val)); BOOST_TEST(!(test_val == val)); BOOST_TEST(test_val != val); const uint128 equal_val = val; BOOST_TEST(!(equal_val > val)); BOOST_TEST(equal_val >= val); BOOST_TEST(!(equal_val < val)); BOOST_TEST(equal_val <= val); BOOST_TEST(equal_val == val); BOOST_TEST(!(equal_val != val)); int negative_val = -100; BOOST_TEST(test_val > negative_val); BOOST_TEST(!(test_val < negative_val)); BOOST_TEST(!(test_val == negative_val)); BOOST_TEST(test_val != negative_val); } void test_arithmetic_operators() { // Only using low word const auto fixed_val = UINT64_MAX / 2; uint128 test_val = fixed_val; BOOST_TEST(test_val / 2 == UINT64_MAX / 4); BOOST_TEST(test_val + 1 == fixed_val + 1); test_val++; BOOST_TEST(test_val == fixed_val + 1); BOOST_TEST(test_val % fixed_val == 1); test_val--; BOOST_TEST(test_val == fixed_val); BOOST_TEST(test_val % fixed_val == 0); BOOST_TEST(test_val / fixed_val == 1); test_val = 2; std::uint64_t comp_val = 1; while (test_val < UINT64_MAX) { comp_val *= 2; if(!BOOST_TEST(test_val == comp_val)) { // LCOV_EXCL_START std::cerr << "Target: " << comp_val << "\ntest_val: " << test_val.low << std::endl; // LCOV_EXCL_STOP } test_val *= 2; } // And back down while (test_val >= 2) { test_val /= 2; if(!BOOST_TEST(test_val == comp_val)) { // LCOV_EXCL_START std::cerr << "Target: " << comp_val << "\ntest_val: " << test_val.low << std::endl; // LCOV_EXCL_STOP } comp_val /= 2; } // Add the high word uint128 test_high_word = UINT64_MAX; ++test_high_word; BOOST_TEST(test_high_word.high == 1 && test_high_word.low == 0); --test_high_word; #ifdef BOOST_CHARCONV_HAS_INT128 boost::uint128_type reference = UINT64_MAX; BOOST_TEST(test_high_word == reference); for (int i = 0; i < 63; ++i) { if(!BOOST_TEST(test_high_word == reference)) { // LCOV_EXCL_START std::cerr << "i: " << i << "\nTarget: " << reference << "\ntest_val: " << test_high_word.high << " " << test_high_word.low << std::endl; // // LCOV_EXCL_STOP } test_high_word *= 2; reference *= 2; } while (test_high_word >= 2) { BOOST_TEST(test_high_word == reference); test_high_word /= 2; reference /= 2; } #endif } void test_bitwise_operators() { #ifdef BOOST_CHARCONV_HAS_INT128 boost::uint128_type ref = UINT64_MAX; uint128 test_val = UINT64_MAX; ref <<= 1; test_val <<= 1; BOOST_TEST(test_val == ref); ref >>= 2; test_val >>= 2; BOOST_TEST(test_val == ref); BOOST_TEST((test_val | 1) == (ref | 1)); BOOST_TEST((test_val & 1) == (ref & 1)); BOOST_TEST(~test_val == ~ref); #endif } void test_memcpy() { #if defined(BOOST_CHARCONV_HAS_QUADMATH) && defined(BOOST_CHARCONV_HAS_INT128) __float128 fval = 1e4000Q; boost::uint128_type ref; trivial_uint128 cpyval; std::memcpy(&cpyval, &fval, sizeof(fval)); std::memcpy(&ref, &fval, sizeof(fval)); uint128 test_val = cpyval; BOOST_TEST(test_val == ref); #endif } void test_limits() { BOOST_TEST((std::numeric_limits::min)() == 0); BOOST_TEST((std::numeric_limits::max)() == uint128(UINT64_MAX, UINT64_MAX)); BOOST_TEST(std::numeric_limits::is_signed == false); BOOST_TEST(std::numeric_limits::is_integer == true); BOOST_TEST(std::numeric_limits::digits == CHAR_BIT * sizeof(std::uint64_t) * 2); // Max value is 340,282,366,920,938,463,463,374,607,431,768,211,455 (39 digits) so 38 without change BOOST_TEST(std::numeric_limits::digits10 == 38); } int main() { test_relational_operators(); test_relational_operators(); test_relational_operators(); test_relational_operators(); test_relational_operators(); test_relational_operators(); test_relational_operators(); test_relational_operators(); test_relational_operators(); test_relational_operators(); test_relational_operators(); test_arithmetic_operators(); test_bitwise_operators(); test_memcpy(); test_limits(); return boost::report_errors(); }