intc/intc.h

2062 lines
76 KiB
C

#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 <stdio.h>
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.data); // 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.data); // 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
#if !defined(INTC_NO_CPP_FEATURES)
#define INTC_NO_CPP_FEATURES
#endif
#define INTC_BEGIN_EXTERN_C
#define INTC_END_EXTERN_C
#define INTC_ZERO_INIT {0}
#include <stdbool.h>
#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 data[63 + 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_hex_cstring(...)
// Construct a 128 unsigned integer from a string. This function supports
// hexadecimal strings with and without the 0x prefix i.e. "0xafc8a" or "afc8a"
// or "0xAFC8A" or "xafc8a" .
INTC_API bool INTC_API_PREFIX(128_init_hex_cstring)(const char *string, int size, struct intc_u128 *dest);
// Construct a 128 unsigned integer from a base 10 number string. The separator
// character given will be permitted and skipped in the string if encountered,
// e.g. ','. If no separator is permitted, pass 0 as the separator.
INTC_API bool INTC_API_PREFIX(128_init_cstring)(char const *string, int size, struct intc_u128 *dest, char separator);
// 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 = {}; this->lo.lo = lo_u64; }
intc_u256(intc_u128 lo) { *this = {}; 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 data[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_hex_cstring(...)
// Construct a 128 unsigned integer from a string. This function supports
// hexadecimal strings with and without the 0x prefix i.e. "0xafc8a" or "afc8a"
// or "0xAFC8A" or "xafc8a".
INTC_API bool INTC_API_PREFIX(256_init_hex_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_hex_cstring_base)(char const *string, int size, int base, struct intc_u256 *dest);
// Construct a 256 unsigned integer from a base 10 number string. The separator
// character given will be permitted and skipped in the string if encountered,
// e.g. ','. If no separator is permitted, pass 0 as the separator.
INTC_API bool INTC_API_PREFIX(256_init_cstring)(char const *string, int size, struct intc_u256 *dest, char separator);
// 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] = INTC_ZERO_INIT;
static bool const INTC__U16_IS_16_BITS[sizeof(intc_u16) == 2 ? 1 : -1] = INTC_ZERO_INIT;
static bool const INTC__U32_IS_32_BITS[sizeof(intc_u32) == 4 ? 1 : -1] = INTC_ZERO_INIT;
static bool const INTC__U64_IS_64_BITS[sizeof(intc_u64) == 8 ? 1 : -1] = INTC_ZERO_INIT;
INTC_BEGIN_EXTERN_C
// NOTE: 128 Bit Unsigned Integer
// -----------------------------------------------------------------------------
// NOTE: U128 Converters
// -----------------------------------------------------------------------------
INTC_API bool INTC_API_PREFIX(128_init_hex_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 = size - 1, bits_written = 0;
index >= 0;
index--, bits_written += 4)
{
if (bits_written >= (int)(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 >= (int)(sizeof(dest->lo) * 8)) ? &dest->hi : &dest->lo;
*word = *word | ((intc_u64)bits4 << bits_written);
}
return true;
}
INTC_API bool INTC_API_PREFIX(128_init_cstring)(char const *string, int size, struct intc_u128 *dest, char separator)
{
if (string == 0 || size == 0 || !dest)
return false;
if (size < 0) {
for (size = 0; string[size]; size++)
;
}
int const MAX_SIZE = sizeof("340282366920938463463374607431768211456") - 1; // 2^128
*dest = INTC_U128_ZERO;
for (int index = 0, digits_written = 0;
index < size;
index++)
{
if (digits_written >= MAX_SIZE)
return true;
char digit = string[index];
if (separator != 0 && digit == separator)
continue;
intc_u64 value = (digit >= '0' && digit <= '9') ? (digit - '0') : 0xFF;
if (value == 0xFF)
return false;
*dest = intc_u128_mul_u64(*dest, 10);
*dest = intc_u128_add_u64(*dest, value);
digits_written++;
}
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(!"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.data[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.data[val.size++] = "0123456789abcdefghijklmnopqrstuvwxyz"[div_result.rem.lo];
if (separate_ch && 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.data[val.size++] = separate_ch;
}
} while (INTC_API_PREFIX(128_as_bool)(div_result.quot));
}
INTC_ASSERT(val.size < (int)sizeof(val.data) - 1);
struct intc_u128_string result;
result.size = 0;
for (int i = val.size - 1; i >= 0; i--)
result.data[result.size++] = val.data[i];
result.data[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_hex_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_hex_cstring)(buffer, half_buffer_size, &dest->hi);
result |= INTC_API_PREFIX(128_init_hex_cstring)(buffer + half_buffer_size, half_buffer_size, &dest->lo);
return result;
}
INTC_API bool INTC_API_PREFIX(256_init_hex_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_init_cstring)(char const *string, int size, struct intc_u256 *dest, char separator)
{
if (string == 0 || size == 0 || !dest)
return false;
if (size < 0) {
for (size = 0; string[size]; size++)
;
}
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, separator);
result |= INTC_API_PREFIX(128_init_cstring)(buffer + half_buffer_size, half_buffer_size, &dest->lo, separator);
return result;
}
INTC_API bool INTC_API_PREFIX(256_as_bool)(struct intc_u256 in)
{
bool result = (bool)((unsigned)INTC_API_PREFIX(128_as_bool)(in.lo) |
(unsigned)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 = (bool)((unsigned)INTC_API_PREFIX(128_neq)(lhs.lo, rhs.lo) |
(unsigned)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 = (bool)((unsigned)INTC_API_PREFIX(256_gt)(lhs, rhs) |
(unsigned)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(!"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 = INTC_ZERO_INIT;
if ((base < 2) || (base > 36))
return val;
if (INTC_API_PREFIX(256_eq)(in, INTC_U256_ZERO)) {
val.data[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.data[val.size++] = "0123456789abcdefghijklmnopqrstuvwxyz"[INTC_API_PREFIX(128_as_u32)(div_result.rem.lo)];
if (separate_ch && 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.data[val.size++] = separate_ch;
}
} while (INTC_API_PREFIX(256_as_bool)(div_result.quot));
}
INTC_ASSERT(val.size <= (int)(sizeof(val.data) - 1));
struct intc_u256_string result;
result.size = 0;
for (int i = val.size - 1; i >= 0; i--)
result.data[result.size++] = val.data[i];
result.data[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