2062 lines
76 KiB
C
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
|