From db2de5787d1866de01ecda740af5ca48e18b2eaf Mon Sep 17 00:00:00 2001 From: "hyunghwan.chung" Date: Wed, 4 Nov 2015 17:32:28 +0000 Subject: [PATCH] added more code to stix_strtoint() --- stix/lib/bigint.c | 198 ++++++++++++++++++++++++++++++++++---------- stix/lib/main.c | 7 +- stix/lib/stix-cmn.h | 106 +++++++++++++++++++++++- stix/lib/stix-prv.h | 6 ++ 4 files changed, 269 insertions(+), 48 deletions(-) diff --git a/stix/lib/bigint.c b/stix/lib/bigint.c index 2a08c49..fbf0558 100644 --- a/stix/lib/bigint.c +++ b/stix/lib/bigint.c @@ -31,6 +31,56 @@ /*#define IS_POWER_OF_2(ui) (((ui) > 0) && (((ui) & (~(ui)+ 1)) == (ui)))*/ #define IS_POWER_OF_2(ui) (((ui) > 0) && ((ui) & ((ui) - 1)) == 0) /* unsigned integer only */ +#if (STIX_SIZEOF_OOW_T == STIX_SIZEOF_INT) && defined(STIX_HAVE_BUILTIN_UADD_OVERFLOW) +# define oow_add_overflow(a,b,c) __builtin_uadd_overflow(a,b,c) +#elif (STIX_SIZEOF_OOW_T == STIX_SIZEOF_LONG) && defined(STIX_HAVE_BUILTIN_UADDL_OVERFLOW) +# define oow_add_overflow(a,b,c) __builtin_uaddl_overflow(a,b,c) +#elif (STIX_SIZEOF_OOW_T == STIX_SIZEOF_LONG_LONG) && defined(STIX_HAVE_BUILTIN_UADDLL_OVERFLOW) +# define oow_add_overflow(a,b,c) __builtin_uaddll_overflow(a,b,c) +#else +static STIX_INLINE int oow_add_overflow (stix_oow_t a, stix_oow_t b, stix_oow_t* c) +{ + *c = a + b; + return b > STIX_TYPE_MAX(stix_oow_t) - a; +} +#endif + +#if (STIX_SIZEOF_OOHW_T == STIX_SIZEOF_INT) && defined(STIX_HAVE_BUILTIN_UADD_OVERFLOW) +# define oohw_add_overflow(a,b,c) __builtin_uadd_overflow(a,b,c) +#elif (STIX_SIZEOF_OOHW_T == STIX_SIZEOF_LONG) && defined(STIX_HAVE_BUILTIN_UADDL_OVERFLOW) +# define oohw_add_overflow(a,b,c) __builtin_uaddl_overflow(a,b,c) +#elif (STIX_SIZEOF_OOHW_T == STIX_SIZEOF_LONG_LONG) && defined(STIX_HAVE_BUILTIN_UADDLL_OVERFLOW) +# define oohw_add_overflow(a,b,c) __builtin_uaddll_overflow(a,b,c) +#else +static STIX_INLINE int oohw_add_overflow (stix_oohw_t a, stix_oohw_t b, stix_oohw_t* c) +{ + *c = a + b; + return b > STIX_TYPE_MAX(stix_oohw_t) - a; +} +#endif + +#if (STIX_SIZEOF_OOW_T == STIX_SIZEOF_INT) && defined(STIX_HAVE_BUILTIN_UMUL_OVERFLOW) +# define oow_mul_overflow(a,b,c) __builtin_umul_overflow(a,b,c) +#elif (STIX_SIZEOF_OOW_T == STIX_SIZEOF_LONG) && defined(STIX_HAVE_BUILTIN_UMULL_OVERFLOW) +# define oow_mul_overflow(a,b,c) __builtin_umull_overflow(a,b,c) +#elif (STIX_SIZEOF_OOW_T == STIX_SIZEOF_LONG_LONG) && defined(STIX_HAVE_BUILTIN_UMULLL_OVERFLOW) +# define oow_mul_overflow(a,b,c) __builtin_umulll_overflow(a,b,c) +#else +static STIX_INLINE int oow_mul_overflow (stix_oow_t a, stix_oow_t b, stix_oow_t* c) +{ +#if (STIX_SIZEOF_UINTMAX_T > STIX_SIZEOF_OOW_T) + stix_uintmax_t k; + k = (stix_uintmax_t)a * (stix_uintmax_t)b; + *c = (stix_oow_t)k; + return (k >> STIX_OOW_BITS) > 0; + /*return k > STIX_TYPE_MAX(stix_oow_t);*/ +#else + *c = a * b; + return b > 0 && a > STIX_TYPE_MAX(stix_oow_t) / b; /* works for unsigned types only */ +#endif +} +#endif + static STIX_INLINE int is_integer (stix_t* stix, stix_oop_t oop) { stix_oop_t c; @@ -468,13 +518,23 @@ oops_einval: return STIX_NULL; } - +static stix_uint8_t ooch_val_tab[] = +{ + 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 99, 99, 99, 99, 99, 99, + 99, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 99, 99, 99, 99, 99, + 99, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 99, 99, 99, 99, 99 +}; stix_oop_t stix_strtoint (stix_t* stix, const stix_ooch_t* str, stix_oow_t len, unsigned int radix) { int neg = 0; const stix_ooch_t* ptr, * start, * end; - stix_oow_t w, v, r; + stix_oow_t w, v; stix_oohw_t hw[64]; stix_oow_t hwlen; @@ -506,14 +566,21 @@ stix_oop_t stix_strtoint (stix_t* stix, const stix_ooch_t* str, stix_oow_t len, return STIX_OOP_FROM_SMINT(0); } + hwlen = 0; + start = ptr; /* this is the real start */ + if (IS_POWER_OF_2(radix)) { unsigned int exp; + unsigned int bitcnt; /* get log2(radix) in a fast way under the fact that - * radix is a power of 2. */ - #if defined(__GNUC__) && (defined(__x86_64) || defined(__amd64) || defined(__i386) || defined(i386)) + * radix is a power of 2. the exponent acquired is + * the number of bits that a digit of the given radix takes up */ + #if defined(STIX_HAVE_BUILTIN_CTZ) + exp = __builtin_ctz(radix); + #elif defined(__GNUC__) && (defined(__x86_64) || defined(__amd64) || defined(__i386) || defined(i386)) /* use the Bit Scan Forward instruction */ __asm__ volatile ( "bsf %1,%0\n\t" @@ -521,24 +588,22 @@ stix_oop_t stix_strtoint (stix_t* stix, const stix_ooch_t* str, stix_oow_t len, : "r"(radix) /* input */ ); + #elif defined(USE_UGLY_CODE) && defined(__GNUC__) && defined(__arm__) && (defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_8__)) - #elif defined(USE_THIS_UGLY_CODE) && defined(__GNUC__) && defined(__arm__) && (defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_8__)) - - /* clz is available in ARMv5T and above */ + /* CLZ is available in ARMv5T and above. there is no instruction to + * count trailing zeros or something similar. using RBIT with CLZ + * would be good in ARMv6T2 and above to avoid further calculation + * afte CLZ */ __asm__ volatile ( "clz %0,%1\n\t" : "=r"(exp) /* output */ : "r"(radix) /* input */ ); - - /* TODO: in ARMv6T2 and above, RBIT can be used before clz to avoid this calculation */ exp = (STIX_SIZEOF(exp) * 8) - exp - 1; - /* TODO: PPC - use cntlz, cntlzw, cntlzd, SPARC - use lzcnt, MIPS clz */ #else - - static unsigned int exp_tab[] = + static stix_uint8_t exp_tab[] = { 0, 0, 1, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0 @@ -546,49 +611,102 @@ stix_oop_t stix_strtoint (stix_t* stix, const stix_ooch_t* str, stix_oow_t len, exp = exp_tab[radix]; #endif -printf ("<<%d>>>>>>\n",exp); - start = ptr; /* this is the real start */ + w = 0; + bitcnt = 0; ptr = end - 1; - hwlen = 0; - w = 0; - r = 1; while (ptr >= start) { - if (*ptr >= '0' && *ptr <= '9') v = *ptr - '0'; - else if (*ptr >= 'A' && *ptr <= 'Z') v = *ptr - 'A' + 10; - else if (*ptr >= 'a' && *ptr <= 'z') v = *ptr - 'a' + 10; - else goto oops_einval; - + if (*ptr < 0 || *ptr >= STIX_COUNTOF(ooch_val_tab)) goto oops_einval; + v = ooch_val_tab[*ptr]; if (v >= radix) goto oops_einval; - printf ("wwww=<<%lx>>", (long int)w); - w += v * r; - printf ("r=><<%lX>> v<<%lX>> w<<%lX>>\n", (long int)r, (long int)v, (long int)w); - if (w > STIX_TYPE_MAX(stix_oohw_t)) + w |= (v << bitcnt); + bitcnt += exp; + if (bitcnt >= STIX_OOHW_BITS) { + bitcnt -= STIX_OOHW_BITS; +/* TODO: grow hw if it's full OR + * i can estimate how much will be needed based on ext. so preallocate the buffer for these bases */ hw[hwlen++] = (stix_oohw_t)(w & STIX_LBMASK(stix_oow_t, STIX_OOHW_BITS)); - w = w >> STIX_OOHW_BITS; - if (w == 0) r = 1; - else r = radix; - } - else - { - r = r * radix; + w >>= STIX_OOHW_BITS; } ptr--; } STIX_ASSERT (w <= STIX_TYPE_MAX(stix_oohw_t)); - hw[hwlen++] = w; + if (hwlen == 0 || w > 0) hw[hwlen++] = w; } else { - /* TODO: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */ + stix_oow_t r1, r2; + stix_oohw_t multiplier; + int dg, i, max_ndigits; + + w = 0; + ptr = start; + +max_ndigits = 9; /* GET THIS */ +reqsize = (end - str) / max_ndigits + 1; +if (reqsize > STIX_COUNTF(hw)) hwp = malloc (reqsize * STIX_SIZEOF(stix_oohw_t)); + + multiplier = 1; + for (i = 0; i < max_ndigits; i++) multiplier *= radix; + + do + { + r1 = 0; + for (dg = 0; dg < max_ndigits; dg++) + { + if (ptr >= end) + { + multiplier = 1; + for (i = 0; i < dg; i++) multiplier *= radix; + break; + } + + if (*ptr < 0 || *ptr >= STIX_COUNTOF(ooch_val_tab)) goto oops_einval; + v = ooch_val_tab[*ptr]; + if (v >= radix) goto oops_einval; + + r1 = r1 * radix + (stix_oohw_t)v; + ptr++; + } + + r2 = r1; + for (i = 0; i < hwlen; i++) + { + stix_oohw_t high, low; + + v = (stix_oow_t)hw[i] * multiplier; + high = (stix_oohw_t)(v >> STIX_OOHW_BITS); + low = (stix_oohw_t)(v /*& STIX_LBMASK(stix_oow_t, STIX_OOHW_BITS)*/); + + #if defined(oohw_add_overflow) + /* use oohw_add_overflow() only if it's compiler-builtin. */ + r2 = high + oohw_add_overflow(low, r2, &low); + #else + /* don't use the fall-back version of oohw_add_overflow() */ + low += r2; + r2 = high + (low < r2); + #endif + + hw[i] = low; + } + if (r2) hw[hwlen++] = r2; + } + while (dg >= max_ndigits); } -/* +{ int i; +for (i = hwlen; i > 0;) +{ +printf ("%08x ", hw[--i]); +} +printf ("\n"); +} + if (hwlen == 1) return STIX_OOP_FROM_SMINT((stix_ooi_t)hw[0] * -neg); else if (hwlen == 2) { @@ -602,15 +720,7 @@ printf ("<<%d>>>>>>\n",exp); if (w <= STIX_SMINT_MAX) return STIX_OOP_FROM_SMINT(w); } } -*/ -{ int i; -for (i = hwlen; i > 0;) -{ -printf ("%x ", hw[--i]); -} -printf ("\n"); -} return stix_instantiate (stix, (neg? stix->_large_negative_integer: stix->_large_positive_integer), hw, hwlen); oops_einval: diff --git a/stix/lib/main.c b/stix/lib/main.c index f71505d..6fb9a84 100644 --- a/stix/lib/main.c +++ b/stix/lib/main.c @@ -465,7 +465,10 @@ int main (int argc, char* argv[]) { /*const stix_bch_t* xxx = "9999999999999999999999999999999999999999999999999999999999999999999999999999999999";*/ -const stix_bch_t* xxx = "7777777777777777777777777"; + +//const stix_bch_t* xxx = "2305843009213693953"; +const stix_bch_t* xxx = "184467440737095516161111"; + stix_ooch_t buf[10240]; stix_oow_t xxxlen; stix_oow_t buflen; @@ -473,7 +476,7 @@ stix_oow_t buflen; xxxlen = stix_countbcstr(xxx); buflen = STIX_COUNTOF(buf); stix_utf8toucs (xxx, &xxxlen, buf, &buflen); -stix_strtoint (stix, buf, buflen, 16); +dump_object (stix, stix_strtoint (stix, buf, buflen, 10), "STRINT"); } { stix_ooch_t x[] = { 'X', 't', 'r', 'i', 'n', 'g', '\0' }; diff --git a/stix/lib/stix-cmn.h b/stix/lib/stix-cmn.h index f7edbbe..cb38cc7 100644 --- a/stix/lib/stix-cmn.h +++ b/stix/lib/stix-cmn.h @@ -49,9 +49,13 @@ # endif #endif + + /* ========================================================================= * PRIMITIVE TYPE DEFINTIONS * ========================================================================= */ + +/* stix_int8_t */ #if defined(STIX_SIZEOF_CHAR) && (STIX_SIZEOF_CHAR == 1) # define STIX_HAVE_UINT8_T # define STIX_HAVE_INT8_T @@ -74,6 +78,8 @@ typedef signed char stix_int8_t; #endif + +/* stix_int16_t */ #if defined(STIX_SIZEOF_SHORT) && (STIX_SIZEOF_SHORT == 2) # define STIX_HAVE_UINT16_T # define STIX_HAVE_INT16_T @@ -97,6 +103,7 @@ #endif +/* stix_int32_t */ #if defined(STIX_SIZEOF_INT) && (STIX_SIZEOF_INT == 4) # define STIX_HAVE_UINT32_T # define STIX_HAVE_INT32_T @@ -129,7 +136,7 @@ typedef signed int stix_int32_t; #endif - +/* stix_int64_t */ #if defined(STIX_SIZEOF_INT) && (STIX_SIZEOF_INT == 8) # define STIX_HAVE_UINT64_T # define STIX_HAVE_INT64_T @@ -164,6 +171,7 @@ /* no 64-bit integer */ #endif +/* stix_int128_t */ #if defined(STIX_SIZEOF_INT) && (STIX_SIZEOF_INT == 16) # define STIX_HAVE_UINT128_T # define STIX_HAVE_INT128_T @@ -216,7 +224,7 @@ typedef stix_uint64_t stix_ushortptr_t; typedef stix_int64_t stix_shortptr_t; #else -# error UNSUPPORTED POINTER SIZE +# error UNKNOWN POINTER SIZE #endif #define STIX_SIZEOF_INTPTR_T STIX_SIZEOF_VOID_P @@ -224,6 +232,36 @@ #define STIX_SIZEOF_SHORTPTR_T (STIX_SIZEOF_VOID_P / 2) #define STIX_SIZEOF_USHORTPTR_T (STIX_SIZEOF_VOID_P / 2) +#if defined(STIX_HAVE_INT128_T) +# define STIX_SIZEOF_INTMAX_T 16 +# define STIX_SIZEOF_UINTMAX_T 16 + typedef stix_int128_t stix_intmax_t; + typedef stix_uint128_t stix_uintmax_t; +#elif defined(STIX_HAVE_INT64_T) +# define STIX_SIZEOF_INTMAX_T 8 +# define STIX_SIZEOF_UINTMAX_T 8 + typedef stix_int64_t stix_intmax_t; + typedef stix_uint64_t stix_uintmax_t; +#elif defined(STIX_HAVE_INT32_T) +# define STIX_SIZEOF_INTMAX_T 4 +# define STIX_SIZEOF_UINTMAX_T 4 + typedef stix_int32_t stix_intmax_t; + typedef stix_uint32_t stix_uintmax_t; +#elif defined(STIX_HAVE_INT16_T) +# define STIX_SIZEOF_INTMAX_T 2 +# define STIX_SIZEOF_UINTMAX_T 2 + typedef stix_int16_t stix_intmax_t; + typedef stix_uint16_t stix_uintmax_t; +#elif defined(STIX_HAVE_INT8_T) +# define STIX_SIZEOF_INTMAX_T 1 +# define STIX_SIZEOF_UINTMAX_T 1 + typedef stix_int8_t stix_intmax_t; + typedef stix_uint8_t stix_uintmax_t; +#else +# error UNKNOWN INTMAX SIZE +#endif + + typedef stix_uintptr_t stix_size_t; typedef stix_intptr_t stix_ssize_t; @@ -476,12 +514,17 @@ struct stix_cmgr_t * =========================================================================*/ typedef stix_uint8_t stix_oob_t; + /* NOTE: sizeof(stix_oop_t) must be equal to sizeof(stix_oow_t) */ typedef stix_uintptr_t stix_oow_t; typedef stix_intptr_t stix_ooi_t; +#define STIX_SIZEOF_OOW_T STIX_SIZEOF_UINTPTR_T +#define STIX_SIZEOF_OOI_T STIX_SIZEOF_INTPTR_T typedef stix_ushortptr_t stix_oohw_t; /* half word - half word */ typedef stix_shortptr_t stix_oohi_t; /* signed half word */ +#define STIX_SIZEOF_OOHW_T STIX_SIZEOF_USHORTPTR_T +#define STIX_SIZEOF_OOHI_T STIX_SIZEOF_SHORTPTR_T typedef stix_uch_t stix_ooch_t; typedef stix_uci_t stix_ooci_t; @@ -489,4 +532,63 @@ typedef stix_ucs_t stix_oocs_t; #define STIX_OOCH_IS_UCH +/* ========================================================================= + * COMPILER FEATURE TEST MACROS + * =========================================================================*/ +#if defined(__has_builtin) + #if __has_builtin(__builtin_ctz) + #define STIX_HAVE_BUILTIN_CTZ + #endif + #if __has_builtin(__builtin_uadd_overflow) + #define STIX_HAVE_BUILTIN_UADD_OVERFLOW + #endif + #if __has_builtin(__builtin_uaddl_overflow) + #define STIX_HAVE_BUILTIN_UADDL_OVERFLOW + #endif + #if __has_builtin(__builtin_uaddll_overflow) + #define STIX_HAVE_BUILTIN_UADDLL_OVERFLOW + #endif + #if __has_builtin(__builtin_umul_overflow) + #define STIX_HAVE_BUILTIN_UMUL_OVERFLOW + #endif + #if __has_builtin(__builtin_umull_overflow) + #define STIX_HAVE_BUILTIN_UMULL_OVERFLOW + #endif + #if __has_builtin(__builtin_umulll_overflow) + #define STIX_HAVE_BUILTIN_UMULLL_OVERFLOW + #endif + +#elif defined(__GNUC__) && defined(__GNUC_MINOR__) + + #if (__GNUC__ >= 5) + #define STIX_HAVE_BUILTIN_UADD_OVERFLOW + #define STIX_HAVE_BUILTIN_UADDL_OVERFLOW + #define STIX_HAVE_BUILTIN_UADDLL_OVERFLOW + #define STIX_HAVE_BUILTIN_UMUL_OVERFLOW + #define STIX_HAVE_BUILTIN_UMULL_OVERFLOW + #define STIX_HAVE_BUILTIN_UMULLL_OVERFLOW + #endif + + #if (__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) + #define STIX_HAVE_BUILTIN_CTZ + #endif +#endif + +/* +#if !defined(__has_builtin) + #define __has_builtin(x) 0 +#endif + + +#if !defined(__is_identifier) + #define __is_identifier(x) 0 +#endif + +#if !defined(__has_attribute) + #define __has_attribute(x) 0 +#endif +*/ + + + #endif diff --git a/stix/lib/stix-prv.h b/stix/lib/stix-prv.h index 9f1c18c..e6bf81e 100644 --- a/stix/lib/stix-prv.h +++ b/stix/lib/stix-prv.h @@ -1050,6 +1050,12 @@ stix_oop_t stix_subints ( stix_oop_t y ); +stix_oop_t stix_strtoint ( + stix_t* stix, + const stix_ooch_t* str, + stix_oow_t len, + unsigned int radix +); /* ========================================================================= */ /* comp.c */ /* ========================================================================= */