From 614c47bebcdb07e3d9de68d51a4acc4e819dcbf4 Mon Sep 17 00:00:00 2001 From: doyle Date: Mon, 27 Mar 2023 23:46:08 +1100 Subject: [PATCH] intc: Add number -> u128/256 constructor --- intc.h | 96 +++++++++++++++++++++++++++++++++++++++++++++------- intc_tests.c | 29 ++++++++++------ 2 files changed, 101 insertions(+), 24 deletions(-) diff --git a/intc.h b/intc.h index 2c2d41c..a82260e 100644 --- a/intc.h +++ b/intc.h @@ -191,7 +191,7 @@ struct intc_u128_divmod_result struct intc_u128_string { // NOTE: Max value 340,282,366,920,938,463,463,374,607,431,768,211,455 - char data[256 + 1]; + char data[63 + 1]; int size; }; @@ -220,11 +220,16 @@ struct intc_u128_string INTC_BEGIN_EXTERN_C // NOTE: U128 Converters // ----------------------------------------------------------------------------- -// Reminder: If INTC_API_PREFIX is not defined, example API looks like: intc_u128_init_cstring(...) +// 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_cstring)(const char *string, int size, struct intc_u128 *dest); +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. @@ -435,17 +440,22 @@ struct intc_u256_string INTC_BEGIN_EXTERN_C // NOTE: U256 Converters // ----------------------------------------------------------------------------- -// Reminder: If INTC_API_PREFIX is not defined, example API looks like: intc_u256_init_cstring(...) +// 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_cstring)(char const *string, int size, struct intc_u256 *dest); +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_cstring_base)(char const *string, int size, int base, struct intc_u256 *dest); +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. @@ -613,7 +623,7 @@ INTC_BEGIN_EXTERN_C // ----------------------------------------------------------------------------- // NOTE: U128 Converters // ----------------------------------------------------------------------------- -INTC_API bool INTC_API_PREFIX(128_init_cstring)(char const *string, int size, struct intc_u128 *dest) +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; @@ -651,6 +661,41 @@ INTC_API bool INTC_API_PREFIX(128_init_cstring)(char const *string, int size, st 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; @@ -1015,7 +1060,7 @@ INTC_API struct intc_u128_string INTC_API_PREFIX(128_str)(struct intc_u128 in, u 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_every_n_chars > 0 && INTC_API_PREFIX(128_as_bool)(div_result.quot)) { + 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; @@ -1266,7 +1311,7 @@ INTC_BEGIN_EXTERN_C // ----------------------------------------------------------------------------- // NOTE: U256 Converters // ----------------------------------------------------------------------------- -INTC_API bool INTC_API_PREFIX(256_init_cstring)(char const *string, int size, struct intc_u256 *dest) +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; @@ -1288,13 +1333,13 @@ INTC_API bool INTC_API_PREFIX(256_init_cstring)(char const *string, int size, st buffer[pad_length + string_index] = string[string_index]; int half_buffer_size = sizeof(buffer) / 2; - bool result = INTC_API_PREFIX(128_init_cstring)(buffer, half_buffer_size, &dest->hi); - result |= INTC_API_PREFIX(128_init_cstring)(buffer + half_buffer_size, half_buffer_size, &dest->lo); + 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_cstring_base)(char const *string, int size, int base, struct intc_u256 *dest) +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; @@ -1329,6 +1374,31 @@ INTC_API bool INTC_API_PREFIX(256_init_cstring_base)(char const *string, int siz 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) | @@ -1743,7 +1813,7 @@ INTC_API struct intc_u256_string INTC_API_PREFIX(256_str)(struct intc_u256 in, u 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_every_n_chars > 0 && INTC_API_PREFIX(256_as_bool)(div_result.quot)) { + 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; diff --git a/intc_tests.c b/intc_tests.c index 84f6d3c..6c29a5c 100644 --- a/intc_tests.c +++ b/intc_tests.c @@ -1199,30 +1199,37 @@ struct intc_test_state intc_u256_unit_tests(void) } { - INTC_TESTS_BEGIN("Constructor.string"); + INTC_TESTS_BEGIN("Constructor.dataing"); struct intc_u256 val; - INTC_TESTS_ASSERT(intc_u256_init_cstring("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", -1 /*size*/, &val)); + INTC_TESTS_ASSERT(intc_u256_init_hex_cstring("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", -1 /*size*/, &val)); INTC_TESTS_ASSERT_MSG(intc_u256_eq(val, INTC_U256_MAX), "val: %s\n" "expect: %s\n", intc_u256_readable_hex_str(val).data, intc_u256_readable_hex_str(INTC_U256_MAX).data); - INTC_TESTS_ASSERT(intc_u256_init_cstring("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", -1 /*size*/, &val)); + INTC_TESTS_ASSERT(intc_u256_init_hex_cstring("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", -1 /*size*/, &val)); INTC_TESTS_ASSERT_MSG(intc_u256_eq(val, INTC_U256_MAX), "val: %s\n" "expect: %s\n", intc_u256_readable_hex_str(val).data, intc_u256_readable_hex_str(INTC_U256_MAX).data); +<<<<<<< HEAD INTC_TESTS_ASSERT(intc_u256_init_cstring("0x0", -1 /*size*/, &val)); INTC_TESTS_ASSERT_MSG(intc_u256_eq(val, INTC_U256_ZERO), "val: %s\n", intc_u256_readable_hex_str(val).data); INTC_TESTS_ASSERT(intc_u256_init_cstring("0x0", -1 /*size*/, &val)); +======= + INTC_TESTS_ASSERT(intc_u256_init_hex_cstring("0x0", -1 /*size*/, &val)); + INTC_TESTS_ASSERT_MSG(intc_u256_eq(val, INTC_U256_ZERO), "val: %s\n", intc_u256_readable_hex_str(val).data); + + INTC_TESTS_ASSERT(intc_u256_init_hex_cstring("0x0", -1 /*size*/, &val)); +>>>>>>> f769dd0 (intc: Add number -> u128/256 constructor) INTC_TESTS_ASSERT_MSG(intc_u256_eq(val, INTC_U256_ZERO), "val: %s\n", intc_u256_readable_hex_str(val).data); struct intc_u256 expect = INTC_U64_TO_U256(0x0123456789abcdefULL); - INTC_TESTS_ASSERT(intc_u256_init_cstring("0x0123456789abcdef", -1 /*size*/, &val)); + INTC_TESTS_ASSERT(intc_u256_init_hex_cstring("0x0123456789abcdef", -1 /*size*/, &val)); INTC_TESTS_ASSERT_MSG(intc_u256_eq(val, expect), "val: %s\n" "expect: %s\n", @@ -1234,37 +1241,37 @@ struct intc_test_state intc_u256_unit_tests(void) { INTC_TESTS_BEGIN("Constructor.base_string"); struct intc_u256 val; - INTC_TESTS_ASSERT(intc_u256_init_cstring_base("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", -1 /*size*/, 16 /*base*/, &val)); + INTC_TESTS_ASSERT(intc_u256_init_hex_cstring_base("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", -1 /*size*/, 16 /*base*/, &val)); INTC_TESTS_ASSERT_MSG(intc_u256_eq(val, INTC_U256_MAX), "val: %s\n" "expect: %s\n", intc_u256_readable_hex_str(val).data, intc_u256_readable_hex_str(INTC_U256_MAX).data); - INTC_TESTS_ASSERT(intc_u256_init_cstring_base("115792089237316195423570985008687907853269984665640564039457584007913129639935", -1 /*size*/, 10 /*base*/, &val)); + INTC_TESTS_ASSERT(intc_u256_init_hex_cstring_base("115792089237316195423570985008687907853269984665640564039457584007913129639935", -1 /*size*/, 10 /*base*/, &val)); INTC_TESTS_ASSERT_MSG(intc_u256_eq(val, INTC_U256_MAX), "val: %s\n" "expect: %s\n", intc_u256_readable_hex_str(val).data, intc_u256_readable_hex_str(INTC_U256_MAX).data); - INTC_TESTS_ASSERT(intc_u256_init_cstring_base("1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", -1 /*size*/, 2 /*base*/, &val)); + INTC_TESTS_ASSERT(intc_u256_init_hex_cstring_base("1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", -1 /*size*/, 2 /*base*/, &val)); INTC_TESTS_ASSERT_MSG(intc_u256_eq(val, INTC_U256_MAX), "val: %s\n" "expect: %s\n", intc_u256_readable_hex_str(val).data, intc_u256_readable_hex_str(INTC_U256_MAX).data); - INTC_TESTS_ASSERT(intc_u256_init_cstring_base("0", -1 /*size*/, 10 /*base*/, &val)); + INTC_TESTS_ASSERT(intc_u256_init_hex_cstring_base("0", -1 /*size*/, 10 /*base*/, &val)); INTC_TESTS_ASSERT(intc_u256_eq(val, INTC_U256_ZERO)); - INTC_TESTS_ASSERT(intc_u256_init_cstring_base("0x0123456789abcdef", -1 /*size*/, 16 /*base*/, &val)); + INTC_TESTS_ASSERT(intc_u256_init_hex_cstring_base("0x0123456789abcdef", -1 /*size*/, 16 /*base*/, &val)); INTC_TESTS_ASSERT(intc_u256_eq(val, INTC_U64_TO_U256(0x0123456789abcdefULL))); - INTC_TESTS_ASSERT(intc_u256_init_cstring_base("755", -1 /*size*/, 8 /*base*/, &val)); + INTC_TESTS_ASSERT(intc_u256_init_hex_cstring_base("755", -1 /*size*/, 8 /*base*/, &val)); INTC_TESTS_ASSERT(intc_u256_eq(val, INTC_U64_TO_U256(0x01ed))); - INTC_TESTS_ASSERT(intc_u256_init_cstring_base("31415926", -1 /*size*/, 10 /*base*/, &val)); + INTC_TESTS_ASSERT(intc_u256_init_hex_cstring_base("31415926", -1 /*size*/, 10 /*base*/, &val)); INTC_TESTS_ASSERT(intc_u256_eq(val, INTC_U64_TO_U256(0x01df5e76ULL))); INTC_TESTS_END; }