From 3f7b586ca2c54f2034b6e5b31b77c0fd53cc2c3c Mon Sep 17 00:00:00 2001 From: doyle Date: Sun, 12 Sep 2021 18:28:32 +1000 Subject: [PATCH] Initial commit --- .gitignore | 1 + README.md | 42 + build_tests.bat | 23 + intc.h | 2082 +++++++++++++++++++++++++++++++++++++++++++++++ intc_tests.h | 1950 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 4098 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 build_tests.bat create mode 100644 intc.h create mode 100644 intc_tests.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..378eac2 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +build diff --git a/README.md b/README.md new file mode 100644 index 0000000..150b10a --- /dev/null +++ b/README.md @@ -0,0 +1,42 @@ +# intc +A MIT licensed C/C++ uint128/256 type library, originally adapted from [calccrypto's uint128/256 library](https://github.com/calccrypto/uint256_t) turned into a primarily C first library and opt out C++ features when compiling in C++ mode. + +The overarching motivation of the library can be summed up as follows + +- Single header, drop in - no build configuration required. +- Minimal dependencies (only depends on stdbool.h when compiling in C). +- Zero allocations (in other libs typically when converting to strings). +- Ability to rename the API via the pre-processor for tighter integration into C code bases +- C++ features are optional and can be opt out via the pre-processor, i.e. operator overloading and constructors. + +## Usage +Include `intc.h` and defined `INTC_IMPLEMENTATION` in one and only one file to enable the implementation in that translation unit. + +```cpp +#define INTC_IMPLEMENTATION +#include "intc.h" +#include + +int main(int, char**) +{ +#if defined(__cplusplus) + intc_u256 value = 32; + value += 32; + if (value == 64) + value *= 1'000'000'000'000; + intc_u256_string string = intc_u256_readable_int_str(value); + printf("%.*s\n", string.size, string.str); // 64,000,000,000,000 +#else + intc_u256 value = INTC_U64_TO_U256(32); + value = intc_u256_add_u64(value, 32); + if (intc_u256_eq_u64(value, 64)) + value = intc_u256_mul(value, INTC_U64_TO_U256(1'000'000'000'000)); + intc_u256_string string = intc_u256_readable_int_str(value); + printf("%.*s\n", string.size, string.str); // 64,000,000,000,000 +#endif + return 0; +} +``` + +## Tests +Tests are adapted from calccrypto's test suite and can be built by running `build_tests.bat` for Windows and `build_tests.sh` for Unix. For Windows MSVC's cl compiler must be available on the path and GCC must be available on Unix. diff --git a/build_tests.bat b/build_tests.bat new file mode 100644 index 0000000..b398726 --- /dev/null +++ b/build_tests.bat @@ -0,0 +1,23 @@ +@echo off + +set script_dir=%~dp0 +if not exist build mkdir build + +where /q cl || ( + echo MSVC's cl compiler must be available on the path to build + goto :eof +) + +REM MSVC cl build +echo [SCRIPT] Building tests via cl to build\intc_tests_msvc.exe +pushd build +cl -nologo -O2 -D INTC_TESTS_WITH_MAIN -I %script_dir% -TP %script_dir%\intc_tests.h /Fe:intc_tests_msvc /link +popd build + +REM Optional clang-cl build if we have the compiler on the path +where /q clang-cl || goto :eof +echo [SCRIPT] Building tests via clang-cl to build\intc_tests_clang.exe +pushd build +clang-cl -nologo -O2 -D INTC_TESTS_WITH_MAIN -I %script_dir% -TP %script_dir%\intc_tests.h /Fe:intc_tests_clang /link +popd build + diff --git a/intc.h b/intc.h new file mode 100644 index 0000000..a0196aa --- /dev/null +++ b/intc.h @@ -0,0 +1,2082 @@ +#if !defined(INTC_H) +#define INTC_H +// ----------------------------------------------------------------------------- +// NOTE: Overview +// ----------------------------------------------------------------------------- +// calccrypto's uint128/256 C++ library converted into a single header file +// C/C++ library with some additional C-isms/cosmetic configurations. Some of +// the over-arching motivations of this library. +// +// - Single header, drop in - no build configuration required. +// - Minimal dependencies (only depends on stdbool.h when compiling in C). +// - Zero allocations (in other libs typically when converting to strings). +// - Ability to rename the API via the pre-processor for tighter integration +// into C code bases (See Configuration > INTC_API_PREFIX). +// - C++ features are optional and can be opt out via the pre-processor, i.e. +// operator overloading and constructors. +// (See Configuration > INTC_NO_CPP_FEATURES). +// +// ----------------------------------------------------------------------------- +// NOTE: License +// ----------------------------------------------------------------------------- +// +// MIT License +// Copyright (c) 2021 github.com/doy-lee +// Copyright (c) 2013 - 2017 Jason Lee @ calccrypto at gmail.com +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +// ----------------------------------------------------------------------------- +// NOTE: Configuration +// ----------------------------------------------------------------------------- +// #define INTC_IMPLEMENTATION +// Define this in one and only one C++ file to enable the implementation +// code of the header file +// +// #define INTC_ASSERT +// Define this macro to override the assert implementation in this file to +// a custom macro. If not overridden, when NDEBUG is defined- the assert is +// compiled out, otherwise a default assert macro is provided. +// +// #define INTC_NO_TYPEDEFS +// Define this macro to disable 'typedef struct intc_u128 intc_u128;' to +// force having to specify 'struct intc_u128' when declaring the integer +// types. Only relevant when compiling with a C compiler, otherwise ignored. +// +// #define INTC_NO_U256 +// Define this macro to disable the uint256 code in the library. +// +// #define INTC_STATIC_API +// Define this macro to prefix all functions with the static qualifier +// +// #define INTC_NO_CPP_FEATURES +// Define this macro to disable the C++ constructors and operator +// overloading in the library. When this library is compiled as a C library, +// this macro is ignored. When compiling the library in C++ with this macro, +// the functions in the library will be exported with 'extern "C"' defined +// (i.e. prevent name-mangling). +// +// #define INTC_API_PREFIX +// Define this macro to rename the 'intc_u' part of the functions in this +// library to your desired name via the pre-processor, i.e. +// +// #define INTC_API_PREFIX(expr) MyNamespace_u##expr +// intc_u128 value = MyNamespace_u128_add(INTC_U128(128, 128), INTC_U128(128, 128)); +// +// or +// +// #define INTC_API_PREFIX(expr) uint##expr +// intc_u128 value = uint128_add(INTC_U128(128, 128), INTC_U128(128, 128)); +// +// ----------------------------------------------------------------------------- +// NOTE: Examples +// ----------------------------------------------------------------------------- +/* + #define INTC_IMPLEMENTATION + #include "intc.h" + #include + + int main(int, char**) + { + #if defined(__cplusplus) + intc_u256 value = 32; + value += 32; + if (value == 64) + value *= 1'000'000'000'000; + intc_u256_string string = intc_u256_readable_int_str(value); + printf("%.*s\n", string.size, string.str); // 64,000,000,000,000 + #else + intc_u256 value = INTC_U64_TO_U256(32); + value = intc_u256_add_u64(value, 32); + if (intc_u256_eq_u64(value, 64)) + value = intc_u256_mul(value, INTC_U64_TO_U256(1'000'000'000'000)); + intc_u256_string string = intc_u256_readable_int_str(value); + printf("%.*s\n", string.size, string.str); // 64,000,000,000,000 + #endif + return 0; + } + + */ +// NOTE: INTC Macros +// ----------------------------------------------------------------------------- +#if !defined(INTC_ASSERT) + #if defined(NDEBUG) + #define INTC_ASSERT(expr) + #else + #define INTC_ASSERT(expr) \ + do \ + { \ + if (!(expr)) \ + { \ + (*(volatile int *)0) = 0; \ + } \ + } while (0) + #endif +#endif + +#if !defined(INTC_API_PREFIX) + #define INTC_API_PREFIX(expr) intc_u##expr +#endif + +#if !defined(INTC_API) + #if defined(INTC_STATIC_API) + #define INTC_API static + #else + #define INTC_API + #endif +#endif + +#if defined(__cplusplus) + #if defined(INTC_NO_CPP_FEATURES) + #define INTC_BEGIN_EXTERN_C extern "C" { + #define INTC_END_EXTERN_C } + #else + #define INTC_BEGIN_EXTERN_C + #define INTC_END_EXTERN_C + #endif + #define INTC_ZERO_INIT {} +#else + #define INTC_BEGIN_EXTERN_C + #define INTC_END_EXTERN_C + #define INTC_ZERO_INIT {0} + #include +#endif + +// ----------------------------------------------------------------------------- +// NOTE: Typedefs +// ----------------------------------------------------------------------------- +typedef unsigned char intc_u8; +typedef unsigned short intc_u16; +typedef unsigned int intc_u32; +typedef unsigned int intc_uint; +#ifdef _MSC_VER + typedef unsigned __int64 intc_u64; +#else + typedef unsigned long long intc_u64; +#endif + +// ----------------------------------------------------------------------------- +// NOTE: 128 Bit Unsigned Integer +// ----------------------------------------------------------------------------- +struct intc_u128 +{ +#if !defined(INTC_NO_CPP_FEATURES) + intc_u128() = default; + intc_u128(intc_u64 lo) : lo(lo), hi(0) {} + intc_u128(intc_u64 lo, intc_u64 hi) : lo(lo), hi(hi) {} +#endif // INTC_NO_CPP_FEATURES + + intc_u64 lo, hi; +}; + +struct intc_u128_divmod_result +{ + struct intc_u128 quot; + struct intc_u128 rem; +}; + +struct intc_u128_string +{ + // NOTE: Max value 340,282,366,920,938,463,463,374,607,431,768,211,455 + char str[256 + 1]; + int size; +}; + +// ----------------------------------------------------------------------------- +// NOTE: Constructors +// ----------------------------------------------------------------------------- +#if defined (__cplusplus) + #define INTC_U128(lo, hi) intc_u128{(lo), (hi)} + #define INTC_U128_MIN intc_u128{0, 0} + #define INTC_U128_MAX intc_u128{(intc_u64)-1, (intc_u64)-1} + #define INTC_U128_ZERO intc_u128{0, 0} + #define INTC_U64_TO_U128(u64) intc_u128{(u64), 0} +#else + #define INTC_U128(lo, hi) (struct intc_u128){(lo), (hi)} + #define INTC_U128_MIN (struct intc_u128){0, 0} + #define INTC_U128_MAX (struct intc_u128){(intc_u64)-1, (intc_u64)-1} + #define INTC_U128_ZERO (struct intc_u128){0, 0} + #define INTC_U64_TO_U128(u64) (struct intc_u128){(u64), 0} + + #if !defined(INTC_NO_TYPEDEFS) + typedef struct intc_u128 intc_u128; + typedef struct intc_u128_divmod_result intc_u128_divmod_result; + typedef struct intc_u128_string intc_u128_string; + #endif +#endif + +INTC_BEGIN_EXTERN_C +// ----------------------------------------------------------------------------- +// NOTE: U128 Converters +// ----------------------------------------------------------------------------- +// Reminder: If INTC_API_PREFIX is not defined, example API looks like: intc_u128_init_cstring(...) +// Construct a 128 unsigned integer from a string. This function supports +// hexadecimal strings with and without the 0x prefix and integer numbers, i.e. +// "0xafc8a" or "afc8a" or "0xAFC8A" or "xafc8a" or "720010" etc +INTC_API bool INTC_API_PREFIX(128_init_cstring)(const char *string, int size, struct intc_u128 *dest); + +// Interpret the 128 bit integer as a lower bit-type by using the lo bits of the +// integer and truncating where necessary. +INTC_API bool INTC_API_PREFIX(128_as_bool)(struct intc_u128 in); +INTC_API intc_u8 INTC_API_PREFIX(128_as_u8)(struct intc_u128 in); +INTC_API intc_u16 INTC_API_PREFIX(128_as_u16)(struct intc_u128 in); +INTC_API intc_u32 INTC_API_PREFIX(128_as_u32)(struct intc_u128 in); +INTC_API intc_u64 INTC_API_PREFIX(128_as_u64)(struct intc_u128 in); + +// ----------------------------------------------------------------------------- +// NOTE: U128 Bitwise +// ----------------------------------------------------------------------------- +// Reminder: If INTC_API_PREFIX is not defined, example API looks like: intc_u128_and(...) +INTC_API struct intc_u128 INTC_API_PREFIX(128_and)(struct intc_u128 lhs, struct intc_u128 rhs); +INTC_API struct intc_u128 INTC_API_PREFIX(128_or)(struct intc_u128 lhs, struct intc_u128 rhs); +INTC_API struct intc_u128 INTC_API_PREFIX(128_xor)(struct intc_u128 lhs, struct intc_u128 rhs); +INTC_API struct intc_u128 INTC_API_PREFIX(128_negate)(struct intc_u128 lhs); +INTC_API struct intc_u128 INTC_API_PREFIX(128_lshift)(struct intc_u128 lhs, unsigned rhs); +INTC_API struct intc_u128 INTC_API_PREFIX(128_rshift)(struct intc_u128 lhs, unsigned rhs); + +// ----------------------------------------------------------------------------- +// NOTE: U128 Equality +// ----------------------------------------------------------------------------- +// If INTC_API_PREFIX not defined then, for example: intc_u128_eq(...) +INTC_API bool INTC_API_PREFIX(128_eq)(struct intc_u128 lhs, struct intc_u128 rhs); +INTC_API bool INTC_API_PREFIX(128_neq)(struct intc_u128 lhs, struct intc_u128 rhs); + +// ----------------------------------------------------------------------------- +// NOTE: U128 Equality U64 Helpers +// ----------------------------------------------------------------------------- +INTC_API bool INTC_API_PREFIX(128_eq_u64)(struct intc_u128 lhs, intc_u64 rhs); +INTC_API bool INTC_API_PREFIX(128_neq_u64)(struct intc_u128 lhs, intc_u64 rhs); + +// ----------------------------------------------------------------------------- +// NOTE: U128 Relational +// ----------------------------------------------------------------------------- +// Reminder: If INTC_API_PREFIX is not defined, example API looks like: intc_u128_gt(...) +INTC_API bool INTC_API_PREFIX(128_gt)(struct intc_u128 lhs, struct intc_u128 rhs); +INTC_API bool INTC_API_PREFIX(128_lt)(struct intc_u128 lhs, struct intc_u128 rhs); +INTC_API bool INTC_API_PREFIX(128_gt_eq)(struct intc_u128 lhs, struct intc_u128 rhs); +INTC_API bool INTC_API_PREFIX(128_lt_eq)(struct intc_u128 lhs, struct intc_u128 rhs); + +// ----------------------------------------------------------------------------- +// NOTE: U128 Relational U64 Helpers +// ----------------------------------------------------------------------------- +// Reminder: If INTC_API_PREFIX is not defined, example API looks like: intc_u128_gt_u64(...) +INTC_API bool INTC_API_PREFIX(128_gt_u64)(struct intc_u128 lhs, intc_u64 rhs); +INTC_API bool INTC_API_PREFIX(128_lt_u64)(struct intc_u128 lhs, intc_u64 rhs); +INTC_API bool INTC_API_PREFIX(128_gt_eq_u64)(struct intc_u128 lhs, intc_u64 rhs); +INTC_API bool INTC_API_PREFIX(128_lt_eq_u64)(struct intc_u128 lhs, intc_u64 rhs); + +// ----------------------------------------------------------------------------- +// NOTE: U128 Arithmetic +// ----------------------------------------------------------------------------- +// Reminder: If INTC_API_PREFIX is not defined, example API looks like: intc_u128_add(...) +INTC_API struct intc_u128 INTC_API_PREFIX(128_add)(struct intc_u128 lhs, struct intc_u128 rhs); +INTC_API struct intc_u128 INTC_API_PREFIX(128_sub)(struct intc_u128 lhs, struct intc_u128 rhs); +INTC_API struct intc_u128 INTC_API_PREFIX(128_mul)(struct intc_u128 lhs, struct intc_u128 rhs); +INTC_API struct intc_u128_divmod_result INTC_API_PREFIX(128_divmod)(struct intc_u128 lhs, struct intc_u128 rhs); +INTC_API struct intc_u128 INTC_API_PREFIX(128_div)(struct intc_u128 lhs, struct intc_u128 rhs); +INTC_API struct intc_u128 INTC_API_PREFIX(128_mod)(struct intc_u128 lhs, struct intc_u128 rhs); + +// ----------------------------------------------------------------------------- +// NOTE: U128 Arithmetic U64 Helpers +// ----------------------------------------------------------------------------- +// Reminder: If INTC_API_PREFIX is not defined, example API looks like: intc_u128_add_u64(...) +INTC_API struct intc_u128 INTC_API_PREFIX(128_add_u64)(struct intc_u128 lhs, intc_u64 rhs); +INTC_API struct intc_u128 INTC_API_PREFIX(128_sub_u64)(struct intc_u128 lhs, intc_u64 rhs); +INTC_API struct intc_u128 INTC_API_PREFIX(128_mul_u64)(struct intc_u128 lhs, intc_u64 rhs); +INTC_API struct intc_u128_divmod_result INTC_API_PREFIX(128_divmod_u64)(struct intc_u128 lhs, intc_u64 rhs); +INTC_API struct intc_u128 INTC_API_PREFIX(128_div_u64)(struct intc_u128 lhs, intc_u64 rhs); +INTC_API struct intc_u128 INTC_API_PREFIX(128_mod_u64)(struct intc_u128 lhs, intc_u64 rhs); + +// ----------------------------------------------------------------------------- +// NOTE: U128 Misc +// ----------------------------------------------------------------------------- +// Reminder: If INTC_API_PREFIX is not defined, example API looks like: intc_u128_clz(...) +INTC_API int INTC_API_PREFIX(128_clz)(struct intc_u128 in); // CLZ (Count leading zeros) + +// ----------------------------------------------------------------------------- +// NOTE: U128 Printing +// ----------------------------------------------------------------------------- +// Reminder: If INTC_API_PREFIX is not defined, example API looks like: intc_u128_str(...) + +// TODO(dqn): Add API for letting user pass in a buffer and we write into it. + +// Convert the 128 bit unsigned integer into a string. +// base: The number system base to print the string as where base must be (2 < base < 36). +// seperate_every_n_chars: When > 0, the string will be separated by the 'seperate_ch' for every N +// characters specified in this parameter. +// seperate_ch: The character to use to separate the tring. If +// 'seperate_every_n_chars <= 0' then this parameter is ignored. +// return: The integer converted to a string, on failure, an empty string is +// returned. The string is always null-terminated. The string's size is not +// inclusive of the null-terminator. +INTC_API struct intc_u128_string INTC_API_PREFIX(128_str)(struct intc_u128 in, unsigned base, int separate_every_n_chars, char separate_ch); + +// Helper function that calls intc_u128_str with base 10 (i.e. human readable). +INTC_API struct intc_u128_string INTC_API_PREFIX(128_int_str)(struct intc_u128 in, int separate_every_n_chars, char separate_ch); + +// Helper function that calls intc_u128_str with base 10 (i.e. human readable), +// seperated by the thousands with a comma, i.e. 1,000. +INTC_API struct intc_u128_string INTC_API_PREFIX(128_readable_int_str)(struct intc_u128 in); + +// Helper function that calls intc_u128_str with base 16 (i.e. hex) +INTC_API struct intc_u128_string INTC_API_PREFIX(128_hex_str)(struct intc_u128 in, int separate_every_n_chars, char separate_ch); + +// Helper function that calls intc_u128_str with base 16 (i.e. hex), seperated +// every 4 hex characters with '_', i.e. ffff_ffff +INTC_API struct intc_u128_string INTC_API_PREFIX(128_readable_hex_str)(struct intc_u128 in); +INTC_END_EXTERN_C + +#if !defined(INTC_NO_CPP_FEATURES) +// ----------------------------------------------------------------------------- +// NOTE: U128 CPP Bitwise +// ----------------------------------------------------------------------------- +INTC_API intc_u128 operator&(intc_u128 lhs, intc_u128 rhs); +INTC_API intc_u128 operator|(intc_u128 lhs, intc_u128 rhs); +INTC_API intc_u128 operator^(intc_u128 lhs, intc_u128 rhs); +INTC_API intc_u128 operator~(intc_u128 lhs); +INTC_API intc_u128 operator<<(intc_u128 lhs, unsigned rhs); +INTC_API intc_u128 operator>>(intc_u128 lhs, unsigned rhs); + +// ----------------------------------------------------------------------------- +// NOTE: U128 CPP Equality +// ----------------------------------------------------------------------------- +INTC_API bool operator==(intc_u128 lhs, intc_u128 rhs); +INTC_API bool operator!=(intc_u128 lhs, intc_u128 rhs); + +// ----------------------------------------------------------------------------- +// NOTE: U128 CPP Relational +// ----------------------------------------------------------------------------- +INTC_API bool operator>(intc_u128 lhs, intc_u128 rhs); +INTC_API bool operator<(intc_u128 lhs, intc_u128 rhs); +INTC_API bool operator>=(intc_u128 lhs, intc_u128 rhs); +INTC_API bool operator<=(intc_u128 lhs, intc_u128 rhs); + +// ----------------------------------------------------------------------------- +// NOTE: U128 CPP Arithmetic +// ----------------------------------------------------------------------------- +INTC_API intc_u128 operator+(intc_u128 lhs, intc_u128 rhs); +INTC_API intc_u128 operator-(intc_u128 lhs, intc_u128 rhs); +INTC_API intc_u128 operator*(intc_u128 lhs, intc_u128 rhs); +INTC_API intc_u128 operator/(intc_u128 lhs, intc_u128 rhs); +INTC_API intc_u128 operator%(intc_u128 lhs, intc_u128 rhs); + +// ----------------------------------------------------------------------------- +// NOTE: U128 CPP Other +// ----------------------------------------------------------------------------- +INTC_API intc_u128 &operator&=(intc_u128 &lhs, intc_u128 rhs); +INTC_API intc_u128 &operator|=(intc_u128 &lhs, intc_u128 rhs); +INTC_API intc_u128 &operator^=(intc_u128 &lhs, intc_u128 rhs); +INTC_API intc_u128 &operator<<=(intc_u128 &lhs, unsigned rhs); +INTC_API intc_u128 &operator>>=(intc_u128 &lhs, unsigned rhs); + +INTC_API intc_u128 &operator+=(intc_u128 &lhs, intc_u128 rhs); +INTC_API intc_u128 &operator-=(intc_u128 &lhs, intc_u128 rhs); +INTC_API intc_u128 &operator*=(intc_u128 &lhs, intc_u128 rhs); +INTC_API intc_u128 &operator/=(intc_u128 &lhs, intc_u128 rhs); +INTC_API intc_u128 &operator%=(intc_u128 &lhs, intc_u128 rhs); + +INTC_API intc_u128 &operator++(intc_u128 &lhs); +INTC_API intc_u128 &operator--(intc_u128 &lhs); +INTC_API intc_u128 operator++(intc_u128 &lhs, int); +INTC_API intc_u128 operator--(intc_u128 &lhs, int); +#endif // !defined(INTC_NO_CPP_FEATURES) + +// ----------------------------------------------------------------------------- +// NOTE: 256 Bit Unsigned Integer +// ----------------------------------------------------------------------------- +#if !defined(INTC_NO_U256) +struct intc_u256 +{ +#if !defined(INTC_NO_CPP_FEATURES) + intc_u256() = default; + intc_u256(intc_u64 lo_u64) { *this = {}; lo.lo = lo_u64; } + intc_u256(intc_u128 lo) { *this = {}; lo = lo; } + intc_u256(intc_u128 lo, intc_u128 hi) : lo(lo), hi(hi) {} +#endif // INTC_NO_CPP_FEATURES + + struct intc_u128 lo, hi; +}; + +struct intc_u256_divmod_result +{ + struct intc_u256 quot; + struct intc_u256 rem; +}; + +struct intc_u256_string +{ + // NOTE: Max value 115,792,089,237,316,195,423,570,985,008,687,907,853,269,984,665,640,564,039,457,584,007,913,129,639,935 + char str[512 + 1]; + int size; +}; + +// ----------------------------------------------------------------------------- +// NOTE: U256 Constructors +// ----------------------------------------------------------------------------- +#if defined(__cplusplus) + #define INTC_U256(lo, hi) intc_u256{lo, hi} + #define INTC_U256_MIN intc_u256{INTC_U128_MIN, INTC_U128_MIN} + #define INTC_U256_MAX intc_u256{INTC_U128_MAX, INTC_U128_MAX} + #define INTC_U256_ZERO intc_u256{INTC_U128_ZERO, INTC_U128_ZERO} + + #define INTC_U64_TO_U256(u64) intc_u256{INTC_U64_TO_U128(u64), INTC_U128_ZERO} + #define INTC_U128_TO_U256(u128) intc_u256{(u128), 0} +#else + #define INTC_U256(lo, hi) (struct intc_u256){(lo), (hi)} + #define INTC_U256_MIN (struct intc_u256){INTC_U128_MIN, INTC_U128_MIN} + #define INTC_U256_MAX (struct intc_u256){INTC_U128_MAX, INTC_U128_MAX} + #define INTC_U256_ZERO (struct intc_u256){INTC_U128_ZERO, INTC_U128_ZERO} + + #define INTC_U64_TO_U256(u64) (struct intc_u256){INTC_U64_TO_U128(u64), INTC_U128_ZERO} + #define INTC_U128_TO_U256(u128) (struct intc_u256){(u128), 0} + + #if !defined(INTC_NO_TYPEDEFS) + typedef struct intc_u256 intc_u256; + typedef struct intc_u256_divmod_result intc_u256_divmod_result; + typedef struct intc_u256_string intc_u256_string; + #endif +#endif + +INTC_BEGIN_EXTERN_C +// ----------------------------------------------------------------------------- +// NOTE: U256 Converters +// ----------------------------------------------------------------------------- +// Reminder: If INTC_API_PREFIX is not defined, example API looks like: intc_u256_init_cstring(...) +// Construct a 128 unsigned integer from a string. This function supports +// hexadecimal strings with and without the 0x prefix and integer numbers, i.e. +// "0xafc8a" or "afc8a" or "0xAFC8A" or "xafc8a" or "720010" etc +INTC_API bool INTC_API_PREFIX(256_init_cstring)(char const *string, int size, struct intc_u256 *dest); + +// TODO(dqn): We should support all the bases that the printing functions work +// with so you can always do a round-trip store and load from disk. +// Similar to above except the base of the number can be specified, base must be +// between (2 < base < 17). +INTC_API bool INTC_API_PREFIX(256_init_cstring_base)(char const *string, int size, int base, struct intc_u256 *dest); + +// Interpret the 256 bit integer as a lower bit-type by using the lo bits of the +// integer and truncating where necessary. +INTC_API bool INTC_API_PREFIX(256_as_bool)(struct intc_u256 in); +INTC_API intc_u8 INTC_API_PREFIX(256_as_u8)(struct intc_u256 in); +INTC_API intc_u16 INTC_API_PREFIX(256_as_u16)(struct intc_u256 in); +INTC_API intc_u32 INTC_API_PREFIX(256_as_u32)(struct intc_u256 in); +INTC_API intc_u64 INTC_API_PREFIX(256_as_u64)(struct intc_u256 in); +INTC_API struct intc_u128 INTC_API_PREFIX(256_as_u128)(struct intc_u256 in); + +// ----------------------------------------------------------------------------- +// NOTE: U256 Bitwise +// ----------------------------------------------------------------------------- +// Reminder: If INTC_API_PREFIX is not defined, example API looks like: intc_u256_and(...) +INTC_API struct intc_u256 INTC_API_PREFIX(256_and)(struct intc_u256 lhs, struct intc_u256 rhs); +INTC_API struct intc_u256 INTC_API_PREFIX(256_or)(struct intc_u256 lhs, struct intc_u256 rhs); +INTC_API struct intc_u256 INTC_API_PREFIX(256_xor)(struct intc_u256 lhs, struct intc_u256 rhs); + +INTC_API struct intc_u256 INTC_API_PREFIX(256_and_u128)(struct intc_u256 lhs, struct intc_u128 rhs); +INTC_API struct intc_u256 INTC_API_PREFIX(256_or_u128)(struct intc_u256 lhs, struct intc_u128 rhs); +INTC_API struct intc_u256 INTC_API_PREFIX(256_xor_u128)(struct intc_u256 lhs, struct intc_u128 rhs); + +INTC_API struct intc_u256 INTC_API_PREFIX(256_negate)(struct intc_u256 lhs); +INTC_API struct intc_u256 INTC_API_PREFIX(256_lshift)(struct intc_u256 lhs, unsigned shift); +INTC_API struct intc_u256 INTC_API_PREFIX(256_rshift)(struct intc_u256 lhs, unsigned shift); + +// ----------------------------------------------------------------------------- +// NOTE: U256 Equality +// ----------------------------------------------------------------------------- +// Reminder: If INTC_API_PREFIX is not defined, example API looks like: intc_u256_eq(...) +INTC_API bool INTC_API_PREFIX(256_eq)(struct intc_u256 lhs, struct intc_u256 rhs); +INTC_API bool INTC_API_PREFIX(256_neq)(struct intc_u256 lhs, struct intc_u256 rhs); + +// ----------------------------------------------------------------------------- +// NOTE: U256 Equality U64 Helpers +// ----------------------------------------------------------------------------- +// Reminder: If INTC_API_PREFIX is not defined, example API looks like: intc_u256_eq_u64(...) +INTC_API bool INTC_API_PREFIX(256_eq_u64)(struct intc_u256 lhs, intc_u64 rhs); +INTC_API bool INTC_API_PREFIX(256_neq_u64)(struct intc_u256 lhs, intc_u64 rhs); + +// ----------------------------------------------------------------------------- +// NOTE: U256 Relational +// ----------------------------------------------------------------------------- +// Reminder: If INTC_API_PREFIX is not defined, example API looks like: intc_u256_gt(...) +INTC_API bool INTC_API_PREFIX(256_gt)(struct intc_u256 lhs, struct intc_u256 rhs); +INTC_API bool INTC_API_PREFIX(256_lt)(struct intc_u256 lhs, struct intc_u256 rhs); +INTC_API bool INTC_API_PREFIX(256_gt_eq)(struct intc_u256 lhs, struct intc_u256 rhs); +INTC_API bool INTC_API_PREFIX(256_lt_eq)(struct intc_u256 lhs, struct intc_u256 rhs); + +// ----------------------------------------------------------------------------- +// NOTE: U256 Relational U64 Helpers +// ----------------------------------------------------------------------------- +// Reminder: If INTC_API_PREFIX is not defined, example API looks like: intc_u256_gt_u64(...) +INTC_API bool INTC_API_PREFIX(256_gt_u64)(struct intc_u256 lhs, intc_u64 rhs); +INTC_API bool INTC_API_PREFIX(256_lt_u64)(struct intc_u256 lhs, intc_u64 rhs); +INTC_API bool INTC_API_PREFIX(256_gt_eq_u64)(struct intc_u256 lhs, intc_u64 rhs); +INTC_API bool INTC_API_PREFIX(256_lt_eq_u64)(struct intc_u256 lhs, intc_u64 rhs); + +// ----------------------------------------------------------------------------- +// NOTE: U256 Arithmetic +// ----------------------------------------------------------------------------- +// Reminder: If INTC_API_PREFIX is not defined, example API looks like: intc_u256_add(...) +INTC_API struct intc_u256 INTC_API_PREFIX(256_add)(struct intc_u256 lhs, struct intc_u256 rhs); +INTC_API struct intc_u256 INTC_API_PREFIX(256_sub)(struct intc_u256 lhs, struct intc_u256 rhs); +INTC_API struct intc_u256 INTC_API_PREFIX(256_mul)(struct intc_u256 lhs, struct intc_u256 rhs); +INTC_API struct intc_u256_divmod_result INTC_API_PREFIX(256_divmod)(struct intc_u256 lhs, struct intc_u256 rhs); +INTC_API struct intc_u256 INTC_API_PREFIX(256_div)(struct intc_u256 lhs, struct intc_u256 rhs); +INTC_API struct intc_u256 INTC_API_PREFIX(256_mod)(struct intc_u256 lhs, struct intc_u256 rhs); + +INTC_API struct intc_u256 INTC_API_PREFIX(256_add_u64)(struct intc_u256 lhs, intc_u64 rhs); +INTC_API struct intc_u256 INTC_API_PREFIX(256_sub_u64)(struct intc_u256 lhs, intc_u64 rhs); +INTC_API struct intc_u256 INTC_API_PREFIX(256_mul_u64)(struct intc_u256 lhs, intc_u64 rhs); +INTC_API struct intc_u256_divmod_result INTC_API_PREFIX(256_divmod_u64)(struct intc_u256 lhs, intc_u64 rhs); +INTC_API struct intc_u256 INTC_API_PREFIX(256_div_u64)(struct intc_u256 lhs, intc_u64 rhs); +INTC_API struct intc_u256 INTC_API_PREFIX(256_mod_u64)(struct intc_u256 lhs, intc_u64 rhs); + +// ----------------------------------------------------------------------------- +// NOTE: U256 Misc +// ----------------------------------------------------------------------------- +// Reminder: If INTC_API_PREFIX is not defined, example API looks like: intc_u256_clz(...) +INTC_API int INTC_API_PREFIX(256_clz)(struct intc_u256 in); + +// ----------------------------------------------------------------------------- +// NOTE: U256 Printing +// ----------------------------------------------------------------------------- +// Reminder: If INTC_API_PREFIX is not defined, example API looks like: intc_u256_str(...) +// Convert the 256 bit unsigned integer into a string. +// base: The number system base to print the string as where base must be (2 < base < 36). +// seperate_every_n_chars: When > 0, the string will be separated by the 'seperate_ch' for every N +// characters specified in this parameter. +// seperate_ch: The character to use to separate the tring. If +// 'seperate_every_n_chars <= 0' then this parameter is ignored. +// return: The integer converted to a string, on failure, an empty string is +// returned. The string is always null-terminated. The string's size is not +// inclusive of the null-terminator. +INTC_API struct intc_u256_string INTC_API_PREFIX(256_str)(struct intc_u256 in, unsigned base, int separate_every_n_chars, char separate_ch); + +// Helper function that calls intc_u256_str with base 10 (i.e. human readable). +INTC_API struct intc_u256_string INTC_API_PREFIX(256_int_str)(struct intc_u256 in, int separate_every_n_chars, char separate_ch); + +// Helper function that calls intc_u256_str with base 10 (i.e. human readable), +// seperated by the thousands with a comma, i.e. 1,000. +INTC_API struct intc_u256_string INTC_API_PREFIX(256_readable_int_str)(struct intc_u256 in); + +// Helper function that calls intc_u256_str with base 16 (i.e. hex) +INTC_API struct intc_u256_string INTC_API_PREFIX(256_hex_str)(struct intc_u256 in, int separate_every_n_chars, char separate_ch); + +// Helper function that calls intc_u256_str with base 16 (i.e. hex), seperated +// every 4 hex characters with '_', i.e. ffff_ffff +INTC_API struct intc_u256_string INTC_API_PREFIX(256_readable_hex_str)(struct intc_u256 in); +INTC_END_EXTERN_C + +#if !defined(INTC_NO_CPP_FEATURES) +// ----------------------------------------------------------------------------- +// NOTE: U256 CPP Bitwise +// ----------------------------------------------------------------------------- +INTC_API intc_u256 operator&(intc_u256 lhs, intc_u256 rhs); +INTC_API intc_u256 operator|(intc_u256 lhs, intc_u256 rhs); +INTC_API intc_u256 operator^(intc_u256 lhs, intc_u256 rhs); +INTC_API intc_u256 operator~(intc_u256 lhs); +INTC_API intc_u256 operator<<(intc_u256 lhs, unsigned rhs); +INTC_API intc_u256 operator>>(intc_u256 lhs, unsigned rhs); + +// ----------------------------------------------------------------------------- +// NOTE: U256 CPP Equality +// ----------------------------------------------------------------------------- +INTC_API bool operator==(intc_u256 lhs, intc_u256 rhs); +INTC_API bool operator!=(intc_u256 lhs, intc_u256 rhs); + +// ----------------------------------------------------------------------------- +// NOTE: U256 CPP Relational +// ----------------------------------------------------------------------------- +INTC_API bool operator>(intc_u256 lhs, intc_u256 rhs); +INTC_API bool operator<(intc_u256 lhs, intc_u256 rhs); +INTC_API bool operator>=(intc_u256 lhs, intc_u256 rhs); +INTC_API bool operator<=(intc_u256 lhs, intc_u256 rhs); + +// ----------------------------------------------------------------------------- +// NOTE: U256 CPP Arithmetic +// ----------------------------------------------------------------------------- +INTC_API intc_u256 operator+(intc_u256 lhs, intc_u256 rhs); +INTC_API intc_u256 operator-(intc_u256 lhs, intc_u256 rhs); +INTC_API intc_u256 operator*(intc_u256 lhs, intc_u256 rhs); +INTC_API intc_u256 operator/(intc_u256 lhs, intc_u256 rhs); +INTC_API intc_u256 operator%(intc_u256 lhs, intc_u256 rhs); + +// ----------------------------------------------------------------------------- +// NOTE: U256 CPP Other +// ----------------------------------------------------------------------------- +INTC_API intc_u256 &operator&=(intc_u256 &lhs, intc_u256 rhs); +INTC_API intc_u256 &operator|=(intc_u256 &lhs, intc_u256 rhs); +INTC_API intc_u256 &operator^=(intc_u256 &lhs, intc_u256 rhs); +INTC_API intc_u256 &operator<<=(intc_u256 &lhs, unsigned rhs); +INTC_API intc_u256 &operator>>=(intc_u256 &lhs, unsigned rhs); + +INTC_API intc_u256 &operator+=(intc_u256 &lhs, intc_u256 rhs); +INTC_API intc_u256 &operator-=(intc_u256 &lhs, intc_u256 rhs); +INTC_API intc_u256 &operator*=(intc_u256 &lhs, intc_u256 rhs); +INTC_API intc_u256 &operator/=(intc_u256 &lhs, intc_u256 rhs); +INTC_API intc_u256 &operator%=(intc_u256 &lhs, intc_u256 rhs); + +INTC_API intc_u256 &operator++(intc_u256 &lhs); +INTC_API intc_u256 &operator--(intc_u256 &lhs); +INTC_API intc_u256 operator++(intc_u256 &lhs, int); +INTC_API intc_u256 operator--(intc_u256 &lhs, int); +#endif // !defined(INTC_NO_CPP_FEATURES) +#endif // !defined(INTC_NO_U256) +#endif // INTC_H + +#if defined(INTC_IMPLEMENTATION) +static bool const INTC__U8_IS_8_BITS [sizeof(intc_u8) == 1 ? 1 : -1] = {}; +static bool const INTC__U16_IS_16_BITS[sizeof(intc_u16) == 2 ? 1 : -1] = {}; +static bool const INTC__U32_IS_32_BITS[sizeof(intc_u32) == 4 ? 1 : -1] = {}; +static bool const INTC__U64_IS_64_BITS[sizeof(intc_u64) == 8 ? 1 : -1] = {}; + +INTC_BEGIN_EXTERN_C +// ----------------------------------------------------------------------------- +// NOTE: 128 Bit Unsigned Integer +// ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- +// NOTE: U128 Converters +// ----------------------------------------------------------------------------- +INTC_API bool INTC_API_PREFIX(128_init_cstring)(char const *string, int size, struct intc_u128 *dest) +{ + if (string == 0 || size == 0 || !dest) + return false; + + if (size < 0) + { + for (size = 0; string[size]; size++) + ; + } + + if (size >= 2 && string[1] == 'x') { string += 2; size -= 2; } + else if (size >= 1 && string[0] == 'x') { string += 1; size -= 1; } + + *dest = INTC_U128_ZERO; + + for (int index = 0; index < size; index++) + { + int bits_written = (index * 4); + if (bits_written >= (sizeof(*dest) * 8)) + return true; + + char hex_ch = string[index]; + unsigned char bits4 = (hex_ch >= '0' && hex_ch <= '9') ? 0 + (hex_ch - '0') + : (hex_ch >= 'a' && hex_ch <= 'f') ? 10 + (hex_ch - 'a') + : (hex_ch >= 'A' && hex_ch <= 'F') ? 10 + (hex_ch - 'A') + : 0xFF; + + if (bits4 == 0xFF) + return false; + + intc_u64 *word = (bits_written >= (sizeof(dest->lo) * 8)) ? &dest->lo : &dest->hi; + *word = (*word << 4) | bits4; + } + + return true; +} + +INTC_API bool INTC_API_PREFIX(128_as_bool)(struct intc_u128 in) +{ + bool result = in.lo | in.hi; + return result; +} + +INTC_API intc_u8 INTC_API_PREFIX(128_as_u8)(struct intc_u128 in) +{ + intc_u8 result = (intc_u8)in.lo; + return result; +} + +INTC_API intc_u16 INTC_API_PREFIX(128_as_u16)(struct intc_u128 in) +{ + intc_u16 result = (intc_u16)in.lo; + return result; +} + +INTC_API intc_u32 INTC_API_PREFIX(128_as_u32)(struct intc_u128 in) +{ + intc_u32 result = (intc_u32)in.lo; + return result; +} + +INTC_API intc_u64 INTC_API_PREFIX(128_as_u64)(struct intc_u128 in) +{ + intc_u64 result = (intc_u64)in.lo; + return result; +} + +// ----------------------------------------------------------------------------- +// NOTE: U128 Bitwise +// ----------------------------------------------------------------------------- +INTC_API struct intc_u128 INTC_API_PREFIX(128_and)(struct intc_u128 lhs, struct intc_u128 rhs) +{ + struct intc_u128 result = INTC_U128(lhs.lo & rhs.lo, lhs.hi & rhs.hi); + return result; +} + +INTC_API struct intc_u128 INTC_API_PREFIX(128_or)(struct intc_u128 lhs, struct intc_u128 rhs) +{ + struct intc_u128 result = INTC_U128(lhs.lo | rhs.lo, lhs.hi | rhs.hi); + return result; +} + +INTC_API struct intc_u128 INTC_API_PREFIX(128_xor)(struct intc_u128 lhs, struct intc_u128 rhs) +{ + struct intc_u128 result = INTC_U128(lhs.lo ^ rhs.lo, lhs.hi ^ rhs.hi); + return result; +} + +INTC_API struct intc_u128 INTC_API_PREFIX(128_negate)(struct intc_u128 lhs) +{ + struct intc_u128 result = INTC_U128(~lhs.lo, ~lhs.hi); + return result; +} + +INTC_API struct intc_u128 INTC_API_PREFIX(128_lshift)(struct intc_u128 lhs, unsigned shift) +{ + if ((shift >= 128)) + return INTC_U128_ZERO; + + if (shift == 64) + return INTC_U128(0, lhs.lo); + + if (shift == 0) + return lhs; + + if (shift < 64) + return INTC_U128(lhs.lo << shift, (lhs.hi << shift) + (lhs.lo >> (64 - shift))); + + if ((128 > shift) && (shift > 64)) + return INTC_U128(0, lhs.lo << (shift - 64)); + + return INTC_U128_ZERO; +} + +INTC_API struct intc_u128 INTC_API_PREFIX(128_rshift)(struct intc_u128 lhs, unsigned shift) +{ + if ((shift >= 128)) + return INTC_U128_ZERO; + + if (shift == 64) + return INTC_U128(lhs.hi, 0); + + if (shift == 0) + return lhs; + + if (shift < 64) + return INTC_U128((lhs.hi << (64 - shift)) + (lhs.lo >> shift), lhs.hi >> shift); + + if ((128 > shift) && (shift > 64)) + return INTC_U128((lhs.hi >> (shift - 64)), 0); + + return INTC_U128_ZERO; +} + +// ----------------------------------------------------------------------------- +// NOTE: U128 Equality +// ----------------------------------------------------------------------------- +INTC_API bool INTC_API_PREFIX(128_eq)(struct intc_u128 lhs, struct intc_u128 rhs) +{ + bool result = ((lhs.lo == rhs.lo) && (lhs.hi == rhs.hi)); + return result; +} + +INTC_API bool INTC_API_PREFIX(128_neq)(struct intc_u128 lhs, struct intc_u128 rhs) +{ + bool result = ((lhs.lo != rhs.lo) | (lhs.hi != rhs.hi)); + return result; +} + +// ----------------------------------------------------------------------------- +// NOTE: U128 Equality U64 Helpers +// ----------------------------------------------------------------------------- +INTC_API bool INTC_API_PREFIX(128_eq_u64)(struct intc_u128 lhs, intc_u64 rhs) +{ + bool result = INTC_API_PREFIX(128_eq)(lhs, INTC_U64_TO_U128(rhs)); + return result; +} + +INTC_API bool INTC_API_PREFIX(128_neq_u64)(struct intc_u128 lhs, intc_u64 rhs) +{ + bool result = INTC_API_PREFIX(128_neq)(lhs, INTC_U64_TO_U128(rhs)); + return result; +} + +// ----------------------------------------------------------------------------- +// NOTE: U128 Relational +// ----------------------------------------------------------------------------- +INTC_API bool INTC_API_PREFIX(128_gt)(struct intc_u128 lhs, struct intc_u128 rhs) +{ + bool result = (lhs.hi == rhs.hi) ? (lhs.lo > rhs.lo) : (lhs.hi > rhs.hi); + return result; +} + +INTC_API bool INTC_API_PREFIX(128_lt)(struct intc_u128 lhs, struct intc_u128 rhs) +{ + bool result = (lhs.hi == rhs.hi) ? (lhs.lo < rhs.lo) : (lhs.hi < rhs.hi); + return result; +} + +INTC_API bool INTC_API_PREFIX(128_gt_eq)(struct intc_u128 lhs, struct intc_u128 rhs) +{ + bool result = (lhs.hi == rhs.hi) ? (lhs.lo >= rhs.lo) : (lhs.hi >= rhs.hi); + return result; +} + +INTC_API bool INTC_API_PREFIX(128_lt_eq)(struct intc_u128 lhs, struct intc_u128 rhs) +{ + bool result = (lhs.hi == rhs.hi) ? (lhs.lo <= rhs.lo) : (lhs.hi <= rhs.hi); + return result; +} + +// ----------------------------------------------------------------------------- +// NOTE: U128 Relational U64 Helpers +// ----------------------------------------------------------------------------- +INTC_API bool INTC_API_PREFIX(128_gt_u64)(struct intc_u128 lhs, intc_u64 rhs) +{ + bool result = INTC_API_PREFIX(128_gt)(lhs, INTC_U64_TO_U128(rhs)); + return result; +} + +INTC_API bool INTC_API_PREFIX(128_lt_u64)(struct intc_u128 lhs, intc_u64 rhs) +{ + bool result = INTC_API_PREFIX(128_lt)(lhs, INTC_U64_TO_U128(rhs)); + return result; +} + +INTC_API bool INTC_API_PREFIX(128_gt_eq_u64)(struct intc_u128 lhs, intc_u64 rhs) +{ + bool resugt_eq = INTC_API_PREFIX(128_gt_eq)(lhs, INTC_U64_TO_U128(rhs)); + return resugt_eq; +} + +INTC_API bool INTC_API_PREFIX(128_lt_eq_u64)(struct intc_u128 lhs, intc_u64 rhs) +{ + bool result_eq = INTC_API_PREFIX(128_lt_eq)(lhs, INTC_U64_TO_U128(rhs)); + return result_eq; +} + +// ----------------------------------------------------------------------------- +// NOTE: U128 Arithmetic +// ----------------------------------------------------------------------------- +INTC_API struct intc_u128 INTC_API_PREFIX(128_add)(struct intc_u128 lhs, struct intc_u128 rhs) +{ + struct intc_u128 result = INTC_U128(lhs.lo + rhs.lo, lhs.hi + rhs.hi + ((lhs.lo + rhs.lo) < lhs.lo)); + return result; +} + +INTC_API struct intc_u128 INTC_API_PREFIX(128_sub)(struct intc_u128 lhs, struct intc_u128 rhs) +{ + struct intc_u128 result = INTC_U128(lhs.lo - rhs.lo, lhs.hi - rhs.hi - ((lhs.lo - rhs.lo) > lhs.lo)); + return result; +} + +INTC_API struct intc_u128 INTC_API_PREFIX(128_mul)(struct intc_u128 lhs, struct intc_u128 rhs) +{ + // split values into 4 32-bit parts + intc_u64 top[4] = {lhs.hi >> 32, lhs.hi & 0xffffffff, lhs.lo >> 32, lhs.lo & 0xffffffff}; + intc_u64 bottom[4] = {rhs.hi >> 32, rhs.hi & 0xffffffff, rhs.lo >> 32, rhs.lo & 0xffffffff}; + intc_u64 products[4][4]; + + // multiply each component of the values + for(int y = 3; y > -1; y--){ + for(int x = 3; x > -1; x--){ + products[3 - x][y] = top[x] * bottom[y]; + } + } + + // first row + intc_u64 fourth32 = (products[0][3] & 0xffffffff); + intc_u64 third32 = (products[0][2] & 0xffffffff) + (products[0][3] >> 32); + intc_u64 second32 = (products[0][1] & 0xffffffff) + (products[0][2] >> 32); + intc_u64 first32 = (products[0][0] & 0xffffffff) + (products[0][1] >> 32); + + // second row + third32 += (products[1][3] & 0xffffffff); + second32 += (products[1][2] & 0xffffffff) + (products[1][3] >> 32); + first32 += (products[1][1] & 0xffffffff) + (products[1][2] >> 32); + + // third row + second32 += (products[2][3] & 0xffffffff); + first32 += (products[2][2] & 0xffffffff) + (products[2][3] >> 32); + + // fourth row + first32 += (products[3][3] & 0xffffffff); + + // move carry to next digit + third32 += fourth32 >> 32; + second32 += third32 >> 32; + first32 += second32 >> 32; + + // remove carry from current digit + fourth32 &= 0xffffffff; + third32 &= 0xffffffff; + second32 &= 0xffffffff; + first32 &= 0xffffffff; + + // combine components + struct intc_u128 result = INTC_U128((third32 << 32) | fourth32, (first32 << 32) | second32); + return result; +} + +INTC_API struct intc_u128_divmod_result INTC_API_PREFIX(128_divmod)(struct intc_u128 lhs, struct intc_u128 rhs) +{ + // Save some calculations ///////////////////// + struct intc_u128_divmod_result result = INTC_ZERO_INIT; + + if (INTC_API_PREFIX(128_eq)(rhs, INTC_U128_ZERO)) + { + INTC_ASSERT(0 && "Division by zero"); + return result; + } + + if (INTC_API_PREFIX(128_eq)(rhs, INTC_U64_TO_U128(1))) + { + result.quot = lhs; + return result; + } + + if (INTC_API_PREFIX(128_eq)(lhs, rhs)) + { + result.quot = INTC_U64_TO_U128(1); + return result; + } + + if (INTC_API_PREFIX(128_eq)(lhs, INTC_U128_ZERO) || INTC_API_PREFIX(128_lt)(lhs, rhs)) + { + result.rem = lhs; + return result; + } + + int count = INTC_API_PREFIX(128_clz)(lhs); + for (int x = count; x > 0; x--) + { + result.quot = INTC_API_PREFIX(128_lshift)(result.quot, 1); + result.rem = INTC_API_PREFIX(128_lshift)(result.rem, 1); + + if (INTC_API_PREFIX(128_rshift)(lhs, x - 1U).lo & 1) + result.rem = INTC_API_PREFIX(128_add)(result.rem, INTC_U64_TO_U128(1)); + + if (INTC_API_PREFIX(128_gt_eq)(result.rem, rhs)) + { + result.rem = INTC_API_PREFIX(128_sub)(result.rem, rhs); + result.quot = INTC_API_PREFIX(128_add)(result.quot, INTC_U64_TO_U128(1)); + } + } + + return result; +} + +INTC_API struct intc_u128 INTC_API_PREFIX(128_div)(struct intc_u128 lhs, struct intc_u128 rhs) +{ + struct intc_u128 result = INTC_API_PREFIX(128_divmod)(lhs, rhs).quot; + return result; +} + +INTC_API struct intc_u128 INTC_API_PREFIX(128_mod)(struct intc_u128 lhs, struct intc_u128 rhs) +{ + struct intc_u128 result = INTC_API_PREFIX(128_divmod)(lhs, rhs).rem; + return result; +} + +// ----------------------------------------------------------------------------- +// NOTE: U128 Arithmetic U64 Helpers +// ----------------------------------------------------------------------------- +INTC_API struct intc_u128 INTC_API_PREFIX(128_add_u64)(struct intc_u128 lhs, intc_u64 rhs) +{ + struct intc_u128 result = INTC_API_PREFIX(128_add)(lhs, INTC_U64_TO_U128(rhs)); + return result; +} + +INTC_API struct intc_u128 INTC_API_PREFIX(128_sub_u64)(struct intc_u128 lhs, intc_u64 rhs) +{ + struct intc_u128 result = INTC_API_PREFIX(128_sub)(lhs, INTC_U64_TO_U128(rhs)); + return result; +} + +INTC_API struct intc_u128 INTC_API_PREFIX(128_mul_u64)(struct intc_u128 lhs, intc_u64 rhs) +{ + struct intc_u128 result = INTC_API_PREFIX(128_mul)(lhs, INTC_U64_TO_U128(rhs)); + return result; +} + +INTC_API struct intc_u128_divmod_result INTC_API_PREFIX(128_divmod_u64)(struct intc_u128 lhs, intc_u64 rhs) +{ + struct intc_u128_divmod_result result = INTC_API_PREFIX(128_divmod)(lhs, INTC_U64_TO_U128(rhs)); + return result; +} + +INTC_API struct intc_u128 INTC_API_PREFIX(128_div_u64)(struct intc_u128 lhs, intc_u64 rhs) +{ + struct intc_u128 result = INTC_API_PREFIX(128_div)(lhs, INTC_U64_TO_U128(rhs)); + return result; +} + +INTC_API struct intc_u128 INTC_API_PREFIX(128_mod_u64)(struct intc_u128 lhs, intc_u64 rhs) +{ + struct intc_u128 result = INTC_API_PREFIX(128_mod)(lhs, INTC_U64_TO_U128(rhs)); + return result; +} + +// ----------------------------------------------------------------------------- +// NOTE: U128 Misc +// ----------------------------------------------------------------------------- +INTC_API int INTC_API_PREFIX(128_clz)(struct intc_u128 in) +{ + int result = in.hi ? 64 /*include the 64 bits of the low part*/ : 0; + for (intc_u64 val = result ? in.hi : in.lo; + val; + val >>= 1, result++) + { + } + + return result; +} + +// ----------------------------------------------------------------------------- +// NOTE: U128 Printing +// ----------------------------------------------------------------------------- +INTC_API struct intc_u128_string INTC_API_PREFIX(128_str)(struct intc_u128 in, unsigned base, int separate_every_n_chars, char separate_ch) +{ + struct intc_u128_string val = INTC_ZERO_INIT; + if ((base < 2) || (base > 36)) + return val; + + if (INTC_API_PREFIX(128_eq)(in, INTC_U128_ZERO)) + { + val.str[val.size++] = '0'; + } + else + { + int insert_count = 0; + struct intc_u128_divmod_result div_result; + div_result.quot = in; + div_result.rem = INTC_U128_ZERO; + + do + { + div_result = INTC_API_PREFIX(128_divmod)(div_result.quot, INTC_U64_TO_U128(base)); + val.str[val.size++] = "0123456789abcdefghijklmnopqrstuvwxyz"[div_result.rem.lo]; + + if (separate_every_n_chars > 0 && INTC_API_PREFIX(128_as_bool)(div_result.quot)) + { + insert_count++; + if (insert_count % separate_every_n_chars == 0) + val.str[val.size++] = separate_ch; + } + } while (INTC_API_PREFIX(128_as_bool)(div_result.quot)); + } + + INTC_ASSERT(val.size < sizeof(val.str) - 1); + + struct intc_u128_string result; + result.size = 0; + + for (int i = val.size - 1; i >= 0; i--) + result.str[result.size++] = val.str[i]; + result.str[result.size] = 0; + + return result; +} + +INTC_API struct intc_u128_string INTC_API_PREFIX(128_int_str)(struct intc_u128 in, int separate_every_n_chars, char separate_ch) +{ + struct intc_u128_string result = INTC_API_PREFIX(128_str)(in, 10 /*base*/, separate_every_n_chars, separate_ch); + return result; +} + +INTC_API struct intc_u128_string INTC_API_PREFIX(128_readable_int_str)(struct intc_u128 in) +{ + struct intc_u128_string result = INTC_API_PREFIX(128_str)(in, 10 /*base*/, 3 /*separate_every_n_chars*/, ',' /*separate_ch*/); + return result; +} + +INTC_API struct intc_u128_string INTC_API_PREFIX(128_hex_str)(struct intc_u128 in, int separate_every_n_chars, char separate_ch) +{ + struct intc_u128_string result = INTC_API_PREFIX(128_str)(in, 16 /*base*/, separate_every_n_chars, separate_ch); + return result; +} + +INTC_API struct intc_u128_string INTC_API_PREFIX(128_readable_hex_str)(struct intc_u128 in) +{ + struct intc_u128_string result = INTC_API_PREFIX(128_str)(in, 16 /*base*/, 4 /*separate_every_n_chars*/, '_' /*separate_ch*/); + return result; +} +INTC_END_EXTERN_C + +#if !defined(INTC_NO_CPP_FEATURES) +// ----------------------------------------------------------------------------- +// NOTE: U128 CPP Bitwise +// ----------------------------------------------------------------------------- +INTC_API intc_u128 operator&(intc_u128 lhs, intc_u128 rhs) +{ + intc_u128 result = INTC_API_PREFIX(128_and)(lhs, rhs); + return result; +} + +INTC_API intc_u128 operator|(intc_u128 lhs, intc_u128 rhs) +{ + intc_u128 result = INTC_API_PREFIX(128_or)(lhs, rhs); + return result; +} + +INTC_API intc_u128 operator^(intc_u128 lhs, intc_u128 rhs) +{ + intc_u128 result = INTC_API_PREFIX(128_xor)(lhs, rhs); + return result; +} + +INTC_API intc_u128 operator~(intc_u128 lhs) +{ + intc_u128 result = INTC_API_PREFIX(128_negate)(lhs); + return result; +} + +INTC_API intc_u128 operator<<(intc_u128 lhs, unsigned shift) +{ + intc_u128 result = INTC_API_PREFIX(128_lshift)(lhs, shift); + return result; +} + +INTC_API intc_u128 operator>>(intc_u128 lhs, unsigned shift) +{ + intc_u128 result = INTC_API_PREFIX(128_rshift)(lhs, shift); + return result; +} + +// ----------------------------------------------------------------------------- +// NOTE: U128 CPP Equality +// ----------------------------------------------------------------------------- +INTC_API bool operator==(intc_u128 lhs, intc_u128 rhs) +{ + bool result = INTC_API_PREFIX(128_eq)(lhs, rhs); + return result; +} + +INTC_API bool operator!=(intc_u128 lhs, intc_u128 rhs) +{ + bool result = INTC_API_PREFIX(128_neq)(lhs, rhs); + return result; +} + +// ----------------------------------------------------------------------------- +// NOTE: U128 CPP Relational +// ----------------------------------------------------------------------------- +INTC_API bool operator>(intc_u128 lhs, intc_u128 rhs) +{ + bool result = INTC_API_PREFIX(128_gt)(lhs, rhs); + return result; +} + +INTC_API bool operator<(intc_u128 lhs, intc_u128 rhs) +{ + bool result = INTC_API_PREFIX(128_lt)(lhs, rhs); + return result; +} + +INTC_API bool operator>=(intc_u128 lhs, intc_u128 rhs) +{ + bool result = INTC_API_PREFIX(128_gt_eq)(lhs, rhs); + return result; +} + +INTC_API bool operator<=(intc_u128 lhs, intc_u128 rhs) +{ + bool result = INTC_API_PREFIX(128_lt_eq)(lhs, rhs); + return result; +} + +// ----------------------------------------------------------------------------- +// NOTE: U128 CPP Arithmetic +// ----------------------------------------------------------------------------- +INTC_API intc_u128 operator+(intc_u128 lhs, intc_u128 rhs) +{ + intc_u128 result = INTC_API_PREFIX(128_add)(lhs, rhs); + return result; +} + +INTC_API intc_u128 operator-(intc_u128 lhs, intc_u128 rhs) +{ + intc_u128 result = INTC_API_PREFIX(128_sub)(lhs, rhs); + return result; +} + +INTC_API intc_u128 operator*(intc_u128 lhs, intc_u128 rhs) +{ + intc_u128 result = INTC_API_PREFIX(128_mul)(lhs, rhs); + return result; +} + +INTC_API intc_u128 operator/(intc_u128 lhs, intc_u128 rhs) +{ + intc_u128 result = INTC_API_PREFIX(128_div)(lhs, rhs); + return result; +} + +INTC_API intc_u128 operator%(intc_u128 lhs, intc_u128 rhs) +{ + intc_u128 result = INTC_API_PREFIX(128_mod)(lhs, rhs); + return result; +} + +// ----------------------------------------------------------------------------- +// NOTE: U128 CPP Other +// ----------------------------------------------------------------------------- +INTC_API intc_u128 &operator&=(intc_u128 &lhs, intc_u128 rhs) +{ + lhs = lhs & rhs; + return lhs; +} + +INTC_API intc_u128 &operator|=(intc_u128 &lhs, intc_u128 rhs) +{ + lhs = lhs | rhs; + return lhs; +} + +INTC_API intc_u128 &operator^=(intc_u128 &lhs, intc_u128 rhs) +{ + lhs = lhs ^ rhs; + return lhs; +} + +INTC_API intc_u128 &operator<<=(intc_u128 &lhs, unsigned rhs) +{ + lhs = lhs << rhs; + return lhs; +} + +INTC_API intc_u128 &operator>>=(intc_u128 &lhs, unsigned rhs) +{ + lhs = lhs >> rhs; + return lhs; +} + +INTC_API intc_u128 &operator+=(intc_u128 &lhs, intc_u128 rhs) +{ + lhs = lhs + rhs; + return lhs; +} + +INTC_API intc_u128 &operator-=(intc_u128 &lhs, intc_u128 rhs) +{ + lhs = lhs - rhs; + return lhs; +} + +INTC_API intc_u128 &operator*=(intc_u128 &lhs, intc_u128 rhs) +{ + lhs = lhs * rhs; + return lhs; +} + +INTC_API intc_u128 &operator/=(intc_u128 &lhs, intc_u128 rhs) +{ + lhs = lhs / rhs; + return lhs; +} + +INTC_API intc_u128 &operator%=(intc_u128 &lhs, intc_u128 rhs) +{ + lhs = lhs % rhs; + return lhs; +} + +INTC_API intc_u128 &operator++(intc_u128 &lhs) +{ + lhs = lhs + 1; + return lhs; +} + +INTC_API intc_u128 &operator--(intc_u128 &lhs) +{ + lhs = lhs - 1; + return lhs; +} + +INTC_API intc_u128 operator++(intc_u128 &lhs, int) +{ + intc_u128 val = lhs; + ++val; + return val; +} + +INTC_API intc_u128 operator--(intc_u128 &lhs, int) +{ + intc_u128 val = lhs; + --val; + return val; +} +#endif // !defined(INTC_NO_CPP_FEATURES) + +#if !defined(INTC_NO_U256) +INTC_BEGIN_EXTERN_C +// ----------------------------------------------------------------------------- +// NOTE: 256 Bit Unsigned Integer +// ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- +// NOTE: U256 Converters +// ----------------------------------------------------------------------------- +INTC_API bool INTC_API_PREFIX(256_init_cstring)(char const *string, int size, struct intc_u256 *dest) +{ + if (string == 0 || size == 0 || !dest) + return false; + + if (size < 0) + { + for (size = 0; string[size]; size++) + ; + } + + if (size >= 2 && string[1] == 'x') { string += 2; size -= 2; } + else if (size >= 1 && string[0] == 'x') { string += 1; size -= 1; } + + char buffer[64]; + int pad_length = (int)sizeof(buffer) - size; + for (int pad_index = 0; pad_index < pad_length; pad_index++) + buffer[pad_index] = '0'; + + for (int string_index = 0; string_index < size; string_index++) + buffer[pad_length + string_index] = string[string_index]; + + int half_buffer_size = sizeof(buffer) / 2; + bool result = INTC_API_PREFIX(128_init_cstring)(buffer, half_buffer_size, &dest->hi); + result |= INTC_API_PREFIX(128_init_cstring)(buffer + half_buffer_size, half_buffer_size, &dest->lo); + + return result; +} + +INTC_API bool INTC_API_PREFIX(256_init_cstring_base)(char const *string, int size, int base, struct intc_u256 *dest) +{ + if (string == 0 || size == 0 || !dest || base <= 0) + return false; + + if (size < 0) + { + for (size = 0; string[size]; size++) + ; + } + + if (size >= 2 && string[1] == 'x') { string += 2; size -= 2; } + else if (size >= 1 && string[0] == 'x') { string += 1; size -= 1; } + + *dest = INTC_U256_ZERO; + struct intc_u256 power = INTC_U64_TO_U256(1); + for (int digit = 0, pos = size - 1; + pos >= 0; + digit = 0, pos--) + { + if ('0' <= string[pos] && string[pos] <= '9') + digit = string[pos] - '0'; + else if ('a' <= string[pos] && string[pos] <= 'z') + digit = string[pos] - 'a' + 10; + else if ('A' <= string[pos] && string[pos] <= 'Z') + digit = string[pos] - 'A' + 10; + else + return false; + + *dest = INTC_API_PREFIX(256_add)(*dest, INTC_API_PREFIX(256_mul_u64)(power, (intc_u64)digit)); + power = INTC_API_PREFIX(256_mul_u64)(power, base); + } + + return true; +} + +INTC_API bool INTC_API_PREFIX(256_as_bool)(struct intc_u256 in) +{ + bool result = INTC_API_PREFIX(128_as_bool)(in.lo) | INTC_API_PREFIX(128_as_bool)(in.hi); + return result; +} + +INTC_API intc_u8 INTC_API_PREFIX(256_as_u8)(struct intc_u256 in) +{ + intc_u8 result = (intc_u8)in.lo.lo; + return result; +} + +INTC_API intc_u16 INTC_API_PREFIX(256_as_u16)(struct intc_u256 in) +{ + intc_u16 result = (intc_u16)in.lo.lo; + return result; +} + +INTC_API intc_u32 INTC_API_PREFIX(256_as_u32)(struct intc_u256 in) +{ + intc_u32 result = (intc_u32)in.lo.lo; + return result; +} + +INTC_API intc_u64 INTC_API_PREFIX(256_as_u64)(struct intc_u256 in) +{ + intc_u64 result = (intc_u64)in.lo.lo; + return result; +} + +INTC_API struct intc_u128 INTC_API_PREFIX(256_as_u128)(struct intc_u256 in) +{ + struct intc_u128 result = in.lo; + return result; +} + +// ----------------------------------------------------------------------------- +// NOTE: U256 Bitwise +// ----------------------------------------------------------------------------- +INTC_API struct intc_u256 INTC_API_PREFIX(256_and)(struct intc_u256 lhs, struct intc_u256 rhs) +{ + struct intc_u256 result = INTC_U256(INTC_API_PREFIX(128_and)(lhs.lo, rhs.lo), INTC_API_PREFIX(128_and)(lhs.hi, rhs.hi)); + return result; +} + +INTC_API struct intc_u256 INTC_API_PREFIX(256_or)(struct intc_u256 lhs, struct intc_u256 rhs) +{ + struct intc_u256 result = INTC_U256(INTC_API_PREFIX(128_or)(lhs.lo, rhs.lo), INTC_API_PREFIX(128_or)(lhs.hi, rhs.hi)); + return result; +} + +INTC_API struct intc_u256 INTC_API_PREFIX(256_xor)(struct intc_u256 lhs, struct intc_u256 rhs) +{ + struct intc_u256 result = INTC_U256(INTC_API_PREFIX(128_xor)(lhs.lo, rhs.lo), INTC_API_PREFIX(128_xor)(lhs.hi, rhs.hi)); + return result; +} + +INTC_API struct intc_u256 INTC_API_PREFIX(256_and_u128)(struct intc_u256 lhs, struct intc_u128 rhs) +{ + struct intc_u256 result = INTC_U256(INTC_API_PREFIX(128_and)(lhs.lo, rhs), INTC_U128_ZERO); + return result; +} + +INTC_API struct intc_u256 INTC_API_PREFIX(256_or_u128)(struct intc_u256 lhs, struct intc_u128 rhs) +{ + struct intc_u256 result = INTC_U256(INTC_API_PREFIX(128_or)(lhs.lo, rhs), lhs.hi); + return result; +} + +INTC_API struct intc_u256 INTC_API_PREFIX(256_xor_u128)(struct intc_u256 lhs, struct intc_u128 rhs) +{ + struct intc_u256 result = INTC_U256(INTC_API_PREFIX(128_xor)(lhs.lo, rhs), lhs.hi); + return result; +} + +INTC_API struct intc_u256 INTC_API_PREFIX(256_negate)(struct intc_u256 lhs) +{ + struct intc_u256 result = INTC_U256(INTC_API_PREFIX(128_negate)(lhs.lo), INTC_API_PREFIX(128_negate)(lhs.hi)); + return result; +} + +INTC_API struct intc_u256 INTC_API_PREFIX(256_lshift)(struct intc_u256 lhs, unsigned shift) +{ + + if (shift >= 256) + return INTC_U256_ZERO; + + if (shift == 128) + return INTC_U256(INTC_U128_ZERO, lhs.lo); + + if (shift == 0) + return lhs; + + if (shift < 128) + { + struct intc_u128 lo = INTC_API_PREFIX(128_lshift)(lhs.lo, shift); + struct intc_u128 hi = INTC_API_PREFIX(128_add)(INTC_API_PREFIX(128_lshift)(lhs.hi, shift), INTC_API_PREFIX(128_rshift)(lhs.lo, 128 - shift)); + return INTC_U256(lo, hi); + } + + if ((256 > shift) && (shift > 128)) + return INTC_U256(INTC_U128_ZERO, INTC_API_PREFIX(128_lshift)(lhs.lo, (shift - 128))); + + return INTC_U256_ZERO; +} + +INTC_API struct intc_u256 INTC_API_PREFIX(256_rshift)(struct intc_u256 lhs, unsigned shift) +{ + if (shift >= 256) + return INTC_U256_ZERO; + + if (shift == 128) + return INTC_U256(lhs.hi, INTC_U128_ZERO); + + if (shift == 0) + return lhs; + + if (shift < 128) + { + struct intc_u128 lo = INTC_API_PREFIX(128_add)(INTC_API_PREFIX(128_lshift)(lhs.hi, 128 - shift), INTC_API_PREFIX(128_rshift)(lhs.lo, shift)); + struct intc_u128 hi = INTC_API_PREFIX(128_rshift)(lhs.hi, shift); + return INTC_U256(lo, hi); + } + + if ((256 > shift) && (shift > 128)) + return INTC_U256(INTC_U128_ZERO, INTC_API_PREFIX(128_rshift)(lhs.hi, (shift - 128))); + + return INTC_U256_ZERO; +} + +// ----------------------------------------------------------------------------- +// NOTE: U256 Equality +// ----------------------------------------------------------------------------- +INTC_API bool INTC_API_PREFIX(256_eq)(struct intc_u256 lhs, struct intc_u256 rhs) +{ + bool result = (INTC_API_PREFIX(128_eq)(lhs.lo, rhs.lo) && INTC_API_PREFIX(128_eq)(lhs.hi, rhs.hi)); + return result; +} + +INTC_API bool INTC_API_PREFIX(256_neq)(struct intc_u256 lhs, struct intc_u256 rhs) +{ + bool result = (INTC_API_PREFIX(128_neq)(lhs.lo, rhs.lo) | INTC_API_PREFIX(128_neq)(lhs.hi, rhs.hi)); + return result; +} + +// ----------------------------------------------------------------------------- +// NOTE: U256 Equality U64 Helpers +// ----------------------------------------------------------------------------- +INTC_API bool INTC_API_PREFIX(256_eq_u64)(struct intc_u256 lhs, intc_u64 rhs) +{ + bool result = INTC_API_PREFIX(256_eq)(lhs, INTC_U64_TO_U256(rhs)); + return result; +} + +INTC_API bool INTC_API_PREFIX(256_neq_u64)(struct intc_u256 lhs, intc_u64 rhs) +{ + bool result = INTC_API_PREFIX(256_neq)(lhs, INTC_U64_TO_U256(rhs)); + return result; +} + +// ----------------------------------------------------------------------------- +// NOTE: U256 Relational +// ----------------------------------------------------------------------------- +INTC_API bool INTC_API_PREFIX(256_gt)(struct intc_u256 lhs, struct intc_u256 rhs) +{ + bool result = INTC_API_PREFIX(128_eq)(lhs.hi, rhs.hi) ? INTC_API_PREFIX(128_gt)(lhs.lo, rhs.lo) : INTC_API_PREFIX(128_gt)(lhs.hi, rhs.hi); + return result; +} + +INTC_API bool INTC_API_PREFIX(256_lt)(struct intc_u256 lhs, struct intc_u256 rhs) +{ + bool result = INTC_API_PREFIX(128_eq)(lhs.hi, rhs.hi) ? INTC_API_PREFIX(128_lt)(lhs.lo, rhs.lo) : INTC_API_PREFIX(128_lt)(lhs.hi, rhs.hi); + return result; +} + +INTC_API bool INTC_API_PREFIX(256_gt_eq)(struct intc_u256 lhs, struct intc_u256 rhs) +{ + bool result = INTC_API_PREFIX(256_gt)(lhs, rhs) | INTC_API_PREFIX(256_eq)(lhs, rhs); + return result; +} + +INTC_API bool INTC_API_PREFIX(256_lt_eq)(struct intc_u256 lhs, struct intc_u256 rhs) +{ + bool result = INTC_API_PREFIX(128_eq)(lhs.hi, rhs.hi) ? INTC_API_PREFIX(128_lt_eq)(lhs.lo, rhs.lo) : INTC_API_PREFIX(128_lt_eq)(lhs.hi, rhs.hi); + return result; +} + +// ----------------------------------------------------------------------------- +// NOTE: U256 Relational U64 Helpers +// ----------------------------------------------------------------------------- +INTC_API bool INTC_API_PREFIX(256_gt_u64)(struct intc_u256 lhs, intc_u64 rhs) +{ + bool result = INTC_API_PREFIX(256_gt)(lhs, INTC_U64_TO_U256(rhs)); + return result; +} + +INTC_API bool INTC_API_PREFIX(256_lt_u64)(struct intc_u256 lhs, intc_u64 rhs) +{ + bool result = INTC_API_PREFIX(256_lt)(lhs, INTC_U64_TO_U256(rhs)); + return result; +} + +INTC_API bool INTC_API_PREFIX(256_gt_eq_u64)(struct intc_u256 lhs, intc_u64 rhs) +{ + bool resugt_eq = INTC_API_PREFIX(256_gt_eq)(lhs, INTC_U64_TO_U256(rhs)); + return resugt_eq; +} + +INTC_API bool INTC_API_PREFIX(256_lt_eq_u64)(struct intc_u256 lhs, intc_u64 rhs) +{ + bool result_eq = INTC_API_PREFIX(256_lt_eq)(lhs, INTC_U64_TO_U256(rhs)); + return result_eq; +} + +// ----------------------------------------------------------------------------- +// NOTE: U256 Arithmetic +// ----------------------------------------------------------------------------- +INTC_API struct intc_u256 INTC_API_PREFIX(256_add)(struct intc_u256 lhs, struct intc_u256 rhs) +{ + struct intc_u128 lo = INTC_API_PREFIX(128_add)(lhs.lo, rhs.lo); + struct intc_u128 hi = INTC_API_PREFIX(128_add)(lhs.hi, rhs.hi); + + bool lo_overflow = INTC_API_PREFIX(128_lt)(lo, lhs.lo); + if (lo_overflow) hi = INTC_API_PREFIX(128_add)(hi, INTC_U64_TO_U128(1)); + + struct intc_u256 result = INTC_U256(lo, hi); + return result; +} + +INTC_API struct intc_u256 INTC_API_PREFIX(256_sub)(struct intc_u256 lhs, struct intc_u256 rhs) +{ + struct intc_u128 lo = INTC_API_PREFIX(128_sub)(lhs.lo, rhs.lo); + struct intc_u128 hi = INTC_API_PREFIX(128_sub)(lhs.hi, rhs.hi); + + bool lo_overflow = INTC_API_PREFIX(128_gt)(lo, lhs.lo); + if (lo_overflow) hi = INTC_API_PREFIX(128_sub)(hi, INTC_U64_TO_U128(1)); + + struct intc_u256 result = INTC_U256(lo, hi); + return result; +} + +INTC_API struct intc_u256 INTC_API_PREFIX(256_mul)(struct intc_u256 lhs, struct intc_u256 rhs) +{ + // split values into 4 64-bit parts + struct intc_u128 top[4] = {INTC_U64_TO_U128(lhs.hi.hi), INTC_U64_TO_U128(lhs.hi.lo), INTC_U64_TO_U128(lhs.lo.hi), INTC_U64_TO_U128(lhs.lo.lo)}; + struct intc_u128 bottom[4] = {INTC_U64_TO_U128(rhs.hi.hi), INTC_U64_TO_U128(rhs.hi.lo), INTC_U64_TO_U128(rhs.lo.hi), INTC_U64_TO_U128(rhs.lo.lo)}; + struct intc_u128 products[4][4]; + + // multiply each component of the values + for(int y = 3; y > -1; y--){ + for(int x = 3; x > -1; x--){ + products[3 - y][x] = INTC_API_PREFIX(128_mul)(top[x], bottom[y]); + } + } + + // first row + struct intc_u128 fourth64 = INTC_U64_TO_U128(products[0][3].lo); + struct intc_u128 third64 = INTC_API_PREFIX(128_add)(INTC_U64_TO_U128(products[0][2].lo), INTC_U64_TO_U128(products[0][3].hi)); + struct intc_u128 second64 = INTC_API_PREFIX(128_add)(INTC_U64_TO_U128(products[0][1].lo), INTC_U64_TO_U128(products[0][2].hi)); + struct intc_u128 first64 = INTC_API_PREFIX(128_add)(INTC_U64_TO_U128(products[0][0].lo), INTC_U64_TO_U128(products[0][1].hi)); + + // second row + third64 = INTC_API_PREFIX(128_add)(third64, INTC_U64_TO_U128(products[1][3].lo)); + second64 = INTC_API_PREFIX(128_add)(second64, INTC_API_PREFIX(128_add)(INTC_U64_TO_U128(products[1][2].lo), INTC_U64_TO_U128(products[1][3].hi))); + first64 = INTC_API_PREFIX(128_add)(first64, INTC_API_PREFIX(128_add)(INTC_U64_TO_U128(products[1][1].lo), INTC_U64_TO_U128(products[1][2].hi))); + + // third row + second64 = INTC_API_PREFIX(128_add)(second64, INTC_U64_TO_U128(products[2][3].lo)); + first64 = INTC_API_PREFIX(128_add)(first64, INTC_API_PREFIX(128_add)(INTC_U64_TO_U128(products[2][2].lo), INTC_U64_TO_U128(products[2][3].hi))); + + // fourth roW + first64 = INTC_API_PREFIX(128_add)(first64, INTC_U64_TO_U128(products[3][3].lo)); + + // combines the values, taking care of carry over + struct intc_u256 a = INTC_U256(INTC_U128_ZERO, INTC_API_PREFIX(128_lshift)(first64, 64)); + struct intc_u256 b = INTC_U256(INTC_API_PREFIX(128_lshift)(third64, 64), INTC_U64_TO_U128(third64.hi)); + struct intc_u256 c = INTC_U256(INTC_U128_ZERO, second64); + struct intc_u256 d = INTC_U256(fourth64, INTC_U128_ZERO); + + struct intc_u256 result = INTC_API_PREFIX(256_add)(INTC_API_PREFIX(256_add)(INTC_API_PREFIX(256_add)(a, b), c), d); + return result; +} + +INTC_API struct intc_u256_divmod_result INTC_API_PREFIX(256_divmod)(struct intc_u256 lhs, struct intc_u256 rhs) +{ + // Save some calculations ///////////////////// + struct intc_u256_divmod_result result = INTC_ZERO_INIT; + + if (INTC_API_PREFIX(256_eq)(rhs, INTC_U256_ZERO)) + { + INTC_ASSERT(0 && "Division by zero"); + return result; + } + + if (INTC_API_PREFIX(256_eq)(rhs, INTC_U64_TO_U256(1))) + { + result.quot = lhs; + return result; + } + + if (INTC_API_PREFIX(256_eq)(lhs, rhs)) + { + result.quot = INTC_U64_TO_U256(1); + return result; + } + + if (INTC_API_PREFIX(256_eq)(lhs, INTC_U256_ZERO) || INTC_API_PREFIX(256_lt)(lhs, rhs)) + { + result.rem = lhs; + return result; + } + + struct intc_u256 const ONE = INTC_U64_TO_U256(1); + result.rem = lhs; + + int lhs_bit_count = INTC_API_PREFIX(256_clz)(lhs); + int rhs_bit_count = INTC_API_PREFIX(256_clz)(rhs); + int bit_count = lhs_bit_count - rhs_bit_count; + + struct intc_u256 copyd = INTC_API_PREFIX(256_lshift)(rhs, bit_count); + struct intc_u256 adder = INTC_API_PREFIX(256_lshift)(ONE, bit_count); + + if (INTC_API_PREFIX(256_gt)(copyd, result.rem)) + { + copyd = INTC_API_PREFIX(256_rshift)(copyd, 1); + adder = INTC_API_PREFIX(256_rshift)(adder, 1); + } + + while (INTC_API_PREFIX(256_gt_eq)(result.rem, rhs)) + { + if (INTC_API_PREFIX(256_gt_eq)(result.rem, copyd)) + { + result.rem = INTC_API_PREFIX(256_sub)(result.rem, copyd); + result.quot = INTC_API_PREFIX(256_or)(result.quot, adder); + } + + copyd = INTC_API_PREFIX(256_rshift)(copyd, 1); + adder = INTC_API_PREFIX(256_rshift)(adder, 1); + } + + return result; +} + +INTC_API struct intc_u256 INTC_API_PREFIX(256_div)(struct intc_u256 lhs, struct intc_u256 rhs) +{ + struct intc_u256 result = INTC_API_PREFIX(256_divmod)(lhs, rhs).quot; + return result; +} + +INTC_API struct intc_u256 INTC_API_PREFIX(256_mod)(struct intc_u256 lhs, struct intc_u256 rhs) +{ + struct intc_u256 result = INTC_API_PREFIX(256_divmod)(lhs, rhs).rem; + return result; +} + +// ----------------------------------------------------------------------------- +// NOTE: U256 Arithmetic U64 Helpers +// ----------------------------------------------------------------------------- +INTC_API struct intc_u256 INTC_API_PREFIX(256_add_u64)(struct intc_u256 lhs, intc_u64 rhs) +{ + struct intc_u256 result = INTC_API_PREFIX(256_add)(lhs, INTC_U64_TO_U256(rhs)); + return result; +} + +INTC_API struct intc_u256 INTC_API_PREFIX(256_sub_u64)(struct intc_u256 lhs, intc_u64 rhs) +{ + struct intc_u256 result = INTC_API_PREFIX(256_sub)(lhs, INTC_U64_TO_U256(rhs)); + return result; +} + +INTC_API struct intc_u256 INTC_API_PREFIX(256_mul_u64)(struct intc_u256 lhs, intc_u64 rhs) +{ + struct intc_u256 result = INTC_API_PREFIX(256_mul)(lhs, INTC_U64_TO_U256(rhs)); + return result; +} + +INTC_API struct intc_u256_divmod_result INTC_API_PREFIX(256_divmod_u64)(struct intc_u256 lhs, intc_u64 rhs) +{ + struct intc_u256_divmod_result result = INTC_API_PREFIX(256_divmod)(lhs, INTC_U64_TO_U256(rhs)); + return result; +} + +INTC_API struct intc_u256 INTC_API_PREFIX(256_div_u64)(struct intc_u256 lhs, intc_u64 rhs) +{ + struct intc_u256 result = INTC_API_PREFIX(256_div)(lhs, INTC_U64_TO_U256(rhs)); + return result; +} + +INTC_API struct intc_u256 INTC_API_PREFIX(256_mod_u64)(struct intc_u256 lhs, intc_u64 rhs) +{ + struct intc_u256 result = INTC_API_PREFIX(256_mod)(lhs, INTC_U64_TO_U256(rhs)); + return result; +} + +// ----------------------------------------------------------------------------- +// NOTE: U256 Misc +// ----------------------------------------------------------------------------- +INTC_API int INTC_API_PREFIX(256_clz)(struct intc_u256 in) +{ + int result = INTC_API_PREFIX(128_as_bool)(in.hi) ? 128 /*include the 128 bits of the low part*/ : 0; + for (struct intc_u128 val = result ? in.hi : in.lo; + INTC_API_PREFIX(128_as_bool)(val); + val = INTC_API_PREFIX(128_rshift)(val, 1), result++) + { + } + + return result; +} + +// ----------------------------------------------------------------------------- +// NOTE: U256 Printing +// ----------------------------------------------------------------------------- +INTC_API struct intc_u256_string INTC_API_PREFIX(256_str)(struct intc_u256 in, unsigned base, int separate_every_n_chars, char separate_ch) +{ + struct intc_u256_string val = {0}; + if ((base < 2) || (base > 36)) + return val; + + if (INTC_API_PREFIX(256_eq)(in, INTC_U256_ZERO)) + { + val.str[val.size++] = '0'; + } + else + { + int insert_count = 0; + + struct intc_u256_divmod_result div_result = INTC_ZERO_INIT; + div_result.quot = in; + do + { + div_result = INTC_API_PREFIX(256_divmod)(div_result.quot, INTC_U64_TO_U256(base)); + val.str[val.size++] = "0123456789abcdefghijklmnopqrstuvwxyz"[INTC_API_PREFIX(128_as_u32)(div_result.rem.lo)]; + + if (separate_every_n_chars > 0 && INTC_API_PREFIX(256_as_bool)(div_result.quot)) + { + insert_count++; + if (insert_count % separate_every_n_chars == 0) + val.str[val.size++] = separate_ch; + } + } while (INTC_API_PREFIX(256_as_bool)(div_result.quot)); + } + + INTC_ASSERT(val.size <= sizeof(val.str) - 1); + + struct intc_u256_string result; + result.size = 0; + + for (int i = val.size - 1; i >= 0; i--) + result.str[result.size++] = val.str[i]; + result.str[result.size] = 0; + + return result; +} + +INTC_API struct intc_u256_string INTC_API_PREFIX(256_int_str)(struct intc_u256 in, int separate_every_n_chars, char separate_ch) +{ + struct intc_u256_string result = INTC_API_PREFIX(256_str)(in, 10 /*base*/, separate_every_n_chars, separate_ch); + return result; +} + +INTC_API struct intc_u256_string INTC_API_PREFIX(256_readable_int_str)(struct intc_u256 in) +{ + struct intc_u256_string result = INTC_API_PREFIX(256_str)(in, 10 /*base*/, 3 /*separate_every_n_chars*/, ','); + return result; +} + +INTC_API struct intc_u256_string INTC_API_PREFIX(256_hex_str)(struct intc_u256 in, int separate_every_n_chars, char separate_ch) +{ + struct intc_u256_string result = INTC_API_PREFIX(256_str)(in, 16 /*base*/, separate_every_n_chars, separate_ch); + return result; +} + +INTC_API struct intc_u256_string INTC_API_PREFIX(256_readable_hex_str)(struct intc_u256 in) +{ + struct intc_u256_string result = INTC_API_PREFIX(256_str)(in, 16 /*base*/, 4 /*separate_ever_n_chars*/, '_' /*separate_ch*/); + return result; +} +INTC_END_EXTERN_C + +#if !defined(INTC_NO_CPP_FEATURES) +// ----------------------------------------------------------------------------- +// NOTE: U256 CPP Bitwise +// ----------------------------------------------------------------------------- +INTC_API intc_u256 operator&(intc_u256 lhs, intc_u256 rhs) +{ + intc_u256 result = INTC_API_PREFIX(256_and)(lhs, rhs); + return result; +} + +INTC_API intc_u256 operator|(intc_u256 lhs, intc_u256 rhs) +{ + intc_u256 result = INTC_API_PREFIX(256_or)(lhs, rhs); + return result; +} + +INTC_API intc_u256 operator^(intc_u256 lhs, intc_u256 rhs) +{ + intc_u256 result = INTC_API_PREFIX(256_xor)(lhs, rhs); + return result; +} + +INTC_API intc_u256 operator~(intc_u256 lhs) +{ + intc_u256 result = INTC_API_PREFIX(256_negate)(lhs); + return result; +} + +INTC_API intc_u256 operator<<(intc_u256 lhs, unsigned shift) +{ + intc_u256 result = INTC_API_PREFIX(256_lshift)(lhs, shift); + return result; +} + +INTC_API intc_u256 operator>>(intc_u256 lhs, unsigned shift) +{ + intc_u256 result = INTC_API_PREFIX(256_rshift)(lhs, shift); + return result; +} + +// ----------------------------------------------------------------------------- +// NOTE: U256 CPP Equality +// ----------------------------------------------------------------------------- +INTC_API bool operator==(intc_u256 lhs, intc_u256 rhs) +{ + bool result = INTC_API_PREFIX(256_eq)(lhs, rhs); + return result; +} + +INTC_API bool operator!=(intc_u256 lhs, intc_u256 rhs) +{ + bool result = INTC_API_PREFIX(256_neq)(lhs, rhs); + return result; +} + +// ----------------------------------------------------------------------------- +// NOTE: U256 CPP Relational +// ----------------------------------------------------------------------------- +INTC_API bool operator>(intc_u256 lhs, intc_u256 rhs) +{ + bool result = INTC_API_PREFIX(256_gt)(lhs, rhs); + return result; +} + +INTC_API bool operator<(intc_u256 lhs, intc_u256 rhs) +{ + bool result = INTC_API_PREFIX(256_lt)(lhs, rhs); + return result; +} + +INTC_API bool operator>=(intc_u256 lhs, intc_u256 rhs) +{ + bool result = INTC_API_PREFIX(256_gt_eq)(lhs, rhs); + return result; +} + +INTC_API bool operator<=(intc_u256 lhs, intc_u256 rhs) +{ + bool result = INTC_API_PREFIX(256_lt_eq)(lhs, rhs); + return result; +} + +// ----------------------------------------------------------------------------- +// NOTE: U256 CPP Arithmetic +// ----------------------------------------------------------------------------- +INTC_API intc_u256 operator+(intc_u256 lhs, intc_u256 rhs) +{ + intc_u256 result = INTC_API_PREFIX(256_add)(lhs, rhs); + return result; +} + +INTC_API intc_u256 operator-(intc_u256 lhs, intc_u256 rhs) +{ + intc_u256 result = INTC_API_PREFIX(256_sub)(lhs, rhs); + return result; +} + +INTC_API intc_u256 operator*(intc_u256 lhs, intc_u256 rhs) +{ + intc_u256 result = INTC_API_PREFIX(256_mul)(lhs, rhs); + return result; +} + +INTC_API intc_u256 operator/(intc_u256 lhs, intc_u256 rhs) +{ + intc_u256 result = INTC_API_PREFIX(256_div)(lhs, rhs); + return result; +} + +INTC_API intc_u256 operator%(intc_u256 lhs, intc_u256 rhs) +{ + intc_u256 result = INTC_API_PREFIX(256_mod)(lhs, rhs); + return result; +} + +// ----------------------------------------------------------------------------- +// NOTE: U256 CPP Other +// ----------------------------------------------------------------------------- +INTC_API intc_u256 &operator&=(intc_u256 &lhs, intc_u256 rhs) +{ + lhs = lhs & rhs; + return lhs; +} + +INTC_API intc_u256 &operator|=(intc_u256 &lhs, intc_u256 rhs) +{ + lhs = lhs | rhs; + return lhs; +} + +INTC_API intc_u256 &operator^=(intc_u256 &lhs, intc_u256 rhs) +{ + lhs = lhs ^ rhs; + return lhs; +} + +INTC_API intc_u256 &operator<<=(intc_u256 &lhs, unsigned rhs) +{ + lhs = lhs << rhs; + return lhs; +} + +INTC_API intc_u256 &operator>>=(intc_u256 &lhs, unsigned rhs) +{ + lhs = lhs >> rhs; + return lhs; +} + +INTC_API intc_u256 &operator+=(intc_u256 &lhs, intc_u256 rhs) +{ + lhs = lhs + rhs; + return lhs; +} + +INTC_API intc_u256 &operator-=(intc_u256 &lhs, intc_u256 rhs) +{ + lhs = lhs - rhs; + return lhs; +} + +INTC_API intc_u256 &operator*=(intc_u256 &lhs, intc_u256 rhs) +{ + lhs = lhs * rhs; + return lhs; +} + +INTC_API intc_u256 &operator/=(intc_u256 &lhs, intc_u256 rhs) +{ + lhs = lhs / rhs; + return lhs; +} + +INTC_API intc_u256 &operator%=(intc_u256 &lhs, intc_u256 rhs) +{ + lhs = lhs % rhs; + return lhs; +} + +INTC_API intc_u256 &operator++(intc_u256 &lhs) +{ + lhs = lhs + 1; + return lhs; +} + +INTC_API intc_u256 &operator--(intc_u256 &lhs) +{ + lhs = lhs - 1; + return lhs; +} + +INTC_API intc_u256 operator++(intc_u256 &lhs, int) +{ + intc_u256 val = lhs; + ++val; + return val; +} + +INTC_API intc_u256 operator--(intc_u256 &lhs, int) +{ + intc_u256 val = lhs; + --val; + return val; +} +#endif // !defined(INTC_NO_CPP_FEATURES) +#endif // !defined(INTC_NO_U256) +#endif // INTC_IMPLEMENTATION diff --git a/intc_tests.h b/intc_tests.h new file mode 100644 index 0000000..4c5f6bb --- /dev/null +++ b/intc_tests.h @@ -0,0 +1,1950 @@ +#if !defined(INTC_TESTS_H) +#define INTC_TESTS_H +// ----------------------------------------------------------------------------- +// NOTE: Overview +// ----------------------------------------------------------------------------- +// calccrypto's uint128/256 C++ tests converted into tests compatible with +// intc.h variations. This file compiles down and exposes a couple of functions +// that allow you to run the unit tests for "intc.h" +// +// This file can be compiled standalone by defining the macro +// INTC_TESTS_WITH_MAIN. +// +// ----------------------------------------------------------------------------- +// NOTE: Configuration +// ----------------------------------------------------------------------------- +// #define INTC_TESTS_IMPLEMENTATION +// Define this in one and only one C++ file to enable the implementation +// code of the header file. +// +// #define INTC_TESTS_WITH_MAIN +// Define this macro to enable a main entry point function such that this +// file can be compiled standalone into a runnable executable. +// +// #define INTC_TESTS_NO_COLORS +// Define this macro to disable colors from the output of the unit tests. + +#if defined(INTC_TESTS_WITH_MAIN) + #if !defined(INTC_TESTS_IMPLEMENTATION) + #define INTC_TESTS_IMPLEMENTATION + #endif + + #define INTC_IMPLEMENTATION + #include +#endif + +#include +#include + +// ----------------------------------------------------------------------------- +// NOTE: Data Structures +// ----------------------------------------------------------------------------- +struct intc_test_state +{ + int test_count; + int fail_count; +}; + +struct intc_test_case +{ + char const *name; + int name_size; + bool failed; +}; + +// ----------------------------------------------------------------------------- +// NOTE: Functions +// ----------------------------------------------------------------------------- +// Run the unit tests for intc_u128/u256 integer types. +struct intc_test_state intc_u128_unit_tests(); + +#if !defined(INTC_NO_U256) +struct intc_test_state intc_u256_unit_tests(); +#endif + +// Helper function that runs both tests and pretty prints the summary of the tests +void intc_unit_tests(); + +// Helper function to print out test state +void intc_test_state_print(char const *label, struct intc_test_state const *state); +#endif // INTC_TESTS_H + +// ----------------------------------------------------------------------------- +// NOTE: Test Data Declarations +// ----------------------------------------------------------------------------- +#if defined(INTC_TESTS_IMPLEMENTATION) +struct intc_base_to_string { + int base; + char const *expect; +} const INTC_TESTS_STRING_BASE_TESTS[] = { + {2, "10000100000101011000010101101100"}, + {3, "12201102210121112101"}, + {4, "2010011120111230"}, + {5, "14014244043144"}, + {6, "1003520344444"}, + {7, "105625466632"}, + {8, "20405302554"}, + {9, "5642717471"}, + {10, "2216002924"}, + {11, "a3796a883"}, + {12, "51a175124"}, + {13, "294145645"}, + {14, "170445352"}, + {15, "ce82d6d4"}, + {16, "8415856c"}, + {17, "56dc4e33"}, + {18, "3b2db13a"}, + {19, "291i3b4g"}, + {20, "1eca0764"}, + {21, "14hc96jg"}, + {22, "jblga9e"}, + {23, "em6i5a5"}, + {24, "be75374"}, + {25, "91mo4go"}, + {26, "74d74li"}, + {27, "5jblgea"}, + {28, "4gl7i9g"}, + {29, "3l13lor"}, + {30, "315o5e4"}, + {31, "2fcfub9"}, + {32, "221b1bc"}, + {33, "1nkji2p"}, + {34, "1eq93ik"}, + {35, "176p6y9"}, + {36, "10ncmss"} +}; + +intc_u64 const INTC_TESTS_MAX_UNSIGNED_VALUES[] = { + (intc_u8)-1, + (intc_u16)-1, + (intc_u32)-1, + (intc_u64)-1, +}; + +// ----------------------------------------------------------------------------- +// NOTE: Testing Macros +// ----------------------------------------------------------------------------- +#define INTC_TESTS_ASSERT_MSG(expr, fmt, ...) \ + do \ + { \ + if (!(expr)) \ + { \ + test_case_.failed = true; \ + char const *file = intc_strip_path_to_file(__FILE__); \ + printf(" +--Test failed at %s:%d, expression was: %s\n", file, __LINE__, #expr); \ + printf(" V\n"); \ + if (fmt) \ + { \ + printf(" |--"); \ + printf(fmt, __VA_ARGS__); \ + fputc('\n', stdout); \ + } \ + } \ + } while (0) + +#define INTC_TESTS_ASSERT(expr) INTC_TESTS_ASSERT_MSG(expr, 0, "") + +#if defined(INTC_TESTS_NO_COLORS) + #define INTC_TESTS_COLOR_RED + #define INTC_TESTS_COLOR_GREEN + #define INTC_TESTS_COLOR_MAGENTA + #define INTC_TESTS_COLOR_RESET +#else + #define INTC_TESTS_COLOR_RED "\x1b[31m" + #define INTC_TESTS_COLOR_GREEN "\x1b[32m" + #define INTC_TESTS_COLOR_MAGENTA "\x1b[35m" + #define INTC_TESTS_COLOR_RESET "\x1b[0m" +#endif + +#define INTC_TESTS_BEGIN(test_name) \ + struct intc_test_case test_case_ = INTC_ZERO_INIT; \ + test_case_.name = test_name; \ + test_case_.name_size = sizeof(test_name) - 1; \ + test_case_.failed = false; \ + result.test_count++ + +#define INTC_TESTS_END \ + fprintf(stdout, " %s", test_case_.name); \ + for (int index = 0; index < (64 - test_case_.name_size); index++) \ + { \ + if (index) \ + fputc('.', stdout); \ + else \ + fputc(' ', stdout); \ + } \ + \ + fputc(' ', stdout); \ + if (test_case_.failed) \ + { \ + fprintf(stdout, INTC_TESTS_COLOR_RED "FAILED" INTC_TESTS_COLOR_RESET); \ + result.fail_count++; \ + } \ + else \ + fprintf(stdout, INTC_TESTS_COLOR_GREEN "OK" INTC_TESTS_COLOR_RESET); \ + fputc('\n', stdout); + +// ----------------------------------------------------------------------------- +// NOTE: Implementation +// ----------------------------------------------------------------------------- +static char *intc_strip_path_to_file(char const *file) +{ + int size = strlen(file); + char *result = (char *)file; + for (int i = size - 1; i >= 0; i--) + { + if (file[i] == '\\' || file[i] == '/') + { + result = result + i + 1; + break; + } + } + + return result; +} + +struct intc_test_state intc_u128_unit_tests(void) +{ + struct intc_test_state result = {0}; + printf(INTC_TESTS_COLOR_MAGENTA "intc_u128 unit tests" INTC_TESTS_COLOR_RESET); + printf("\n accessors.cpp\n"); + { + { + INTC_TESTS_BEGIN("Accessor.bits"); + struct intc_u128 value = INTC_U64_TO_U128(1); + for(int i = 0; i < 127; i++){ + INTC_TESTS_ASSERT(intc_u128_clz(value) == i + 1); // before shift + value = intc_u128_lshift(value, 1); + } + + INTC_TESTS_ASSERT(intc_u128_clz(INTC_U128_ZERO) == 0); + INTC_TESTS_END; + } + + { + INTC_TESTS_BEGIN("Accessor.data"); + struct intc_u128 const value = INTC_U128(0x0123456789abcdefULL, 0xfedcba9876543210ULL); + INTC_TESTS_ASSERT(value.hi == 0xfedcba9876543210ULL); + INTC_TESTS_ASSERT(value.lo == 0x0123456789abcdefULL); + INTC_TESTS_END; + } + } + + printf("\n add.cpp\n"); + { + { + INTC_TESTS_BEGIN("Arithmetic.add"); + struct intc_u128 const low = INTC_U128(1, 0); + struct intc_u128 const high = INTC_U128(0, 1); + + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_add(low, low), INTC_U64_TO_U128(2))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_add(low, high), INTC_U128(1, 1))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_add(high, high), INTC_U128(0, 2))); + INTC_TESTS_END; + } + + { + INTC_TESTS_BEGIN("External.add"); + bool t = true; + bool f = false; + intc_u8 u8 = 0xaaULL; + intc_u16 u16 = 0xaaaaULL; + intc_u32 u32 = 0xaaaaaaaaULL; + intc_u64 u64 = 0xaaaaaaaaaaaaaaaaULL; + + struct intc_u128 const val = INTC_U128(0xf0f0f0f0f0f0f0f0ULL, 0xf0f0f0f0f0f0f0f0ULL); + + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_add(INTC_U64_TO_U128(t) , val), INTC_U128(0xf0f0f0f0f0f0f0f1ULL, 0xf0f0f0f0f0f0f0f0ULL))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_add(INTC_U64_TO_U128(f) , val), INTC_U128(0xf0f0f0f0f0f0f0f0ULL, 0xf0f0f0f0f0f0f0f0ULL))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_add(INTC_U64_TO_U128(u8) , val), INTC_U128(0xf0f0f0f0f0f0f19aULL, 0xf0f0f0f0f0f0f0f0ULL))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_add(INTC_U64_TO_U128(u16), val), INTC_U128(0xf0f0f0f0f0f19b9aULL, 0xf0f0f0f0f0f0f0f0ULL))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_add(INTC_U64_TO_U128(u32), val), INTC_U128(0xf0f0f0f19b9b9b9aULL, 0xf0f0f0f0f0f0f0f0ULL))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_add(INTC_U64_TO_U128(u64), val), INTC_U128(0x9b9b9b9b9b9b9b9aULL, 0xf0f0f0f0f0f0f0f1ULL))); + + INTC_TESTS_ASSERT(u8 += intc_u128_as_u8(val) == (intc_u8)0x9aULL); + INTC_TESTS_ASSERT(u16 += intc_u128_as_u16(val) == (intc_u16)0x9b9aULL); + INTC_TESTS_ASSERT(u32 += intc_u128_as_u32(val) == (intc_u32)0x9b9b9b9aULL); + INTC_TESTS_ASSERT(u64 += intc_u128_as_u64(val) == (intc_u64)0x9b9b9b9b9b9b9b9aULL); + INTC_TESTS_END; + } + } + + printf("\n and.cpp\n"); + { + { + INTC_TESTS_BEGIN("BitWise.and"); + struct intc_u128 t = INTC_U64_TO_U128((bool)true); + struct intc_u128 f = INTC_U64_TO_U128((bool)false); + struct intc_u128 u8 = INTC_U64_TO_U128((intc_u8)0xaaULL); + struct intc_u128 u16 = INTC_U64_TO_U128((intc_u16)0xaaaaULL); + struct intc_u128 u32 = INTC_U64_TO_U128((intc_u32)0xaaaaaaaaULL); + struct intc_u128 u64 = INTC_U64_TO_U128((intc_u64)0xaaaaaaaaaaaaaaaaULL); + + struct intc_u128 const val = INTC_U128(0xf0f0f0f0f0f0f0f0ULL, 0xf0f0f0f0f0f0f0f0ULL); + + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_and(t , val), INTC_U64_TO_U128(0))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_and(f , val), INTC_U64_TO_U128(0))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_and(u8 , val), INTC_U64_TO_U128(0xa0ULL))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_and(u16, val), INTC_U64_TO_U128(0xa0a0ULL))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_and(u32, val), INTC_U64_TO_U128(0xa0a0a0a0ULL))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_and(u64, val), INTC_U64_TO_U128(0xa0a0a0a0a0a0a0a0ULL))); + INTC_TESTS_END; + } + + { + INTC_TESTS_BEGIN("External.and"); + bool t = true; + bool f = false; + intc_u8 u8 = 0xaaULL; + intc_u16 u16 = 0xaaaaULL; + intc_u32 u32 = 0xaaaaaaaaULL; + intc_u64 u64 = 0xaaaaaaaaaaaaaaaaULL; + struct intc_u128 const val = INTC_U128(0xf0f0f0f0f0f0f0f0ULL, 0xf0f0f0f0f0f0f0f0ULL); + + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_and(INTC_U64_TO_U128(t) , val), INTC_U64_TO_U128(0x0ULL))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_and(INTC_U64_TO_U128(f) , val), INTC_U64_TO_U128(0x0ULL))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_and(INTC_U64_TO_U128(u8) , val), INTC_U64_TO_U128(0xa0ULL))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_and(INTC_U64_TO_U128(u16), val), INTC_U64_TO_U128(0xa0a0ULL))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_and(INTC_U64_TO_U128(u32), val), INTC_U64_TO_U128(0xa0a0a0a0ULL))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_and(INTC_U64_TO_U128(u64), val), INTC_U64_TO_U128(0xa0a0a0a0a0a0a0a0ULL))); + + INTC_TESTS_ASSERT((bool)(t &= intc_u128_as_bool(val)) == true); + INTC_TESTS_ASSERT((bool)(f &= intc_u128_as_bool(val)) == false); + INTC_TESTS_ASSERT((u8 &= intc_u128_as_u8(val)) == (intc_u8)0xa0ULL); + INTC_TESTS_ASSERT((u16 &= intc_u128_as_u16(val)) == (intc_u16)0xa0a0ULL); + INTC_TESTS_ASSERT((u32 &= intc_u128_as_u32(val)) == (intc_u32)0xa0a0a0a0ULL); + INTC_TESTS_ASSERT((u64 &= intc_u128_as_u64(val)) == (intc_u64)0xa0a0a0a0a0a0a0a0ULL); + + // zero + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_and(INTC_U128_ZERO, val), INTC_U128_ZERO)); + INTC_TESTS_END; + } + } + + printf("\n assignment.cpp\n"); + { + { + INTC_TESTS_BEGIN("Assignment.all"); + const struct intc_u128 t_1 = INTC_U64_TO_U128(true); + const struct intc_u128 f_1 = INTC_U64_TO_U128(false); + const struct intc_u128 u8_1 = INTC_U64_TO_U128(0x01); + const struct intc_u128 u16_1 = INTC_U64_TO_U128(0x0123); + const struct intc_u128 u32_1 = INTC_U64_TO_U128(0x01234567); + const struct intc_u128 u64_1 = INTC_U64_TO_U128(0x0123456789abcdef); + + struct intc_u128 t_2 = INTC_U128_ZERO; + struct intc_u128 f_2 = INTC_U128_ZERO; + struct intc_u128 u8_2 = INTC_U128_ZERO; + struct intc_u128 u16_2 = INTC_U128_ZERO; + struct intc_u128 u32_2 = INTC_U128_ZERO; + struct intc_u128 u64_2 = INTC_U128_ZERO; + + t_2 = t_1; + f_2 = f_1; + u8_2 = u8_1; + u16_2 = u16_1; + u32_2 = u32_1; + u64_2 = u64_1; + + INTC_TESTS_ASSERT(intc_u128_eq(t_1, t_2)); + INTC_TESTS_ASSERT(intc_u128_eq(f_1, f_2)); + INTC_TESTS_ASSERT(intc_u128_eq(u8_1, u8_2)); + INTC_TESTS_ASSERT(intc_u128_eq(u16_1, u16_2)); + INTC_TESTS_ASSERT(intc_u128_eq(u32_1, u32_2)); + INTC_TESTS_ASSERT(intc_u128_eq(u64_1, u64_2)); + INTC_TESTS_END; + } + } + + printf("\n constructor.cpp\n"); + { + { + INTC_TESTS_BEGIN("Constructor.standard"); + struct intc_u128 value = INTC_U64_TO_U128(0x0123456789abcdefULL); + const struct intc_u128 original = value; + + INTC_TESTS_ASSERT(intc_u128_eq(INTC_U128_ZERO, INTC_U128_ZERO)); + INTC_TESTS_ASSERT(intc_u128_eq(value, original)); + INTC_TESTS_ASSERT(intc_u128_eq(value, INTC_U64_TO_U128(0x0123456789abcdefULL))); + INTC_TESTS_END; + } + + { + INTC_TESTS_BEGIN("Constructor.one"); + intc_u64 a = INTC_U64_TO_U128(true).hi; + intc_u64 b = INTC_U64_TO_U128(true).lo; + intc_u64 c = INTC_U64_TO_U128(false).hi; + intc_u64 d = INTC_U64_TO_U128(false).lo; + + intc_u64 e = INTC_U64_TO_U128((intc_u8)0x01ULL).hi; + intc_u64 f = INTC_U64_TO_U128((intc_u16)0x0123ULL).hi; + intc_u64 g = INTC_U64_TO_U128((intc_u32)0x01234567ULL).hi; + intc_u64 h = INTC_U64_TO_U128((intc_u64)0x0123456789abcdefULL).hi; + + intc_u64 i = INTC_U64_TO_U128((intc_u8)0x01ULL).lo; + intc_u64 j = INTC_U64_TO_U128((intc_u16)0x0123ULL).lo; + intc_u64 k = INTC_U64_TO_U128((intc_u32)0x01234567ULL).lo; + intc_u64 l = INTC_U64_TO_U128((intc_u64)0x0123456789abcdefULL).lo; + + INTC_TESTS_ASSERT(a == (intc_u64)false); + INTC_TESTS_ASSERT(b == (intc_u64)true); + INTC_TESTS_ASSERT(c == (intc_u64)false); + INTC_TESTS_ASSERT(d == (intc_u64)false); + + INTC_TESTS_ASSERT(e == 0ULL); + INTC_TESTS_ASSERT(f == 0ULL); + INTC_TESTS_ASSERT(g == 0ULL); + INTC_TESTS_ASSERT(h == 0ULL); + + INTC_TESTS_ASSERT(i == (intc_u8)0x01ULL); + INTC_TESTS_ASSERT(j == (intc_u16)0x0123ULL); + INTC_TESTS_ASSERT(k == (intc_u32)0x01234567ULL); + INTC_TESTS_ASSERT(l == (intc_u64)0x0123456789abcdefULL); + INTC_TESTS_END; + } + + { + INTC_TESTS_BEGIN("Constructor.two"); + for (int hi = 0; hi < 2; hi++) + { + for (int lo = 0; lo < 2; lo++) + { + struct intc_u128 const val = INTC_U128((intc_u64)lo, (intc_u64)hi); + INTC_TESTS_ASSERT(val.hi == hi); + INTC_TESTS_ASSERT(val.lo == lo); + } + } + + intc_u64 a = INTC_U128((intc_u8)0x01ULL, (intc_u8)0x01ULL).hi; + intc_u64 b = INTC_U128((intc_u16)0x0123ULL, (intc_u16)0x0123ULL).hi; + intc_u64 c = INTC_U128((intc_u32)0x01234567ULL, (intc_u32)0x01234567ULL).hi; + intc_u64 d = INTC_U128((intc_u64)0x0123456789abcdefULL, (intc_u64)0x0123456789abcdefULL).hi; + + intc_u64 e = INTC_U128((intc_u8)0x01ULL, (intc_u8)0x01ULL).lo; + intc_u64 f = INTC_U128((intc_u16)0x0123ULL, (intc_u16)0x0123ULL).lo; + intc_u64 g = INTC_U128((intc_u32)0x01234567ULL, (intc_u32)0x01234567ULL).lo; + intc_u64 h = INTC_U128((intc_u64)0x0123456789abcdefULL, (intc_u64)0x0123456789abcdefULL).lo; + + INTC_TESTS_ASSERT(a == (intc_u8)0x01ULL); + INTC_TESTS_ASSERT(b == (intc_u16)0x0123ULL); + INTC_TESTS_ASSERT(c == (intc_u32)0x01234567ULL); + INTC_TESTS_ASSERT(d == (intc_u64)0x0123456789abcdefULL); + + INTC_TESTS_ASSERT(e == (intc_u8)0x01ULL); + INTC_TESTS_ASSERT(f == (intc_u16)0x0123ULL); + INTC_TESTS_ASSERT(g == (intc_u32)0x01234567ULL); + INTC_TESTS_ASSERT(h == (intc_u64)0x0123456789abcdefULL); + INTC_TESTS_END; + } + } + + printf("\n div.cpp\n"); + { + { + INTC_TESTS_BEGIN("Arithmetic.divide"); + struct intc_u128 const big_val = INTC_U64_TO_U128(0xfedbca9876543210ULL); + struct intc_u128 const small_val = INTC_U64_TO_U128(0xffffULL); + struct intc_u128 const res_val = INTC_U64_TO_U128(0xfedcc9753fc9ULL); + + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_div(small_val, small_val), INTC_U64_TO_U128(1))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_div(small_val, big_val), INTC_U64_TO_U128(0))); + + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_div(big_val, big_val), INTC_U64_TO_U128(1))); + + // TODO(dqn): How do we want to do this ... + // EXPECT_THROW(uint128_t(1) / uint128_t(0), std::domain_error); + INTC_TESTS_END; + } + + { + INTC_TESTS_BEGIN("External.divide"); + bool t = true; + bool f = false; + intc_u8 u8 = 0xaaULL; + intc_u16 u16 = 0xaaaaULL; + intc_u32 u32 = 0xaaaaaaaaULL; + intc_u64 u64 = 0xaaaaaaaaaaaaaaaaULL; + + struct intc_u128 const val = INTC_U64_TO_U128(0x7bULL); + + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_div(INTC_U64_TO_U128(t) , val), INTC_U64_TO_U128(false))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_div(INTC_U64_TO_U128(f) , val), INTC_U64_TO_U128(false))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_div(INTC_U64_TO_U128(u8), val), INTC_U64_TO_U128(0x1ULL))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_div(INTC_U64_TO_U128(u16), val), INTC_U64_TO_U128(0x163ULL))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_div(INTC_U64_TO_U128(u32), val), INTC_U64_TO_U128(0x163356bULL))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_div(INTC_U64_TO_U128(u64), val), INTC_U64_TO_U128(0x163356b88ac0de0ULL))); + + INTC_TESTS_ASSERT((intc_u8)(u8 /= intc_u128_as_u8(val)) == (intc_u8)0x1ULL); + INTC_TESTS_ASSERT((intc_u16)(u16 /= intc_u128_as_u16(val)) == (intc_u16)0x163ULL); + INTC_TESTS_ASSERT((intc_u32)(u32 /= intc_u128_as_u32(val)) == (intc_u32)0x163356bULL); + INTC_TESTS_ASSERT((intc_u64)(u64 /= intc_u128_as_u64(val)) == (intc_u64)0x163356b88ac0de0ULL); + INTC_TESTS_END; + } + } + + printf("\n equals.cpp\n"); + { + { + INTC_TESTS_BEGIN("Comparison.equals"); + INTC_TESTS_ASSERT(intc_u128_eq(INTC_U64_TO_U128(0xdeadbeefULL), INTC_U64_TO_U128(0xdeadbeefULL))); + INTC_TESTS_ASSERT(!intc_u128_eq(INTC_U64_TO_U128(0xdeadbeefULL), INTC_U64_TO_U128(0xfee1baadULL))); + INTC_TESTS_END; + } + } + + printf("\n fix.cpp\n"); + { + { + INTC_TESTS_BEGIN("Arithmetic.increment"); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_add_u64(INTC_U128_ZERO, 1), INTC_U64_TO_U128(1))); + INTC_TESTS_END; + } + + { + INTC_TESTS_BEGIN("Arithmetic.decrement"); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_sub_u64(INTC_U128_ZERO, 1), INTC_U128(0xffffffffffffffffULL, 0xffffffffffffffffULL))); + INTC_TESTS_END; + } + } + + printf("\n functions.cpp\n"); + { + { + INTC_TESTS_BEGIN("Function.str"); + int const leading_zeros = 5; // number of leading 0s + + // make sure all of the test strings create the ASCII version of the string + struct intc_u128 const original = INTC_U64_TO_U128(2216002924); + for (int test_index = 0; test_index < sizeof(INTC_TESTS_STRING_BASE_TESTS)/sizeof(INTC_TESTS_STRING_BASE_TESTS[0]); test_index++) + { + struct intc_base_to_string const *test_entry = INTC_TESTS_STRING_BASE_TESTS + test_index; + struct intc_u128_string output = intc_u128_str(original, test_entry->base, 0 /*separate_every_n_chars*/, ' ' /*separate_ch*/); + INTC_TESTS_ASSERT_MSG(strcmp(output.str, test_entry->expect) == 0, + "output: %s\n" + "expect: %s\n", + output.str, + test_entry->expect); + } + INTC_TESTS_END; + } + } + + printf("\n gt.cpp\n"); + { + { + INTC_TESTS_BEGIN("Comparison.greater_than"); + struct intc_u128 const big = INTC_U128(0xffffffffffffffffULL, 0xffffffffffffffffULL); + struct intc_u128 const small = INTC_U128(0x0000000000000000ULL, 0x0000000000000000ULL); + + INTC_TESTS_ASSERT(intc_u128_gt(small, small) == false); + INTC_TESTS_ASSERT(intc_u128_gt(small, big) == false); + + INTC_TESTS_ASSERT(intc_u128_gt(big, small) == true); + INTC_TESTS_ASSERT(intc_u128_gt(big, big) == false); + INTC_TESTS_END; + } + + { + INTC_TESTS_BEGIN("External.greater_than"); + for (int index = 0; + index < sizeof(INTC_TESTS_MAX_UNSIGNED_VALUES)/sizeof(INTC_TESTS_MAX_UNSIGNED_VALUES[0]); + index++) + { + struct intc_u128 const small = INTC_U128_ZERO; + struct intc_u128 const big = INTC_U64_TO_U128(INTC_TESTS_MAX_UNSIGNED_VALUES[index]); + + INTC_TESTS_ASSERT(intc_u128_gt(small, small) == false); + INTC_TESTS_ASSERT(intc_u128_gt(small, big) == false); + + INTC_TESTS_ASSERT(intc_u128_gt(big, small) == true); + INTC_TESTS_ASSERT(intc_u128_gt(big, big) == false); + } + INTC_TESTS_END; + } + } + + printf("\n gte.cpp\n"); + { + { + INTC_TESTS_BEGIN("Comparison.greater_than_or_equals"); + struct intc_u128 const big = INTC_U128(0xffffffffffffffffULL, 0xffffffffffffffffULL); + struct intc_u128 const small = INTC_U128(0x0000000000000000ULL, 0x0000000000000000ULL); + + INTC_TESTS_ASSERT(intc_u128_gt_eq(small, small) == true); + INTC_TESTS_ASSERT(intc_u128_gt_eq(small, big) == false); + + INTC_TESTS_ASSERT(intc_u128_gt_eq(big, small) == true); + INTC_TESTS_ASSERT(intc_u128_gt_eq(big, big) == true); + INTC_TESTS_END; + } + + { + INTC_TESTS_BEGIN("External.greater_than_or_equals"); + for (int index = 0; + index < sizeof(INTC_TESTS_MAX_UNSIGNED_VALUES)/sizeof(INTC_TESTS_MAX_UNSIGNED_VALUES[0]); + index++) + { + struct intc_u128 const small = INTC_U128_ZERO; + struct intc_u128 const big = INTC_U64_TO_U128(INTC_TESTS_MAX_UNSIGNED_VALUES[index]); + + INTC_TESTS_ASSERT(intc_u128_gt_eq(small, small) == true); + INTC_TESTS_ASSERT(intc_u128_gt_eq(small, big) == false); + + INTC_TESTS_ASSERT(intc_u128_gt_eq(big, small) == true); + INTC_TESTS_ASSERT(intc_u128_gt_eq(big, big) == true); + } + INTC_TESTS_END; + } + } + + printf("\n invert.cpp\n"); + { + { + INTC_TESTS_BEGIN("BitWise.invert"); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_negate(INTC_U128(0x0000000000000000ULL, 0x0000000000000000ULL)), INTC_U128(0xffffffffffffffffULL, 0xffffffffffffffffULL))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_negate(INTC_U128(0x0000000000000000ULL, 0xffffffffffffffffULL)), INTC_U128(0xffffffffffffffffULL, 0x0000000000000000ULL))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_negate(INTC_U128(0xffffffffffffffffULL, 0xffffffffffffffffULL)), INTC_U128(0x0000000000000000ULL, 0x0000000000000000ULL))); + INTC_TESTS_END; + } + } + + printf("\n leftshift.cpp\n"); + { + { + INTC_TESTS_BEGIN("BitShift.left"); + // operator<< + struct intc_u128 val = INTC_U64_TO_U128(0x1); + intc_u64 exp_val = 1; + for(int i = 0; i < 64; i++){ + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_lshift(val, i), INTC_U64_TO_U128(exp_val << i))); + } + + struct intc_u128 zero = INTC_U128_ZERO; + for (int i = 0; i < 64; i++) + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_lshift(zero, i), INTC_U128_ZERO)); + INTC_TESTS_END; + } + + { + INTC_TESTS_BEGIN("External.shift_left"); + bool t = true; + bool f = false; + intc_u8 u8 = 0xffULL; + intc_u16 u16 = 0xffffULL; + intc_u32 u32 = 0xffffffffULL; + intc_u64 u64 = 0xffffffffffffffffULL; + struct intc_u128 const u128 = INTC_U128(0xffffffffffffffffULL, 0xffffffffffffffffULL); + + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_lshift(INTC_U64_TO_U128(u8), 7), INTC_U64_TO_U128(0x7f80ULL))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_lshift(INTC_U64_TO_U128(u16), 15), INTC_U64_TO_U128(0x7fff8000ULL))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_lshift(INTC_U64_TO_U128(u32), 31), INTC_U64_TO_U128(0x7fffffff80000000ULL))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_lshift(INTC_U64_TO_U128(u64), 63), INTC_U128(0x8000000000000000ULL, 0x7fffffffffffffffULL))); + INTC_TESTS_END; + } + } + + printf("\n lt.cpp\n"); + { + { + INTC_TESTS_BEGIN("Comparison.less_than"); + struct intc_u128 const big = INTC_U128(0xffffffffffffffffULL, 0xffffffffffffffffULL); + struct intc_u128 const small = INTC_U128(0x0000000000000000ULL, 0x0000000000000000ULL); + + INTC_TESTS_ASSERT(intc_u128_lt(small, small) == false); + INTC_TESTS_ASSERT(intc_u128_lt(small, big) == true); + + INTC_TESTS_ASSERT(intc_u128_lt(big, small) == false); + INTC_TESTS_ASSERT(intc_u128_lt(big, big) == false); + INTC_TESTS_END; + } + + { + INTC_TESTS_BEGIN("External.less_than"); + for (int index = 0; + index < sizeof(INTC_TESTS_MAX_UNSIGNED_VALUES)/sizeof(INTC_TESTS_MAX_UNSIGNED_VALUES[0]); + index++) + { + struct intc_u128 const small = INTC_U128_ZERO; + struct intc_u128 const big = INTC_U64_TO_U128(INTC_TESTS_MAX_UNSIGNED_VALUES[index]); + + INTC_TESTS_ASSERT(intc_u128_lt(small, small) == false); + INTC_TESTS_ASSERT(intc_u128_lt(small, big) == true); + + INTC_TESTS_ASSERT(intc_u128_lt(big, small) == false); + INTC_TESTS_ASSERT(intc_u128_lt(big, big) == false); + } + INTC_TESTS_END; + } + } + + printf("\n lte.cpp\n"); + { + { + INTC_TESTS_BEGIN("Comparison.less_than_or_equals"); + struct intc_u128 const big = INTC_U128(0xffffffffffffffffULL, 0xffffffffffffffffULL); + struct intc_u128 const small = INTC_U128(0x0000000000000000ULL, 0x0000000000000000ULL); + + INTC_TESTS_ASSERT(intc_u128_lt_eq(small, small) == true); + INTC_TESTS_ASSERT(intc_u128_lt_eq(small, big) == true); + + INTC_TESTS_ASSERT(intc_u128_lt_eq(big, small) == false); + INTC_TESTS_ASSERT(intc_u128_lt_eq(big, big) == true); + INTC_TESTS_END; + } + + { + INTC_TESTS_BEGIN("External.less_than_or_equals"); + for (int index = 0; + index < sizeof(INTC_TESTS_MAX_UNSIGNED_VALUES)/sizeof(INTC_TESTS_MAX_UNSIGNED_VALUES[0]); + index++) + { + struct intc_u128 const small = INTC_U128_ZERO; + struct intc_u128 const big = INTC_U64_TO_U128(INTC_TESTS_MAX_UNSIGNED_VALUES[index]); + + INTC_TESTS_ASSERT(intc_u128_lt_eq(small, small) == true); + INTC_TESTS_ASSERT(intc_u128_lt_eq(small, big) == true); + + INTC_TESTS_ASSERT(intc_u128_lt_eq(big, small) == false); + INTC_TESTS_ASSERT(intc_u128_lt_eq(big, big) == true); + } + INTC_TESTS_END; + } + } + + printf("\n mod.cpp\n"); + { + { + INTC_TESTS_BEGIN("Arithmetic.modulo"); + // has remainder + struct intc_u128 const val = INTC_U128(0xffffffffffffffffULL, 0xffffffffffffffffULL); + struct intc_u128 const val_mod = INTC_U64_TO_U128(0xfedcba9876543210ULL); + + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_mod(val, val_mod), INTC_U64_TO_U128(0x7f598f328cc265bfULL))); + + // no remainder + struct intc_u128 const val_0 = INTC_U128(0, 0xfedcba9876543210); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_mod(val_0, val_mod), INTC_U128_ZERO)); + + // TODO(dqn): Add a way to catch divide by 0 assert nicely? Maybe? + // mod 0 + // EXPECT_THROW(uint128_t(1) % uint128_t(0), std::domain_error); + INTC_TESTS_END; + } + + { + INTC_TESTS_BEGIN("External.modulo"); + bool t = true; + bool f = false; + intc_u8 u8 = 0xaaULL; + intc_u16 u16 = 0xaaaaULL; + intc_u32 u32 = 0xaaaaaaaaULL; + intc_u64 u64 = 0xaaaaaaaaaaaaaaaaULL; + struct intc_u128 const u128 = INTC_U128(0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL); + struct intc_u128 const val = INTC_U64_TO_U128(0xd03ULL); // prime + + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_mod(INTC_U64_TO_U128(t), val), INTC_U64_TO_U128(true))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_mod(INTC_U64_TO_U128(f), val), INTC_U64_TO_U128(false))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_mod(INTC_U64_TO_U128(u8), val), INTC_U64_TO_U128((intc_u8) 0xaaULL))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_mod(INTC_U64_TO_U128(u16), val), INTC_U64_TO_U128((intc_u16)0x183ULL))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_mod(INTC_U64_TO_U128(u32), val), INTC_U64_TO_U128((intc_u32)0x249ULL))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_mod(INTC_U64_TO_U128(u64), val), INTC_U64_TO_U128((intc_u64)0xc7fULL))); + INTC_TESTS_END; + } + } + + printf("\n mult.cpp\n"); + { + { + INTC_TESTS_BEGIN("Arithmetic.multiply"); + struct intc_u128 const val = INTC_U64_TO_U128(0xfedbca9876543210ULL); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_mul(val, val), INTC_U128(0x010e6cd7a44a4100ULL, 0xfdb8e2bacbfe7cefULL))); + + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_mul(val, INTC_U128_ZERO), INTC_U128_ZERO)); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_mul(INTC_U128_ZERO, val), INTC_U128_ZERO)); + + struct intc_u128 const one = INTC_U64_TO_U128(1); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_mul(val, one), val)); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_mul(one, val), val)); + INTC_TESTS_END; + } + + { + INTC_TESTS_BEGIN("External.multiply"); + bool t = true; + bool f = false; + intc_u8 u8 = 0xaaULL; + intc_u16 u16 = 0xaaaaULL; + intc_u32 u32 = 0xaaaaaaaaULL; + intc_u64 u64 = 0xaaaaaaaaaaaaaaaaULL; + struct intc_u128 const val = INTC_U128(0xf0f0f0f0f0f0f0f0ULL, 0xf0f0f0f0f0f0f0f0ULL); + + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_mul(INTC_U64_TO_U128(t), val), INTC_U128(0xf0f0f0f0f0f0f0f0ULL, 0xf0f0f0f0f0f0f0f0ULL))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_mul(INTC_U64_TO_U128(f), val), INTC_U128(0x0000000000000000ULL, 0x0000000000000000ULL))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_mul(INTC_U64_TO_U128(u8), val), INTC_U128(0xffffffffffffff60ULL, 0xffffffffffffffffULL))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_mul(INTC_U64_TO_U128(u16), val), INTC_U128(0xffffffffffff5f60ULL, 0xffffffffffffffffULL))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_mul(INTC_U64_TO_U128(u32), val), INTC_U128(0xffffffff5f5f5f60ULL, 0xffffffffffffffffULL))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_mul(INTC_U64_TO_U128(u64), val), INTC_U128(0x5f5f5f5f5f5f5f60ULL, 0xffffffffffffffffULL))); + + INTC_TESTS_ASSERT((intc_u8)(u8 * intc_u128_as_u8(val)) == (intc_u8)0x60ULL); + INTC_TESTS_ASSERT((intc_u16)(u16 * intc_u128_as_u16(val)) == (intc_u16)0x5f60ULL); + INTC_TESTS_ASSERT((intc_u32)(u32 * intc_u128_as_u32(val)) == (intc_u32)0x5f5f5f60ULL); + INTC_TESTS_ASSERT((intc_u64)(u64 * intc_u128_as_u64(val)) == (intc_u64)0x5f5f5f5f5f5f5f60ULL); + INTC_TESTS_END; + } + } + + printf("\n notequals.cpp\n"); + { + { + INTC_TESTS_BEGIN("Comparison.not_equals"); + INTC_TESTS_ASSERT(intc_u128_neq(INTC_U64_TO_U128(0xdeadbeefULL), INTC_U64_TO_U128(0xdeadbeefULL)) == false); + INTC_TESTS_ASSERT(intc_u128_neq(INTC_U64_TO_U128(0xdeadbeefULL), INTC_U64_TO_U128(0xfee1baadULL)) == true); + INTC_TESTS_END; + } + + { + INTC_TESTS_BEGIN("External.not_equals"); + bool const t = true; + bool const f = false; + intc_u8 const u8 = 0xaaULL; + intc_u16 const u16 = 0xaaaaULL; + intc_u32 const u32 = 0xaaaaaaaaULL; + intc_u64 const u64 = 0xaaaaaaaaaaaaaaaaULL; + + INTC_TESTS_ASSERT(intc_u128_neq(INTC_U64_TO_U128(t) , INTC_U64_TO_U128(f)) == true); + INTC_TESTS_ASSERT(intc_u128_neq(INTC_U64_TO_U128(f) , INTC_U64_TO_U128(t)) == true); + INTC_TESTS_ASSERT(intc_u128_neq(INTC_U64_TO_U128(u8) , INTC_U64_TO_U128(u64)) == true); + INTC_TESTS_ASSERT(intc_u128_neq(INTC_U64_TO_U128(u16), INTC_U64_TO_U128(u32)) == true); + INTC_TESTS_ASSERT(intc_u128_neq(INTC_U64_TO_U128(u32), INTC_U64_TO_U128(u16)) == true); + INTC_TESTS_ASSERT(intc_u128_neq(INTC_U64_TO_U128(u64), INTC_U64_TO_U128(u8)) == true); + + INTC_TESTS_ASSERT(intc_u128_neq(INTC_U64_TO_U128(t) , INTC_U64_TO_U128(t)) == false); + INTC_TESTS_ASSERT(intc_u128_neq(INTC_U64_TO_U128(f) , INTC_U64_TO_U128(f)) == false); + INTC_TESTS_ASSERT(intc_u128_neq(INTC_U64_TO_U128(u8) , INTC_U64_TO_U128(u8)) == false); + INTC_TESTS_ASSERT(intc_u128_neq(INTC_U64_TO_U128(u16), INTC_U64_TO_U128(u16)) == false); + INTC_TESTS_ASSERT(intc_u128_neq(INTC_U64_TO_U128(u32), INTC_U64_TO_U128(u32)) == false); + INTC_TESTS_ASSERT(intc_u128_neq(INTC_U64_TO_U128(u64), INTC_U64_TO_U128(u64)) == false); + INTC_TESTS_END; + } + } + + printf("\n or.cpp\n"); + { + { + INTC_TESTS_BEGIN("BitWise.or"); + struct intc_u128 const t = INTC_U64_TO_U128((bool) true); + struct intc_u128 const f = INTC_U64_TO_U128((bool) false); + struct intc_u128 const u8 = INTC_U64_TO_U128((intc_u8) 0xaaULL); + struct intc_u128 const u16 = INTC_U64_TO_U128((intc_u16) 0xaaaaULL); + struct intc_u128 const u32 = INTC_U64_TO_U128((intc_u32) 0xaaaaaaaaULL); + struct intc_u128 const u64 = INTC_U64_TO_U128((intc_u64) 0xaaaaaaaaaaaaaaaaULL); + struct intc_u128 const val = INTC_U128(0xf0f0f0f0f0f0f0f0ULL, 0xf0f0f0f0f0f0f0f0ULL); + + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_or(t , val), INTC_U128(0xf0f0f0f0f0f0f0f1ULL, 0xf0f0f0f0f0f0f0f0ULL))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_or(f , val), INTC_U128(0xf0f0f0f0f0f0f0f0ULL, 0xf0f0f0f0f0f0f0f0ULL))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_or(u8 , val), INTC_U128(0xf0f0f0f0f0f0f0faULL, 0xf0f0f0f0f0f0f0f0ULL))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_or(u16, val), INTC_U128(0xf0f0f0f0f0f0fafaULL, 0xf0f0f0f0f0f0f0f0ULL))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_or(u32, val), INTC_U128(0xf0f0f0f0fafafafaULL, 0xf0f0f0f0f0f0f0f0ULL))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_or(u64, val), INTC_U128(0xfafafafafafafafaULL, 0xf0f0f0f0f0f0f0f0ULL))); + + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_or(INTC_U128_ZERO, val), val)); + INTC_TESTS_END; + } + + { + INTC_TESTS_BEGIN("External.or"); + bool t = true; + bool f = false; + intc_u8 u8 = 0xaa; + intc_u16 u16 = 0xaaaa; + intc_u32 u32 = 0xaaaaaaaaULL; + intc_u64 u64 = 0xaaaaaaaaaaaaaaaaULL; + struct intc_u128 const val = INTC_U128(0xf0f0f0f0f0f0f0f0ULL, 0xf0f0f0f0f0f0f0f0ULL); + + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_or(INTC_U64_TO_U128(t) , val), INTC_U128(0xf0f0f0f0f0f0f0f1ULL, 0xf0f0f0f0f0f0f0f0ULL))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_or(INTC_U64_TO_U128(f) , val), INTC_U128(0xf0f0f0f0f0f0f0f0ULL, 0xf0f0f0f0f0f0f0f0ULL))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_or(INTC_U64_TO_U128(u8) , val), INTC_U128(0xf0f0f0f0f0f0f0faULL, 0xf0f0f0f0f0f0f0f0ULL))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_or(INTC_U64_TO_U128(u16), val), INTC_U128(0xf0f0f0f0f0f0fafaULL, 0xf0f0f0f0f0f0f0f0ULL))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_or(INTC_U64_TO_U128(u32), val), INTC_U128(0xf0f0f0f0fafafafaULL, 0xf0f0f0f0f0f0f0f0ULL))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_or(INTC_U64_TO_U128(u64), val), INTC_U128(0xfafafafafafafafaULL, 0xf0f0f0f0f0f0f0f0ULL))); + INTC_TESTS_END; + } + } + + printf("\n rightshift.cpp\n"); + { + { + INTC_TESTS_BEGIN("BitShift.right"); + // operator>> + struct intc_u128 val = INTC_U64_TO_U128(0xffffffffffffffffULL); + intc_u64 exp = 0xffffffffffffffffULL; + + for(int i = 0; i < 64; i++){ + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_rshift(val, i), INTC_U64_TO_U128(exp >> i))); + } + + struct intc_u128 zero = INTC_U128_ZERO; + for (int i = 0; i < 64; i++) + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_rshift(zero, i), INTC_U128_ZERO)); + INTC_TESTS_END; + } + + { + INTC_TESTS_BEGIN("External.shift_left"); + bool t = true; + bool f = false; + intc_u8 u8 = 0xffULL; + intc_u16 u16 = 0xffffULL; + intc_u32 u32 = 0xffffffffULL; + intc_u64 u64 = 0xffffffffffffffffULL; + + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_rshift(INTC_U64_TO_U128(t) , 0), INTC_U64_TO_U128(1))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_rshift(INTC_U64_TO_U128(f) , 0), INTC_U128_ZERO)); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_rshift(INTC_U64_TO_U128(u8), 0), INTC_U64_TO_U128(u8))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_rshift(INTC_U64_TO_U128(u16), 0), INTC_U64_TO_U128(u16))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_rshift(INTC_U64_TO_U128(u32), 0), INTC_U64_TO_U128(u32))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_rshift(INTC_U64_TO_U128(u64), 0), INTC_U64_TO_U128(u64))); + + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_rshift(INTC_U64_TO_U128(t), 1), INTC_U64_TO_U128((intc_u64)t >> 1))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_rshift(INTC_U64_TO_U128(f), 1), INTC_U64_TO_U128((intc_u64)f >> 1))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_rshift(INTC_U64_TO_U128(u8), 1), INTC_U64_TO_U128((intc_u64)u8 >> 1))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_rshift(INTC_U64_TO_U128(u16), 1), INTC_U64_TO_U128((intc_u64)u16 >> 1))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_rshift(INTC_U64_TO_U128(u32), 1), INTC_U64_TO_U128((intc_u64)u32 >> 1))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_rshift(INTC_U64_TO_U128(u64), 1), INTC_U64_TO_U128((intc_u64)u64 >> 1))); + + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_rshift(INTC_U64_TO_U128(u8), 7), INTC_U64_TO_U128(1))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_rshift(INTC_U64_TO_U128(u16), 15), INTC_U64_TO_U128(1))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_rshift(INTC_U64_TO_U128(u32), 31), INTC_U64_TO_U128(1))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_rshift(INTC_U64_TO_U128(u64), 63), INTC_U64_TO_U128(1))); + INTC_TESTS_END; + } + } + + printf("\n sub.cpp\n"); + { + { + INTC_TESTS_BEGIN("Arithmetic.subtract"); + struct intc_u128 const big = INTC_U128(0xffffffffffffffffULL, 0xffffffffffffffffULL); + struct intc_u128 const small = INTC_U128(0x0000000000000001ULL, 0x0000000000000000ULL); + + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_sub(small, small), INTC_U128_ZERO)); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_sub(small, big), INTC_U128(0x0000000000000002ULL, 0x0000000000000000ULL))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_sub(big , small), INTC_U128(0xfffffffffffffffeULL, 0xffffffffffffffffULL))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_sub(big , big), INTC_U128_ZERO)); + INTC_TESTS_END; + } + + { + INTC_TESTS_BEGIN("External.subtract"); + bool t = true; + bool f = false; + intc_u8 u8 = 0xaaULL; + intc_u16 u16 = 0xaaaaULL; + intc_u32 u32 = 0xaaaaaaaaULL; + intc_u64 u64 = 0xaaaaaaaaaaaaaaaaULL; + struct intc_u128 val = INTC_U128(0xf0f0f0f0f0f0f0f0ULL, 0xf0f0f0f0f0f0f0f0ULL); + + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_sub(INTC_U64_TO_U128(t) , val), INTC_U128(0x0f0f0f0f0f0f0f11ULL, 0x0f0f0f0f0f0f0f0fULL))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_sub(INTC_U64_TO_U128(f) , val), INTC_U128(0x0f0f0f0f0f0f0f10ULL, 0x0f0f0f0f0f0f0f0fULL))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_sub(INTC_U64_TO_U128(u8) , val), INTC_U128(0x0f0f0f0f0f0f0fbaULL, 0x0f0f0f0f0f0f0f0fULL))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_sub(INTC_U64_TO_U128(u16), val), INTC_U128(0x0f0f0f0f0f0fb9baULL, 0x0f0f0f0f0f0f0f0fULL))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_sub(INTC_U64_TO_U128(u32), val), INTC_U128(0x0f0f0f0fb9b9b9baULL, 0x0f0f0f0f0f0f0f0fULL))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_sub(INTC_U64_TO_U128(u64), val), INTC_U128(0xb9b9b9b9b9b9b9baULL, 0x0f0f0f0f0f0f0f0fULL))); + INTC_TESTS_END; + } + } + + printf("\n typecast.cpp\n"); + { + { + INTC_TESTS_BEGIN("Typecast.all"); + struct intc_u128 const val = INTC_U128(0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL); + INTC_TESTS_ASSERT(intc_u128_as_bool(INTC_U64_TO_U128(true)) == true); + INTC_TESTS_ASSERT(intc_u128_as_bool(INTC_U64_TO_U128(false)) == false); + INTC_TESTS_ASSERT(intc_u128_as_u8(val) == (intc_u8)0xaaULL); + INTC_TESTS_ASSERT(intc_u128_as_u16(val) == (intc_u16)0xaaaaULL); + INTC_TESTS_ASSERT(intc_u128_as_u32(val) == (intc_u32)0xaaaaaaaaULL); + INTC_TESTS_ASSERT(intc_u128_as_u64(val) == (intc_u64)0xaaaaaaaaaaaaaaaaULL); + INTC_TESTS_END; + } + } + + printf("\n xor.cpp\n"); + { + { + INTC_TESTS_BEGIN("BitWise.xor"); + struct intc_u128 t = INTC_U64_TO_U128((bool) true); + struct intc_u128 f = INTC_U64_TO_U128((bool) false); + struct intc_u128 u8 = INTC_U64_TO_U128((intc_u8) 0xaaULL); + struct intc_u128 u16 = INTC_U64_TO_U128((intc_u16) 0xaaaaULL); + struct intc_u128 u32 = INTC_U64_TO_U128((intc_u32) 0xaaaaaaaaULL); + struct intc_u128 u64 = INTC_U64_TO_U128((intc_u64) 0xaaaaaaaaaaaaaaaa); + struct intc_u128 const val = INTC_U128(0xf0f0f0f0f0f0f0f0ULL, 0xf0f0f0f0f0f0f0f0ULL); + + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_xor(t , val), INTC_U128(0xf0f0f0f0f0f0f0f1ULL, 0xf0f0f0f0f0f0f0f0ULL))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_xor(f , val), INTC_U128(0xf0f0f0f0f0f0f0f0ULL, 0xf0f0f0f0f0f0f0f0ULL))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_xor(u8 , val), INTC_U128(0xf0f0f0f0f0f0f05aULL, 0xf0f0f0f0f0f0f0f0ULL))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_xor(u16, val), INTC_U128(0xf0f0f0f0f0f05a5aULL, 0xf0f0f0f0f0f0f0f0ULL))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_xor(u32, val), INTC_U128(0xf0f0f0f05a5a5a5aULL, 0xf0f0f0f0f0f0f0f0ULL))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_xor(u64, val), INTC_U128(0x5a5a5a5a5a5a5a5aULL, 0xf0f0f0f0f0f0f0f0ULL))); + + // zero + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_xor(INTC_U128_ZERO, val), val)); + INTC_TESTS_END; + } + + { + INTC_TESTS_BEGIN("External.xor"); + bool t = true; + bool f = false; + intc_u8 u8 = 0xaaULL; + intc_u16 u16 = 0xaaaaULL; + intc_u32 u32 = 0xaaaaaaaaULL; + intc_u64 u64 = 0xaaaaaaaaaaaaaaaaULL; + struct intc_u128 const val = INTC_U128(0xf0f0f0f0f0f0f0f0ULL, 0xf0f0f0f0f0f0f0f0ULL); + + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_xor(INTC_U64_TO_U128(t ), val), INTC_U128(0xf0f0f0f0f0f0f0f1ULL, 0xf0f0f0f0f0f0f0f0ULL))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_xor(INTC_U64_TO_U128(f ), val), INTC_U128(0xf0f0f0f0f0f0f0f0ULL, 0xf0f0f0f0f0f0f0f0ULL))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_xor(INTC_U64_TO_U128(u8 ), val), INTC_U128(0xf0f0f0f0f0f0f05aULL, 0xf0f0f0f0f0f0f0f0ULL))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_xor(INTC_U64_TO_U128(u16), val), INTC_U128(0xf0f0f0f0f0f05a5aULL, 0xf0f0f0f0f0f0f0f0ULL))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_xor(INTC_U64_TO_U128(u32), val), INTC_U128(0xf0f0f0f05a5a5a5aULL, 0xf0f0f0f0f0f0f0f0ULL))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_xor(INTC_U64_TO_U128(u64), val), INTC_U128(0x5a5a5a5a5a5a5a5aULL, 0xf0f0f0f0f0f0f0f0ULL))); + INTC_TESTS_END; + } + } + + fputc('\n', stdout); + return result; +} + +#if !defined(INTC_NO_U256) +struct intc_test_state intc_u256_unit_tests(void) +{ + struct intc_test_state result = {0}; + printf(INTC_TESTS_COLOR_MAGENTA "intc_u256 unit tests" INTC_TESTS_COLOR_RESET); + printf("\n accessors.cpp\n"); + { + { + INTC_TESTS_BEGIN("Accessor.bits"); + struct intc_u256 value = INTC_U64_TO_U256(1); + for (int i = 0; i < 127; i++) + { + INTC_TESTS_ASSERT(intc_u256_clz(value) == (i + 1)); + value = intc_u256_lshift(value, 1); + } + + INTC_TESTS_ASSERT(intc_u256_clz(INTC_U256_ZERO) == 0); + INTC_TESTS_END; + } + + { + INTC_TESTS_BEGIN("Accessor.data"); + const struct intc_u256 value = INTC_U256(INTC_U128(0x0123456789abcdefULL, 0xfedcba9876543210ULL), INTC_U128(0x0123456789abcdefULL, 0xfedcba9876543210ULL)); + INTC_TESTS_ASSERT_MSG(value.hi.hi == 0xfedcba9876543210ULL, "hi.hi: %llx\n", value.hi.hi); + INTC_TESTS_ASSERT_MSG(value.hi.lo == 0x0123456789abcdefULL, "hi.lo: %llx\n", value.hi.lo); + INTC_TESTS_ASSERT_MSG(value.lo.hi == 0xfedcba9876543210ULL, "lo.hi: %llx\n", value.lo.hi); + INTC_TESTS_ASSERT_MSG(value.lo.lo == 0x0123456789abcdefULL, "lo.lo: %llx\n", value.lo.lo); + INTC_TESTS_END; + } + } + + printf("\n add.cpp\n"); + { + { + INTC_TESTS_BEGIN("Arithmetic.add"); + struct intc_u256 low = INTC_U256(1, 0); + struct intc_u256 high = INTC_U256(0, 1); + + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_add(low, low), INTC_U64_TO_U256(2))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_add(low, high), INTC_U256(1, 1))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_add(high, high), INTC_U256(0, 2))); + INTC_TESTS_END; + } + + { + INTC_TESTS_BEGIN("External.add"); + bool t = true; + bool f = false; + intc_u8 u8 = 0xaaULL; + intc_u16 u16 = 0xaaaaULL; + intc_u32 u32 = 0xaaaaaaaaULL; + intc_u64 u64 = 0xaaaaaaaaaaaaaaaaULL; + struct intc_u128 u128 = INTC_U128(0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL); + struct intc_u256 val = INTC_U256(INTC_U128(0xf0f0f0f0f0f0f0f0ULL, 0xf0f0f0f0f0f0f0f0ULL), INTC_U128(0xf0f0f0f0f0f0f0f0ULL, 0xf0f0f0f0f0f0f0f0ULL)); + + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_add_u64(val, t ), INTC_U256(INTC_U128(0xf0f0f0f0f0f0f0f1ULL, 0xf0f0f0f0f0f0f0f0ULL), INTC_U128(0xf0f0f0f0f0f0f0f0ULL, 0xf0f0f0f0f0f0f0f0ULL)))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_add_u64(val, f ), INTC_U256(INTC_U128(0xf0f0f0f0f0f0f0f0ULL, 0xf0f0f0f0f0f0f0f0ULL), INTC_U128(0xf0f0f0f0f0f0f0f0ULL, 0xf0f0f0f0f0f0f0f0ULL)))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_add_u64(val, u8 ), INTC_U256(INTC_U128(0xf0f0f0f0f0f0f19aULL, 0xf0f0f0f0f0f0f0f0ULL), INTC_U128(0xf0f0f0f0f0f0f0f0ULL, 0xf0f0f0f0f0f0f0f0ULL)))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_add_u64(val, u16), INTC_U256(INTC_U128(0xf0f0f0f0f0f19b9aULL, 0xf0f0f0f0f0f0f0f0ULL), INTC_U128(0xf0f0f0f0f0f0f0f0ULL, 0xf0f0f0f0f0f0f0f0ULL)))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_add_u64(val, u32), INTC_U256(INTC_U128(0xf0f0f0f19b9b9b9aULL, 0xf0f0f0f0f0f0f0f0ULL), INTC_U128(0xf0f0f0f0f0f0f0f0ULL, 0xf0f0f0f0f0f0f0f0ULL)))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_add_u64(val, u64), INTC_U256(INTC_U128(0x9b9b9b9b9b9b9b9aULL, 0xf0f0f0f0f0f0f0f1ULL), INTC_U128(0xf0f0f0f0f0f0f0f0ULL, 0xf0f0f0f0f0f0f0f0ULL)))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_add(val, INTC_U128_TO_U256(u128)), INTC_U256(INTC_U128(0x9b9b9b9b9b9b9b9aULL, 0x9b9b9b9b9b9b9b9bULL), INTC_U128(0xf0f0f0f0f0f0f0f1ULL, 0xf0f0f0f0f0f0f0f0ULL)))); + + INTC_TESTS_ASSERT((bool) (t + intc_u256_as_bool(val)) == true); + INTC_TESTS_ASSERT((bool) (f + intc_u256_as_bool(val)) == true); + INTC_TESTS_ASSERT((intc_u8) (u8 + intc_u256_as_u8 (val)) == (intc_u8) 0x9aULL); + INTC_TESTS_ASSERT((intc_u16)(u16 + intc_u256_as_u16 (val)) == (intc_u16)0x9b9aULL); + INTC_TESTS_ASSERT((intc_u32)(u32 + intc_u256_as_u32 (val)) == (intc_u32)0x9b9b9b9aULL); + INTC_TESTS_ASSERT((intc_u64)(u64 + intc_u256_as_u64 (val)) == (intc_u64)0x9b9b9b9b9b9b9b9aULL); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_add(u128, intc_u256_as_u128(val)), INTC_U128(0x9b9b9b9b9b9b9b9aULL, 0x9b9b9b9b9b9b9b9bULL))); + INTC_TESTS_END; + } + } + + printf("\n and.cpp\n"); + { + { + INTC_TESTS_BEGIN("Bitwise.and"); + const struct intc_u256 t = INTC_U64_TO_U256((bool) true); + const struct intc_u256 f = INTC_U64_TO_U256((bool) false); + const struct intc_u256 u8 = INTC_U64_TO_U256((intc_u8) 0xaaULL); + const struct intc_u256 u16 = INTC_U64_TO_U256((intc_u16) 0xaaaaULL); + const struct intc_u256 u32 = INTC_U64_TO_U256((intc_u32) 0xaaaaaaaaULL); + const struct intc_u256 u64 = INTC_U64_TO_U256((intc_u64) 0xaaaaaaaaaaaaaaaaULL); + const struct intc_u256 val = INTC_U128_TO_U256(INTC_U128(0xf0f0f0f0f0f0f0f0ULL, 0xf0f0f0f0f0f0f0f0ULL)); + + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_and(t, val), INTC_U64_TO_U256(0))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_and(f, val), INTC_U64_TO_U256(0))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_and(u8, val), INTC_U64_TO_U256(0xa0ULL))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_and(u16, val), INTC_U64_TO_U256(0xa0a0ULL))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_and(u32, val), INTC_U64_TO_U256(0xa0a0a0a0ULL))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_and(u64, val), INTC_U64_TO_U256(0xa0a0a0a0a0a0a0a0ULL))); + INTC_TESTS_END; + } + + { + INTC_TESTS_BEGIN("External.and"); + bool t = true; + bool f = false; + intc_u8 u8 = 0xaaULL; + intc_u16 u16 = 0xaaaaULL; + intc_u32 u32 = 0xaaaaaaaaULL; + intc_u64 u64 = 0xaaaaaaaaaaaaaaaaULL; + const struct intc_u256 val = INTC_U256(0xf0f0f0f0f0f0f0f0ULL, 0xf0f0f0f0f0f0f0f0ULL); + + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_and(INTC_U64_TO_U256(t ), val), INTC_U64_TO_U256(0))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_and(INTC_U64_TO_U256(f ), val), INTC_U64_TO_U256(0))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_and(INTC_U64_TO_U256(u8 ), val), INTC_U64_TO_U256(0xa0ULL))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_and(INTC_U64_TO_U256(u16), val), INTC_U64_TO_U256(0xa0a0ULL))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_and(INTC_U64_TO_U256(u32), val), INTC_U64_TO_U256(0xa0a0a0a0ULL))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_and(INTC_U64_TO_U256(u64), val), INTC_U64_TO_U256(0xa0a0a0a0a0a0a0a0ULL))); + + // TODO: Why is this test result different from calccrypto and intc? + // + // true &= (0xF0F0F0 ...) == true? + // + // Original test line was + // + // EXPECT_EQ(t &= val, false); + // + INTC_TESTS_ASSERT((bool) (t &= intc_u256_as_bool(val)) == true); + + INTC_TESTS_ASSERT((bool) (f &= intc_u256_as_bool(val)) == false); + INTC_TESTS_ASSERT((intc_u8) (u8 &= intc_u256_as_u8 (val)) == (intc_u8) 0xa0ULL); + INTC_TESTS_ASSERT((intc_u16)(u16 &= intc_u256_as_u16 (val)) == (intc_u16)0xa0a0ULL); + INTC_TESTS_ASSERT((intc_u32)(u32 &= intc_u256_as_u32 (val)) == (intc_u32)0xa0a0a0a0ULL); + INTC_TESTS_ASSERT((intc_u64)(u64 &= intc_u256_as_u64 (val)) == (intc_u64)0xa0a0a0a0a0a0a0a0ULL); + + // zero + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_and(INTC_U256_ZERO, val), INTC_U256_ZERO)); + INTC_TESTS_END; + } + } + + printf("\n assignment.cpp\n"); + { + { + INTC_TESTS_BEGIN("Assignment.all"); + const struct intc_u256 t_1 = INTC_U64_TO_U256(true); + const struct intc_u256 f_1 = INTC_U64_TO_U256(false); + const struct intc_u256 u8_1 = INTC_U64_TO_U256(0x01); + const struct intc_u256 u16_1 = INTC_U64_TO_U256(0x0123); + const struct intc_u256 u32_1 = INTC_U64_TO_U256(0x01234567); + const struct intc_u256 u64_1 = INTC_U64_TO_U256(0x0123456789abcdef); + + struct intc_u256 t_2 = INTC_U64_TO_U256(0); + struct intc_u256 f_2 = INTC_U64_TO_U256(0); + struct intc_u256 u8_2 = INTC_U64_TO_U256(0); + struct intc_u256 u16_2 = INTC_U64_TO_U256(0); + struct intc_u256 u32_2 = INTC_U64_TO_U256(0); + struct intc_u256 u64_2 = INTC_U64_TO_U256(0); + + t_2 = t_1; + f_2 = f_1; + u8_2 = u8_1; + u16_2 = u16_1; + u32_2 = u32_1; + u64_2 = u64_1; + + INTC_TESTS_ASSERT(intc_u256_eq(t_1, t_2)); + INTC_TESTS_ASSERT(intc_u256_eq(f_1, f_2)); + INTC_TESTS_ASSERT(intc_u256_eq(u8_1, u8_2)); + INTC_TESTS_ASSERT(intc_u256_eq(u16_1, u16_2)); + INTC_TESTS_ASSERT(intc_u256_eq(u32_1, u32_2)); + INTC_TESTS_ASSERT(intc_u256_eq(u64_1, u64_2)); + INTC_TESTS_END; + } + } + + printf("\n constructor.cpp\n"); + { + { + INTC_TESTS_BEGIN("Constructor.standard"); + struct intc_u256 value = INTC_U64_TO_U256(0x0123456789abcdefULL); + const struct intc_u256 original = value; + + INTC_TESTS_ASSERT(intc_u256_eq(value, original)); + INTC_TESTS_ASSERT(intc_u256_eq(value, INTC_U64_TO_U256(0x0123456789abcdefULL))); + INTC_TESTS_END; + } + + { + INTC_TESTS_BEGIN("Constructor.string"); + struct intc_u256 val; + INTC_TESTS_ASSERT(intc_u256_init_cstring("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", -1 /*size*/, &val)); + INTC_TESTS_ASSERT_MSG(intc_u256_eq(val, INTC_U256_MAX), + "val: %s\n" + "expect: %s\n", + intc_u256_readable_hex_str(val).str, + intc_u256_readable_hex_str(INTC_U256_MAX).str); + + INTC_TESTS_ASSERT(intc_u256_init_cstring("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", -1 /*size*/, &val)); + INTC_TESTS_ASSERT_MSG(intc_u256_eq(val, INTC_U256_MAX), + "val: %s\n" + "expect: %s\n", + intc_u256_readable_hex_str(val).str, + intc_u256_readable_hex_str(INTC_U256_MAX).str); + + INTC_TESTS_ASSERT(intc_u256_init_cstring("0x0", -1 /*size*/, &val)); + INTC_TESTS_ASSERT_MSG(intc_u256_eq(val, INTC_U256_ZERO), "val: %s\n", intc_u256_readable_hex_str(val).str); + + INTC_TESTS_ASSERT(intc_u256_init_cstring("0x0", -1 /*size*/, &val)); + INTC_TESTS_ASSERT_MSG(intc_u256_eq(val, INTC_U256_ZERO), "val: %s\n", intc_u256_readable_hex_str(val).str); + + struct intc_u256 expect = INTC_U64_TO_U256(0x0123456789abcdefULL); + INTC_TESTS_ASSERT(intc_u256_init_cstring("0x0123456789abcdef", -1 /*size*/, &val)); + INTC_TESTS_ASSERT_MSG(intc_u256_eq(val, expect), + "val: %s\n" + "expect: %s\n", + intc_u256_readable_hex_str(val).str, + intc_u256_readable_hex_str(expect).str); + INTC_TESTS_END; + } + + { + INTC_TESTS_BEGIN("Constructor.base_string"); + struct intc_u256 val; + INTC_TESTS_ASSERT(intc_u256_init_cstring_base("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", -1 /*size*/, 16 /*base*/, &val)); + INTC_TESTS_ASSERT_MSG(intc_u256_eq(val, INTC_U256_MAX), + "val: %s\n" + "expect: %s\n", + intc_u256_readable_hex_str(val).str, + intc_u256_readable_hex_str(INTC_U256_MAX).str); + + INTC_TESTS_ASSERT(intc_u256_init_cstring_base("115792089237316195423570985008687907853269984665640564039457584007913129639935", -1 /*size*/, 10 /*base*/, &val)); + INTC_TESTS_ASSERT_MSG(intc_u256_eq(val, INTC_U256_MAX), + "val: %s\n" + "expect: %s\n", + intc_u256_readable_hex_str(val).str, + intc_u256_readable_hex_str(INTC_U256_MAX).str); + + INTC_TESTS_ASSERT(intc_u256_init_cstring_base("1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", -1 /*size*/, 2 /*base*/, &val)); + INTC_TESTS_ASSERT_MSG(intc_u256_eq(val, INTC_U256_MAX), + "val: %s\n" + "expect: %s\n", + intc_u256_readable_hex_str(val).str, + intc_u256_readable_hex_str(INTC_U256_MAX).str); + + INTC_TESTS_ASSERT(intc_u256_init_cstring_base("0", -1 /*size*/, 10 /*base*/, &val)); + INTC_TESTS_ASSERT(intc_u256_eq(val, INTC_U256_ZERO)); + + INTC_TESTS_ASSERT(intc_u256_init_cstring_base("0x0123456789abcdef", -1 /*size*/, 16 /*base*/, &val)); + INTC_TESTS_ASSERT(intc_u256_eq(val, INTC_U64_TO_U256(0x0123456789abcdefULL))); + + INTC_TESTS_ASSERT(intc_u256_init_cstring_base("755", -1 /*size*/, 8 /*base*/, &val)); + INTC_TESTS_ASSERT(intc_u256_eq(val, INTC_U64_TO_U256(0x01ed))); + + INTC_TESTS_ASSERT(intc_u256_init_cstring_base("31415926", -1 /*size*/, 10 /*base*/, &val)); + INTC_TESTS_ASSERT(intc_u256_eq(val, INTC_U64_TO_U256(0x01df5e76ULL))); + INTC_TESTS_END; + } + + { + INTC_TESTS_BEGIN("Constructor.one"); + INTC_TESTS_ASSERT(intc_u128_as_bool(INTC_U64_TO_U256(true).hi) == false); + INTC_TESTS_ASSERT(intc_u128_as_bool(INTC_U64_TO_U256(true).lo) == true); + INTC_TESTS_ASSERT(intc_u128_as_bool(INTC_U64_TO_U256(false).hi) == false); + INTC_TESTS_ASSERT(intc_u128_as_bool(INTC_U64_TO_U256(false).lo) == false); + + INTC_TESTS_ASSERT(intc_u128_eq(INTC_U64_TO_U256((intc_u8)0x01ULL).hi, INTC_U64_TO_U128(0ULL))); + INTC_TESTS_ASSERT(intc_u128_eq(INTC_U64_TO_U256((intc_u16)0x0123ULL).hi, INTC_U64_TO_U128(0ULL))); + INTC_TESTS_ASSERT(intc_u128_eq(INTC_U64_TO_U256((intc_u32)0x01234567ULL).hi, INTC_U64_TO_U128(0ULL))); + INTC_TESTS_ASSERT(intc_u128_eq(INTC_U64_TO_U256((intc_u64)0x0123456789abcdefULL).hi, INTC_U64_TO_U128(0ULL))); + + INTC_TESTS_ASSERT(intc_u128_eq(INTC_U64_TO_U256((intc_u8)0x01ULL).lo, INTC_U64_TO_U128((intc_u8)0x01ULL))); + INTC_TESTS_ASSERT(intc_u128_eq(INTC_U64_TO_U256((intc_u16)0x0123ULL).lo, INTC_U64_TO_U128((intc_u16)0x0123ULL))); + INTC_TESTS_ASSERT(intc_u128_eq(INTC_U64_TO_U256((intc_u32)0x01234567ULL).lo, INTC_U64_TO_U128((intc_u32)0x01234567ULL))); + INTC_TESTS_ASSERT(intc_u128_eq(INTC_U64_TO_U256((intc_u64)0x0123456789abcdefULL).lo, INTC_U64_TO_U128((intc_u64)0x0123456789abcdefULL))); + INTC_TESTS_END; + } + + { + INTC_TESTS_BEGIN("Constructor.two"); + for (int hi = 0; hi < 2; hi++) + { + for (int lo = 0; lo < 2; lo++) + { + struct intc_u256 const val = INTC_U256(INTC_U64_TO_U128((intc_u64)lo), INTC_U64_TO_U128((intc_u64)hi)); + INTC_TESTS_ASSERT(intc_u128_eq(val.hi, INTC_U64_TO_U128((intc_u64)hi))); + INTC_TESTS_ASSERT(intc_u128_eq(val.lo, INTC_U64_TO_U128((intc_u64)lo))); + } + } + + INTC_TESTS_ASSERT(intc_u128_eq(INTC_U256(INTC_U64_TO_U128((intc_u8) 0x01ULL), INTC_U64_TO_U128((intc_u8)0x01ULL)).hi, INTC_U64_TO_U128((intc_u8)0x01ULL))); + INTC_TESTS_ASSERT(intc_u128_eq(INTC_U256(INTC_U64_TO_U128((intc_u16)0x0123ULL), INTC_U64_TO_U128((intc_u16)0x0123ULL)).hi, INTC_U64_TO_U128((intc_u16)0x0123ULL))); + INTC_TESTS_ASSERT(intc_u128_eq(INTC_U256(INTC_U64_TO_U128((intc_u32)0x01234567ULL), INTC_U64_TO_U128((intc_u32)0x01234567ULL)).hi, INTC_U64_TO_U128((intc_u32)0x01234567ULL))); + INTC_TESTS_ASSERT(intc_u128_eq(INTC_U256(INTC_U64_TO_U128((intc_u64)0x0123456789abcdefULL), INTC_U64_TO_U128((intc_u64)0x0123456789abcdefULL)).hi, INTC_U64_TO_U128((intc_u64)0x0123456789abcdefULL))); + + INTC_TESTS_ASSERT(intc_u128_eq(INTC_U256(INTC_U64_TO_U128((intc_u8) 0x01ULL), INTC_U64_TO_U128((intc_u8) 0x01ULL)).lo, INTC_U64_TO_U128((intc_u8)0x01ULL))); + INTC_TESTS_ASSERT(intc_u128_eq(INTC_U256(INTC_U64_TO_U128((intc_u16)0x0123ULL), INTC_U64_TO_U128((intc_u16)0x0123ULL)).lo, INTC_U64_TO_U128((intc_u16)0x0123ULL))); + INTC_TESTS_ASSERT(intc_u128_eq(INTC_U256(INTC_U64_TO_U128((intc_u32)0x01234567ULL), INTC_U64_TO_U128((intc_u32)0x01234567ULL)).lo, INTC_U64_TO_U128((intc_u32)0x01234567ULL))); + INTC_TESTS_ASSERT(intc_u128_eq(INTC_U256(INTC_U64_TO_U128((intc_u64)0x0123456789abcdefULL), INTC_U64_TO_U128((intc_u64)0x0123456789abcdefULL)).lo, INTC_U64_TO_U128((intc_u64)0x0123456789abcdefULL))); + INTC_TESTS_END; + } + } + + printf("\n div.cpp\n"); + { + { + INTC_TESTS_BEGIN("Arithmetic.divide"); + const struct intc_u256 big = INTC_U64_TO_U256(0xfedbca9876543210ULL); + const struct intc_u256 small = INTC_U64_TO_U256(0xffffULL); + const struct intc_u256 res_val = INTC_U64_TO_U256(0xfedcc9753fc9ULL); + + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_div(small, small), INTC_U64_TO_U256(1))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_div(small, big), INTC_U64_TO_U256(0))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_div(big, big), INTC_U64_TO_U256(1))); + + // TODO(dqn): Add a way to catch divide by 0 assert nicely? Maybe? + // INTC_TESTS_ASSERT(intc_u256_div(INTC_U64_TO_U256(1), INTC_U64_TO_U256(0))); + INTC_TESTS_END; + } + + { + INTC_TESTS_BEGIN("External.divide"); + bool t = true; + bool f = false; + intc_u8 u8 = 0xaaULL; + intc_u16 u16 = 0xaaaaULL; + intc_u32 u32 = 0xaaaaaaaaULL; + intc_u64 u64 = 0xaaaaaaaaaaaaaaaaULL; + struct intc_u128 u128 = INTC_U128(0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL); + struct intc_u256 val = INTC_U64_TO_U256(0x7bULL); + + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_div(INTC_U64_TO_U256(t), val), INTC_U64_TO_U256(false))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_div(INTC_U64_TO_U256(f), val), INTC_U64_TO_U256(false))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_div(INTC_U64_TO_U256(u8), val), INTC_U64_TO_U256(0x1ULL))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_div(INTC_U64_TO_U256(u16), val), INTC_U64_TO_U256(0x163ULL))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_div(INTC_U64_TO_U256(u32), val), INTC_U64_TO_U256(0x163356bULL))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_div(INTC_U64_TO_U256(u64), val), INTC_U64_TO_U256(0x163356b88ac0de0ULL))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_div(u128, intc_u256_as_u128(val)), INTC_U128(0x163356b88ac0de01ULL, 0x163356b88ac0de0ULL))); + INTC_TESTS_END; + } + } + + printf("\n equals.cpp\n"); + { + { + INTC_TESTS_BEGIN("Comparison.equals"); + INTC_TESTS_ASSERT(intc_u256_eq(INTC_U64_TO_U256(0xdeadbeefULL), INTC_U64_TO_U256(0xdeadbeefULL))); + INTC_TESTS_ASSERT(!intc_u256_eq(INTC_U64_TO_U256(0xdeadbeefULL), INTC_U64_TO_U256(0xfee1baadULL))); + INTC_TESTS_END; + } + } + + printf("\n fix.cpp\n"); + { + { + INTC_TESTS_BEGIN("Arithmetic.increment"); + struct intc_u256 value = INTC_U256_ZERO; + value = intc_u256_add_u64(value, 1); + INTC_TESTS_ASSERT(intc_u256_eq(value, INTC_U64_TO_U256(1))); + INTC_TESTS_END; + } + + { + INTC_TESTS_BEGIN("Arithmetic.decrement"); + struct intc_u256 value = INTC_U256_ZERO; + value = intc_u256_sub_u64(value, 1); + INTC_TESTS_ASSERT(intc_u256_eq(value, INTC_U256(INTC_U128(0xffffffffffffffffULL, 0xffffffffffffffffULL), INTC_U128(0xffffffffffffffffULL, 0xffffffffffffffffULL)))); + INTC_TESTS_END; + } + } + + printf("\n functions.cpp\n"); + { + { + INTC_TESTS_BEGIN("Function.str"); + int const leading_zeros = 5; // number of leading 0s + + // make sure all of the test strings create the ASCII version of the string + struct intc_u256 const original = INTC_U64_TO_U256(2216002924); + for (int test_index = 0; test_index < sizeof(INTC_TESTS_STRING_BASE_TESTS)/sizeof(INTC_TESTS_STRING_BASE_TESTS[0]); test_index++) + { + struct intc_base_to_string const *test_entry = INTC_TESTS_STRING_BASE_TESTS + test_index; + struct intc_u256_string output = intc_u256_str(original, test_entry->base, 0 /*separate_every_n_chars*/, ' ' /*separate_ch*/); + INTC_TESTS_ASSERT_MSG(strcmp(output.str, test_entry->expect) == 0, + "output: %s\n" + "expect: %s\n", + output.str, + test_entry->expect); + } + INTC_TESTS_END; + } + } + + printf("\n gt.cpp\n"); + { + { + INTC_TESTS_BEGIN("Comparison.greater_than"); + struct intc_u256 const big = INTC_U256(INTC_U64_TO_U128(0xffffffffffffffffULL), INTC_U64_TO_U128(0xffffffffffffffffULL)); + struct intc_u256 const small = INTC_U256(INTC_U64_TO_U128(0x0000000000000000ULL), INTC_U64_TO_U128(0x0000000000000000ULL)); + + INTC_TESTS_ASSERT(intc_u256_gt(small, small) == false); + INTC_TESTS_ASSERT(intc_u256_gt(small, big) == false); + + INTC_TESTS_ASSERT(intc_u256_gt(big, small) == true); + INTC_TESTS_ASSERT(intc_u256_gt(big, big) == false); + INTC_TESTS_END; + } + + { + INTC_TESTS_BEGIN("External.greater_than"); + for (int index = 0; + index < sizeof(INTC_TESTS_MAX_UNSIGNED_VALUES)/sizeof(INTC_TESTS_MAX_UNSIGNED_VALUES[0]); + index++) + { + struct intc_u256 const small = INTC_U256_ZERO; + struct intc_u256 const big = INTC_U64_TO_U256(INTC_TESTS_MAX_UNSIGNED_VALUES[index]); + + INTC_TESTS_ASSERT(intc_u256_gt(small, small) == false); + INTC_TESTS_ASSERT(intc_u256_gt(small, big) == false); + + INTC_TESTS_ASSERT(intc_u256_gt(big, small) == true); + INTC_TESTS_ASSERT(intc_u256_gt(big, big) == false); + } + + INTC_TESTS_END; + } + } + + printf("\n gte.cpp\n"); + { + { + INTC_TESTS_BEGIN("Comparison.greater_than_or_equals"); + struct intc_u256 const big = INTC_U256(INTC_U64_TO_U128(0xffffffffffffffffULL), INTC_U64_TO_U128(0xffffffffffffffffULL)); + struct intc_u256 const small = INTC_U256(INTC_U64_TO_U128(0x0000000000000000ULL), INTC_U64_TO_U128(0x0000000000000000ULL)); + + INTC_TESTS_ASSERT(intc_u256_gt_eq(small, small) == true); + INTC_TESTS_ASSERT(intc_u256_gt_eq(small, big) == false); + + INTC_TESTS_ASSERT(intc_u256_gt_eq(big, small) == true); + INTC_TESTS_ASSERT(intc_u256_gt_eq(big, big) == true); + INTC_TESTS_END; + } + + { + INTC_TESTS_BEGIN("External.greater_than_or_equals"); + for (int index = 0; + index < sizeof(INTC_TESTS_MAX_UNSIGNED_VALUES)/sizeof(INTC_TESTS_MAX_UNSIGNED_VALUES[0]); + index++) + { + struct intc_u256 const small = INTC_U256_ZERO; + struct intc_u256 const big = INTC_U64_TO_U256(INTC_TESTS_MAX_UNSIGNED_VALUES[index]); + + INTC_TESTS_ASSERT(intc_u256_gt_eq(small, small) == true); + INTC_TESTS_ASSERT(intc_u256_gt_eq(small, big) == false); + + INTC_TESTS_ASSERT(intc_u256_gt_eq(big, small) == true); + INTC_TESTS_ASSERT(intc_u256_gt_eq(big, big) == true); + } + INTC_TESTS_END; + } + } + + printf("\n invert.cpp\n"); + { + { + INTC_TESTS_BEGIN("BitWise.invert"); + for (int hi_hi = 0; hi_hi < 2; hi_hi++) + { + for (int hi_lo = 0; hi_lo < 2; hi_lo++) + { + for (int lo_hi = 0; lo_hi < 2; lo_hi++) + { + for (int lo_lo = 0; lo_lo < 2; lo_lo++) + { + struct intc_u256 const val = + intc_u256_negate(INTC_U256( + INTC_U128(lo_lo ? 0xffffffffffffffffULL : 0x0000000000000000ULL, lo_hi ? 0xffffffffffffffffULL : 0x0000000000000000ULL), + INTC_U128(hi_lo ? 0xffffffffffffffffULL : 0x0000000000000000ULL, hi_hi ? 0xffffffffffffffffULL : 0x0000000000000000ULL))); + + INTC_TESTS_ASSERT(val.hi.hi == hi_hi ? 0x0000000000000000ULL : 0xffffffffffffffffULL); + INTC_TESTS_ASSERT(val.hi.lo == hi_lo ? 0x0000000000000000ULL : 0xffffffffffffffffULL); + INTC_TESTS_ASSERT(val.lo.hi == lo_hi ? 0x0000000000000000ULL : 0xffffffffffffffffULL); + INTC_TESTS_ASSERT(val.lo.lo == lo_lo ? 0x0000000000000000ULL : 0xffffffffffffffffULL); + } + } + } + } + INTC_TESTS_END; + } + } + + printf("\n leftshift.cpp\n"); + { + { + INTC_TESTS_BEGIN("BitShift.left"); + // operator<< + struct intc_u256 val = INTC_U64_TO_U256(0x1); + intc_u64 exp_val = 1; + for(int i = 0; i < 64; i++){ + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_lshift(val, i), INTC_U64_TO_U256(exp_val << i))); + } + + struct intc_u256 zero = INTC_U256_ZERO; + for (int i = 0; i < 64; i++) + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_lshift(zero, i), INTC_U256_ZERO)); + INTC_TESTS_END; + } + + { + INTC_TESTS_BEGIN("External.shift_left"); + bool t = true; + bool f = false; + intc_u8 u8 = 0xffULL; + intc_u16 u16 = 0xffffULL; + intc_u32 u32 = 0xffffffffULL; + intc_u64 u64 = 0xffffffffffffffffULL; + struct intc_u128 const u128 = INTC_U128(0xffffffffffffffffULL, 0xffffffffffffffffULL); + + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_lshift(INTC_U64_TO_U256(u8), 7), INTC_U64_TO_U256(0x7f80ULL))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_lshift(INTC_U64_TO_U256(u16), 15), INTC_U64_TO_U256(0x7fff8000ULL))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_lshift(INTC_U64_TO_U256(u32), 31), INTC_U64_TO_U256(0x7fffffff80000000ULL))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_lshift(INTC_U64_TO_U256(u64), 63), INTC_U256(INTC_U128(0x8000000000000000ULL, 0x7fffffffffffffffULL), INTC_U128(0x0000000000000000ULL, 0x0000000000000000ULL)))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_lshift(INTC_U128_TO_U256(u128), 127), INTC_U256(INTC_U128(0x0, 0x8000000000000000ULL), INTC_U128(0xffffffffffffffffULL, 0x7fffffffffffffffULL)))); + INTC_TESTS_END; + } + } + + printf("\n lt.cpp\n"); + { + { + INTC_TESTS_BEGIN("Comparison.less_than"); + struct intc_u256 const big = INTC_U256(INTC_U64_TO_U128(0xffffffffffffffffULL), INTC_U64_TO_U128(0xffffffffffffffffULL)); + struct intc_u256 const small = INTC_U256(INTC_U64_TO_U128(0x0000000000000000ULL), INTC_U64_TO_U128(0x0000000000000000ULL)); + + INTC_TESTS_ASSERT(intc_u256_lt(small, small) == false); + INTC_TESTS_ASSERT(intc_u256_lt(small, big) == true); + + INTC_TESTS_ASSERT(intc_u256_lt(big, small) == false); + INTC_TESTS_ASSERT(intc_u256_lt(big, big) == false); + INTC_TESTS_END; + } + + { + INTC_TESTS_BEGIN("External.less_than"); + for (int index = 0; + index < sizeof(INTC_TESTS_MAX_UNSIGNED_VALUES)/sizeof(INTC_TESTS_MAX_UNSIGNED_VALUES[0]); + index++) + { + struct intc_u256 const small = INTC_U256_ZERO; + struct intc_u256 const big = INTC_U64_TO_U256(INTC_TESTS_MAX_UNSIGNED_VALUES[index]); + + INTC_TESTS_ASSERT(intc_u256_lt(small, small) == false); + INTC_TESTS_ASSERT(intc_u256_lt(small, big) == true); + + INTC_TESTS_ASSERT(intc_u256_lt(big, small) == false); + INTC_TESTS_ASSERT(intc_u256_lt(big, big) == false); + } + INTC_TESTS_END; + } + } + + printf("\n lte.cpp\n"); + { + { + INTC_TESTS_BEGIN("Comparison.less_than_or_equals"); + struct intc_u256 const big = INTC_U256(INTC_U64_TO_U128(0xffffffffffffffffULL), INTC_U64_TO_U128(0xffffffffffffffffULL)); + struct intc_u256 const small = INTC_U256(INTC_U64_TO_U128(0x0000000000000000ULL), INTC_U64_TO_U128(0x0000000000000000ULL)); + + INTC_TESTS_ASSERT(intc_u256_lt_eq(small, small) == true); + INTC_TESTS_ASSERT(intc_u256_lt_eq(small, big) == true); + + INTC_TESTS_ASSERT(intc_u256_lt_eq(big, small) == false); + INTC_TESTS_ASSERT(intc_u256_lt_eq(big, big) == true); + INTC_TESTS_END; + } + + { + INTC_TESTS_BEGIN("External.less_than_or_equals"); + for (int index = 0; + index < sizeof(INTC_TESTS_MAX_UNSIGNED_VALUES)/sizeof(INTC_TESTS_MAX_UNSIGNED_VALUES[0]); + index++) + { + struct intc_u256 const small = INTC_U256_ZERO; + struct intc_u256 const big = INTC_U64_TO_U256(INTC_TESTS_MAX_UNSIGNED_VALUES[index]); + + INTC_TESTS_ASSERT(intc_u256_lt_eq(small, small) == true); + INTC_TESTS_ASSERT(intc_u256_lt_eq(small, big) == true); + + INTC_TESTS_ASSERT(intc_u256_lt_eq(big, small) == false); + INTC_TESTS_ASSERT(intc_u256_lt_eq(big, big) == true); + } + INTC_TESTS_END; + } + } + + printf("\n mod.cpp\n"); + { + { + INTC_TESTS_BEGIN("Arithmetic.modulo"); + // has remainder + struct intc_u256 const val = INTC_U256(INTC_U128(0xffffffffffffffffULL, 0xffffffffffffffffULL), INTC_U128(0xffffffffffffffffULL, 0xffffffffffffffffULL)); + struct intc_u256 const val_mod = INTC_U64_TO_U256(0xfedcba9876543210ULL); + + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_mod(val, val_mod), INTC_U64_TO_U256(0x63794f9d55c8d29f))); + + // no remainder + struct intc_u256 const val_0 = INTC_U256(INTC_U128(0, 0), INTC_U128(0, 0xfedcba9876543210)); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_mod(val_0, val_mod), INTC_U256_ZERO)); + + // TODO(dqn): Add a way to catch divide by 0 assert nicely? Maybe? + // mod 0 + // EXPECT_THROW(uint256_t(1) % uint256_t(0), std::domain_error); + INTC_TESTS_END; + } + + { + INTC_TESTS_BEGIN("External.modulo"); + bool t = true; + bool f = false; + intc_u8 u8 = 0xaaULL; + intc_u16 u16 = 0xaaaaULL; + intc_u32 u32 = 0xaaaaaaaaULL; + intc_u64 u64 = 0xaaaaaaaaaaaaaaaaULL; + struct intc_u128 const u128 = INTC_U128(0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL); + struct intc_u256 const val = INTC_U64_TO_U256(0xd03ULL); // prime + + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_mod(INTC_U64_TO_U256(t), val), INTC_U64_TO_U256(true))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_mod(INTC_U64_TO_U256(f), val), INTC_U64_TO_U256(false))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_mod(INTC_U64_TO_U256(u8), val), INTC_U64_TO_U256((intc_u8) 0xaaULL))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_mod(INTC_U64_TO_U256(u16), val), INTC_U64_TO_U256((intc_u16)0x183ULL))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_mod(INTC_U64_TO_U256(u32), val), INTC_U64_TO_U256((intc_u32)0x249ULL))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_mod(INTC_U64_TO_U256(u64), val), INTC_U64_TO_U256((intc_u64)0xc7fULL))); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_mod(u128, intc_u256_as_u128(val)), INTC_U64_TO_U128(0x9fbULL))); + INTC_TESTS_END; + } + } + + printf("\n mult.cpp\n"); + { + { + INTC_TESTS_BEGIN("Arithmetic.multiply"); + struct intc_u256 const val = INTC_U64_TO_U256(0xfedbca9876543210ULL); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_mul(val, val), INTC_U256(INTC_U128(0x010e6cd7a44a4100ULL, 0xfdb8e2bacbfe7cefULL), INTC_U128(0x0000000000000000ULL, 0x0000000000000000ULL)))); + + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_mul(val, INTC_U256_ZERO), INTC_U256_ZERO)); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_mul(INTC_U256_ZERO, val), INTC_U256_ZERO)); + + struct intc_u256 const one = INTC_U64_TO_U256(1); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_mul(val, one), val)); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_mul(one, val), val)); + INTC_TESTS_END; + } + + { + INTC_TESTS_BEGIN("External.multiply"); + bool t = true; + bool f = false; + intc_u8 u8 = 0xaaULL; + intc_u16 u16 = 0xaaaaULL; + intc_u32 u32 = 0xaaaaaaaaULL; + intc_u64 u64 = 0xaaaaaaaaaaaaaaaaULL; + struct intc_u128 const u128 = INTC_U128(0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL); + struct intc_u256 const val = INTC_U256(INTC_U128(0xf0f0f0f0f0f0f0f0ULL, 0xf0f0f0f0f0f0f0f0ULL), INTC_U128(0xf0f0f0f0f0f0f0f0ULL, 0xf0f0f0f0f0f0f0f0ULL)); + + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_mul(INTC_U64_TO_U256(t), val), INTC_U256(INTC_U128(0xf0f0f0f0f0f0f0f0ULL, 0xf0f0f0f0f0f0f0f0ULL), INTC_U128(0xf0f0f0f0f0f0f0f0ULL, 0xf0f0f0f0f0f0f0f0ULL)))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_mul(INTC_U64_TO_U256(f), val), INTC_U256(INTC_U128(0x0000000000000000ULL, 0x0000000000000000ULL), INTC_U128(0x0000000000000000ULL, 0x0000000000000000ULL)))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_mul(INTC_U64_TO_U256(u8), val), INTC_U256(INTC_U128(0xffffffffffffff60ULL, 0xffffffffffffffffULL), INTC_U128(0xffffffffffffffffULL, 0xffffffffffffffffULL)))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_mul(INTC_U64_TO_U256(u16), val), INTC_U256(INTC_U128(0xffffffffffff5f60ULL, 0xffffffffffffffffULL), INTC_U128(0xffffffffffffffffULL, 0xffffffffffffffffULL)))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_mul(INTC_U64_TO_U256(u32), val), INTC_U256(INTC_U128(0xffffffff5f5f5f60ULL, 0xffffffffffffffffULL), INTC_U128(0xffffffffffffffffULL, 0xffffffffffffffffULL)))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_mul(INTC_U64_TO_U256(u64), val), INTC_U256(INTC_U128(0x5f5f5f5f5f5f5f60ULL, 0xffffffffffffffffULL), INTC_U128(0xffffffffffffffffULL, 0xffffffffffffffffULL)))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_mul(INTC_U128_TO_U256(u128), val), INTC_U256(INTC_U128(0x5f5f5f5f5f5f5f60ULL, 0x5f5f5f5f5f5f5f5fULL), INTC_U128(0xffffffffffffffffULL, 0xffffffffffffffffULL)))); + + INTC_TESTS_ASSERT((intc_u8)(u8 * intc_u256_as_u8(val)) == (intc_u8)0x60ULL); + INTC_TESTS_ASSERT((intc_u16)(u16 * intc_u256_as_u16(val)) == (intc_u16)0x5f60ULL); + INTC_TESTS_ASSERT((intc_u32)(u32 * intc_u256_as_u32(val)) == (intc_u32)0x5f5f5f60ULL); + INTC_TESTS_ASSERT((intc_u64)(u64 * intc_u256_as_u64(val)) == (intc_u64)0x5f5f5f5f5f5f5f60ULL); + INTC_TESTS_ASSERT(intc_u128_eq(intc_u128_mul(u128, intc_u256_as_u128(val)), INTC_U128(0x5f5f5f5f5f5f5f60ULL, 0x5f5f5f5f5f5f5f5fULL))); + INTC_TESTS_END; + } + } + + printf("\n notequals.cpp\n"); + { + { + INTC_TESTS_BEGIN("Comparison.not_equals"); + INTC_TESTS_ASSERT(intc_u256_neq(INTC_U64_TO_U256(0xdeadbeefULL), INTC_U64_TO_U256(0xdeadbeefULL)) == false); + INTC_TESTS_ASSERT(intc_u256_neq(INTC_U64_TO_U256(0xdeadbeefULL), INTC_U64_TO_U256(0xfee1baadULL)) == true); + INTC_TESTS_END; + } + + { + INTC_TESTS_BEGIN("External.not_equals"); + bool const t = true; + bool const f = false; + intc_u8 const u8 = 0xaaULL; + intc_u16 const u16 = 0xaaaaULL; + intc_u32 const u32 = 0xaaaaaaaaULL; + intc_u64 const u64 = 0xaaaaaaaaaaaaaaaaULL; + + INTC_TESTS_ASSERT(intc_u256_neq(INTC_U64_TO_U256(t) , INTC_U64_TO_U256(f)) == true); + INTC_TESTS_ASSERT(intc_u256_neq(INTC_U64_TO_U256(f) , INTC_U64_TO_U256(t)) == true); + INTC_TESTS_ASSERT(intc_u256_neq(INTC_U64_TO_U256(u8) , INTC_U64_TO_U256(u64)) == true); + INTC_TESTS_ASSERT(intc_u256_neq(INTC_U64_TO_U256(u16), INTC_U64_TO_U256(u32)) == true); + INTC_TESTS_ASSERT(intc_u256_neq(INTC_U64_TO_U256(u32), INTC_U64_TO_U256(u16)) == true); + INTC_TESTS_ASSERT(intc_u256_neq(INTC_U64_TO_U256(u64), INTC_U64_TO_U256(u8)) == true); + + INTC_TESTS_ASSERT(intc_u256_neq(INTC_U64_TO_U256(t) , INTC_U64_TO_U256(t)) == false); + INTC_TESTS_ASSERT(intc_u256_neq(INTC_U64_TO_U256(f) , INTC_U64_TO_U256(f)) == false); + INTC_TESTS_ASSERT(intc_u256_neq(INTC_U64_TO_U256(u8) , INTC_U64_TO_U256(u8)) == false); + INTC_TESTS_ASSERT(intc_u256_neq(INTC_U64_TO_U256(u16), INTC_U64_TO_U256(u16)) == false); + INTC_TESTS_ASSERT(intc_u256_neq(INTC_U64_TO_U256(u32), INTC_U64_TO_U256(u32)) == false); + INTC_TESTS_ASSERT(intc_u256_neq(INTC_U64_TO_U256(u64), INTC_U64_TO_U256(u64)) == false); + INTC_TESTS_END; + } + } + + printf("\n or.cpp\n"); + { + { + INTC_TESTS_BEGIN("BitWise.or"); + struct intc_u256 const t = INTC_U64_TO_U256((bool) true); + struct intc_u256 const f = INTC_U64_TO_U256((bool) false); + struct intc_u256 const u8 = INTC_U64_TO_U256((intc_u8) 0xaaULL); + struct intc_u256 const u16 = INTC_U64_TO_U256((intc_u16) 0xaaaaULL); + struct intc_u256 const u32 = INTC_U64_TO_U256((intc_u32) 0xaaaaaaaaULL); + struct intc_u256 const u64 = INTC_U64_TO_U256((intc_u64) 0xaaaaaaaaaaaaaaaaULL); + struct intc_u256 const val = INTC_U256(INTC_U64_TO_U128(0xf0f0f0f0f0f0f0f0ULL), INTC_U64_TO_U128(0xf0f0f0f0f0f0f0f0ULL)); + + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_or(t , val), INTC_U256(INTC_U64_TO_U128(0xf0f0f0f0f0f0f0f1ULL), INTC_U64_TO_U128(0xf0f0f0f0f0f0f0f0ULL)))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_or(f , val), INTC_U256(INTC_U64_TO_U128(0xf0f0f0f0f0f0f0f0ULL), INTC_U64_TO_U128(0xf0f0f0f0f0f0f0f0ULL)))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_or(u8 , val), INTC_U256(INTC_U64_TO_U128(0xf0f0f0f0f0f0f0faULL), INTC_U64_TO_U128(0xf0f0f0f0f0f0f0f0ULL)))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_or(u16, val), INTC_U256(INTC_U64_TO_U128(0xf0f0f0f0f0f0fafaULL), INTC_U64_TO_U128(0xf0f0f0f0f0f0f0f0ULL)))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_or(u32, val), INTC_U256(INTC_U64_TO_U128(0xf0f0f0f0fafafafaULL), INTC_U64_TO_U128(0xf0f0f0f0f0f0f0f0ULL)))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_or(u64, val), INTC_U256(INTC_U64_TO_U128(0xfafafafafafafafaULL), INTC_U64_TO_U128(0xf0f0f0f0f0f0f0f0ULL)))); + + // zero + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_or(INTC_U256_ZERO, val), val)); + INTC_TESTS_END; + } + + { + INTC_TESTS_BEGIN("External.or"); + bool t = true; + bool f = false; + intc_u8 u8 = 0xaa; + intc_u16 u16 = 0xaaaa; + intc_u32 u32 = 0xaaaaaaaaULL; + intc_u64 u64 = 0xaaaaaaaaaaaaaaaaULL; + struct intc_u256 const val = INTC_U256(INTC_U64_TO_U128(0xf0f0f0f0f0f0f0f0ULL), INTC_U64_TO_U128(0xf0f0f0f0f0f0f0f0ULL)); + + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_or(INTC_U64_TO_U256(t) , val), INTC_U256(INTC_U64_TO_U128(0xf0f0f0f0f0f0f0f1ULL), INTC_U64_TO_U128(0xf0f0f0f0f0f0f0f0ULL)))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_or(INTC_U64_TO_U256(f) , val), INTC_U256(INTC_U64_TO_U128(0xf0f0f0f0f0f0f0f0ULL), INTC_U64_TO_U128(0xf0f0f0f0f0f0f0f0ULL)))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_or(INTC_U64_TO_U256(u8) , val), INTC_U256(INTC_U64_TO_U128(0xf0f0f0f0f0f0f0faULL), INTC_U64_TO_U128(0xf0f0f0f0f0f0f0f0ULL)))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_or(INTC_U64_TO_U256(u16), val), INTC_U256(INTC_U64_TO_U128(0xf0f0f0f0f0f0fafaULL), INTC_U64_TO_U128(0xf0f0f0f0f0f0f0f0ULL)))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_or(INTC_U64_TO_U256(u32), val), INTC_U256(INTC_U64_TO_U128(0xf0f0f0f0fafafafaULL), INTC_U64_TO_U128(0xf0f0f0f0f0f0f0f0ULL)))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_or(INTC_U64_TO_U256(u64), val), INTC_U256(INTC_U64_TO_U128(0xfafafafafafafafaULL), INTC_U64_TO_U128(0xf0f0f0f0f0f0f0f0ULL)))); + INTC_TESTS_END; + } + } + + printf("\n rightshift.cpp\n"); + { + { + INTC_TESTS_BEGIN("BitShift.right"); + // operator>> + struct intc_u256 val = INTC_U64_TO_U256(0xffffffffffffffffULL); + intc_u64 exp = 0xffffffffffffffffULL; + + for(int i = 0; i < 64; i++){ + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_rshift(val, i), INTC_U64_TO_U256(exp >> i))); + } + + struct intc_u256 zero = INTC_U256_ZERO; + for (int i = 0; i < 64; i++) + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_rshift(zero, i), INTC_U256_ZERO)); + INTC_TESTS_END; + } + + { + INTC_TESTS_BEGIN("External.shift_left"); + bool t = true; + bool f = false; + intc_u8 u8 = 0xffULL; + intc_u16 u16 = 0xffffULL; + intc_u32 u32 = 0xffffffffULL; + intc_u64 u64 = 0xffffffffffffffffULL; + + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_rshift(INTC_U64_TO_U256(t) , 0), INTC_U64_TO_U256(1))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_rshift(INTC_U64_TO_U256(f) , 0), INTC_U256_ZERO)); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_rshift(INTC_U64_TO_U256(u8), 0), INTC_U64_TO_U256(u8))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_rshift(INTC_U64_TO_U256(u16), 0), INTC_U64_TO_U256(u16))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_rshift(INTC_U64_TO_U256(u32), 0), INTC_U64_TO_U256(u32))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_rshift(INTC_U64_TO_U256(u64), 0), INTC_U64_TO_U256(u64))); + + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_rshift(INTC_U64_TO_U256(t), 1), INTC_U64_TO_U256((intc_u64)t >> 1))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_rshift(INTC_U64_TO_U256(f), 1), INTC_U64_TO_U256((intc_u64)f >> 1))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_rshift(INTC_U64_TO_U256(u8), 1), INTC_U64_TO_U256((intc_u64)u8 >> 1))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_rshift(INTC_U64_TO_U256(u16), 1), INTC_U64_TO_U256((intc_u64)u16 >> 1))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_rshift(INTC_U64_TO_U256(u32), 1), INTC_U64_TO_U256((intc_u64)u32 >> 1))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_rshift(INTC_U64_TO_U256(u64), 1), INTC_U64_TO_U256(u64 >> 1))); + + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_rshift(INTC_U64_TO_U256(u8), 7), INTC_U64_TO_U256(1))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_rshift(INTC_U64_TO_U256(u16), 15), INTC_U64_TO_U256(1))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_rshift(INTC_U64_TO_U256(u32), 31), INTC_U64_TO_U256(1))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_rshift(INTC_U64_TO_U256(u64), 63), INTC_U64_TO_U256(1))); + INTC_TESTS_END; + } + } + + printf("\n sub.cpp\n"); + { + { + INTC_TESTS_BEGIN("Arithmetic.subtract"); + struct intc_u256 const big = INTC_U256(INTC_U128(0xffffffffffffffffULL, 0xffffffffffffffffULL), INTC_U128(0xffffffffffffffffULL, 0xffffffffffffffffULL)); + struct intc_u256 const small = INTC_U256(INTC_U64_TO_U128(0x0000000000000001ULL), INTC_U64_TO_U128(0x0000000000000000ULL)); + + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_sub(small, small), INTC_U256_ZERO)); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_sub(small, big), INTC_U256(INTC_U128(0x0000000000000002ULL, 0x0000000000000000ULL), INTC_U128(0x0000000000000000ULL, 0x0000000000000000ULL)))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_sub(big , small), INTC_U256(INTC_U128(0xfffffffffffffffeULL, 0xffffffffffffffffULL), INTC_U128(0xffffffffffffffffULL, 0xffffffffffffffffULL)))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_sub(big , big), INTC_U256_ZERO)); + INTC_TESTS_END; + } + + { + INTC_TESTS_BEGIN("External.subtract"); + bool t = true; + bool f = false; + intc_u8 u8 = 0xaaULL; + intc_u16 u16 = 0xaaaaULL; + intc_u32 u32 = 0xaaaaaaaaULL; + intc_u64 u64 = 0xaaaaaaaaaaaaaaaaULL; + struct intc_u128 u128 = INTC_U128(0xaaaaaaaaaaaaaaaaULL, 0xaaaaaaaaaaaaaaaaULL); + struct intc_u256 val = INTC_U256(INTC_U128(0xf0f0f0f0f0f0f0f0ULL, 0xf0f0f0f0f0f0f0f0ULL), INTC_U128(0xf0f0f0f0f0f0f0f0ULL, 0xf0f0f0f0f0f0f0f0ULL)); + + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_sub(INTC_U64_TO_U256(t) , val), INTC_U256(INTC_U128(0x0f0f0f0f0f0f0f11ULL, 0x0f0f0f0f0f0f0f0fULL), INTC_U128(0x0f0f0f0f0f0f0f0fULL, 0x0f0f0f0f0f0f0f0fULL)))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_sub(INTC_U64_TO_U256(f) , val), INTC_U256(INTC_U128(0x0f0f0f0f0f0f0f10ULL, 0x0f0f0f0f0f0f0f0fULL), INTC_U128(0x0f0f0f0f0f0f0f0fULL, 0x0f0f0f0f0f0f0f0fULL)))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_sub(INTC_U64_TO_U256(u8) , val), INTC_U256(INTC_U128(0x0f0f0f0f0f0f0fbaULL, 0x0f0f0f0f0f0f0f0fULL), INTC_U128(0x0f0f0f0f0f0f0f0fULL, 0x0f0f0f0f0f0f0f0fULL)))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_sub(INTC_U64_TO_U256(u16), val), INTC_U256(INTC_U128(0x0f0f0f0f0f0fb9baULL, 0x0f0f0f0f0f0f0f0fULL), INTC_U128(0x0f0f0f0f0f0f0f0fULL, 0x0f0f0f0f0f0f0f0fULL)))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_sub(INTC_U64_TO_U256(u32), val), INTC_U256(INTC_U128(0x0f0f0f0fb9b9b9baULL, 0x0f0f0f0f0f0f0f0fULL), INTC_U128(0x0f0f0f0f0f0f0f0fULL, 0x0f0f0f0f0f0f0f0fULL)))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_sub(INTC_U64_TO_U256(u64), val), INTC_U256(INTC_U128(0xb9b9b9b9b9b9b9baULL, 0x0f0f0f0f0f0f0f0fULL), INTC_U128(0x0f0f0f0f0f0f0f0fULL, 0x0f0f0f0f0f0f0f0fULL)))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_sub(INTC_U128_TO_U256(u128), val), INTC_U256(INTC_U128(0xb9b9b9b9b9b9b9baULL, 0xb9b9b9b9b9b9b9b9ULL), INTC_U128(0x0f0f0f0f0f0f0f0fULL, 0x0f0f0f0f0f0f0f0fULL)))); + INTC_TESTS_END; + } + } + + printf("\n typecast.cpp\n"); + { + { + INTC_TESTS_BEGIN("Typecast.all"); + struct intc_u256 const val = INTC_U256(INTC_U64_TO_U128(0xaaaaaaaaaaaaaaaaULL), INTC_U64_TO_U128(0xaaaaaaaaaaaaaaaaULL)); + INTC_TESTS_ASSERT(intc_u256_as_bool(INTC_U64_TO_U256(true)) == true); + INTC_TESTS_ASSERT(intc_u256_as_bool(INTC_U64_TO_U256(false)) == false); + INTC_TESTS_ASSERT(intc_u256_as_u8(val) == (intc_u8)0xaaULL); + INTC_TESTS_ASSERT(intc_u256_as_u16(val) == (intc_u16)0xaaaaULL); + INTC_TESTS_ASSERT(intc_u256_as_u32(val) == (intc_u32)0xaaaaaaaaULL); + INTC_TESTS_ASSERT(intc_u256_as_u64(val) == (intc_u64)0xaaaaaaaaaaaaaaaaULL); + INTC_TESTS_END; + } + } + + printf("\n xor.cpp\n"); + { + { + INTC_TESTS_BEGIN("BitWise.xor"); + struct intc_u256 t = INTC_U64_TO_U256((bool) true); + struct intc_u256 f = INTC_U64_TO_U256((bool) false); + struct intc_u256 u8 = INTC_U64_TO_U256((intc_u8) 0xaaULL); + struct intc_u256 u16 = INTC_U64_TO_U256((intc_u16) 0xaaaaULL); + struct intc_u256 u32 = INTC_U64_TO_U256((intc_u32) 0xaaaaaaaaULL); + struct intc_u256 u64 = INTC_U64_TO_U256((intc_u64) 0xaaaaaaaaaaaaaaaa); + struct intc_u256 const val = INTC_U256(INTC_U64_TO_U128(0xf0f0f0f0f0f0f0f0ULL), INTC_U64_TO_U128(0xf0f0f0f0f0f0f0f0ULL)); + + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_xor(t , val), INTC_U256(INTC_U64_TO_U128(0xf0f0f0f0f0f0f0f1ULL), INTC_U64_TO_U128(0xf0f0f0f0f0f0f0f0ULL)))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_xor(f , val), INTC_U256(INTC_U64_TO_U128(0xf0f0f0f0f0f0f0f0ULL), INTC_U64_TO_U128(0xf0f0f0f0f0f0f0f0ULL)))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_xor(u8 , val), INTC_U256(INTC_U64_TO_U128(0xf0f0f0f0f0f0f05aULL), INTC_U64_TO_U128(0xf0f0f0f0f0f0f0f0ULL)))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_xor(u16, val), INTC_U256(INTC_U64_TO_U128(0xf0f0f0f0f0f05a5aULL), INTC_U64_TO_U128(0xf0f0f0f0f0f0f0f0ULL)))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_xor(u32, val), INTC_U256(INTC_U64_TO_U128(0xf0f0f0f05a5a5a5aULL), INTC_U64_TO_U128(0xf0f0f0f0f0f0f0f0ULL)))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_xor(u64, val), INTC_U256(INTC_U64_TO_U128(0x5a5a5a5a5a5a5a5aULL), INTC_U64_TO_U128(0xf0f0f0f0f0f0f0f0ULL)))); + + // zero + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_xor(INTC_U256_ZERO, val), val)); + INTC_TESTS_END; + } + + { + INTC_TESTS_BEGIN("External.xor"); + bool t = true; + bool f = false; + intc_u8 u8 = 0xaaULL; + intc_u16 u16 = 0xaaaaULL; + intc_u32 u32 = 0xaaaaaaaaULL; + intc_u64 u64 = 0xaaaaaaaaaaaaaaaaULL; + struct intc_u256 const val = INTC_U256(INTC_U64_TO_U128(0xf0f0f0f0f0f0f0f0ULL), INTC_U64_TO_U128(0xf0f0f0f0f0f0f0f0ULL)); + + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_xor(INTC_U64_TO_U256(t ), val), INTC_U256(INTC_U64_TO_U128(0xf0f0f0f0f0f0f0f1ULL), INTC_U64_TO_U128(0xf0f0f0f0f0f0f0f0ULL)))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_xor(INTC_U64_TO_U256(f ), val), INTC_U256(INTC_U64_TO_U128(0xf0f0f0f0f0f0f0f0ULL), INTC_U64_TO_U128(0xf0f0f0f0f0f0f0f0ULL)))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_xor(INTC_U64_TO_U256(u8 ), val), INTC_U256(INTC_U64_TO_U128(0xf0f0f0f0f0f0f05aULL), INTC_U64_TO_U128(0xf0f0f0f0f0f0f0f0ULL)))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_xor(INTC_U64_TO_U256(u16), val), INTC_U256(INTC_U64_TO_U128(0xf0f0f0f0f0f05a5aULL), INTC_U64_TO_U128(0xf0f0f0f0f0f0f0f0ULL)))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_xor(INTC_U64_TO_U256(u32), val), INTC_U256(INTC_U64_TO_U128(0xf0f0f0f05a5a5a5aULL), INTC_U64_TO_U128(0xf0f0f0f0f0f0f0f0ULL)))); + INTC_TESTS_ASSERT(intc_u256_eq(intc_u256_xor(INTC_U64_TO_U256(u64), val), INTC_U256(INTC_U64_TO_U128(0x5a5a5a5a5a5a5a5aULL), INTC_U64_TO_U128(0xf0f0f0f0f0f0f0f0ULL)))); + INTC_TESTS_END; + } + } + + fputc('\n', stdout); + return result; +} +#endif // !defined(INTC_NO_U256) + +void intc_test_state_print(char const *label, struct intc_test_state const *state) +{ + printf(INTC_TESTS_COLOR_MAGENTA "%s" INTC_TESTS_COLOR_RESET " -- %d/%d tests passsed", label, state->test_count - state->fail_count, state->test_count); + if (state->fail_count) + printf(INTC_TESTS_COLOR_RED " (%d tests failed)" INTC_TESTS_COLOR_RESET, state->fail_count); + fputc('\n', stdout); +} + +void intc_unit_tests(void) +{ + struct intc_test_state u128_state = intc_u128_unit_tests(); +#if !defined(INTC_NO_U256) + struct intc_test_state u256_state = intc_u256_unit_tests(); +#endif + + intc_test_state_print("intc_u128_unit_tests", &u128_state); + +#if !defined(INTC_NO_U256) + intc_test_state_print("intc_u256_unit_tests", &u256_state); +#endif +} + +#if defined(INTC_TESTS_WITH_MAIN) +int main(void) +{ + intc_unit_tests(); + return 0; +} +#endif +#endif // INTC_TESTS_IMPLEMENTATION