libzahl

big integer library
git clone git://git.suckless.org/libzahl
Log | Files | Refs | README | LICENSE

internals.h (11600B)


      1 /* See LICENSE file for copyright and license details. */
      2 #include "../zahl.h"
      3 
      4 #include <errno.h>
      5 #include <stdlib.h>
      6 #include <string.h>
      7 
      8 /* clang pretends to be GCC... */
      9 #if defined(__GNUC__) && defined(__clang__)
     10 # undef __GNUC__
     11 #endif
     12 
     13 #define BITS_PER_CHAR                ZAHL_BITS_PER_CHAR
     14 #define LB_BITS_PER_CHAR             ZAHL_LB_BITS_PER_CHAR
     15 
     16 #define FLOOR_BITS_TO_CHARS(bits)    ZAHL_FLOOR_BITS_TO_CHARS(bits)
     17 #define CEILING_BITS_TO_CHARS(bits)  ZAHL_CEILING_BITS_TO_CHARS(bits)
     18 #define BITS_IN_LAST_CHAR(bits)      ZAHL_BITS_IN_LAST_CHAR(bits)
     19 #define TRUNCATE_TO_CHAR(bits)       ZAHL_TRUNCATE_TO_CHAR(bits)
     20 
     21 #define O0     ZAHL_O0
     22 #define O1     ZAHL_O1
     23 #define O2     ZAHL_O2
     24 #define O3     ZAHL_O3
     25 #define Ofast  ZAHL_Ofast
     26 #define Os     ZAHL_Os
     27 #define Oz     ZAHL_Oz
     28 
     29 #define LIST_TEMPS_HERE\
     30 	X(libzahl_tmp_str_num, 0)\
     31 	X(libzahl_tmp_str_mag, 0)\
     32 	X(libzahl_tmp_str_div, 0)\
     33 	X(libzahl_tmp_str_rem, 0)\
     34 	X(libzahl_tmp_gcd_u, 0)\
     35 	X(libzahl_tmp_gcd_v, 0)\
     36 	X(libzahl_tmp_sub, 0)\
     37 	X(libzahl_tmp_modmul, 0)\
     38 	X(libzahl_tmp_pow_b, 0)\
     39 	X(libzahl_tmp_pow_c, 0)\
     40 	X(libzahl_tmp_pow_d, 0)\
     41 	X(libzahl_tmp_modsqr, 0)\
     42 	X(libzahl_tmp_divmod_a, 0)\
     43 	X(libzahl_tmp_divmod_b, 0)\
     44 	X(libzahl_tmp_divmod_d, 0)\
     45 	X(libzahl_tmp_ptest_x, 0)\
     46 	X(libzahl_tmp_ptest_a, 0)\
     47 	X(libzahl_tmp_ptest_d, 0)\
     48 	X(libzahl_tmp_ptest_n1, 0)\
     49 	X(libzahl_tmp_ptest_n4, 0)
     50 
     51 #define LIST_TEMPS\
     52 	X(libzahl_tmp_div, 0)\
     53 	X(libzahl_tmp_mod, 0)\
     54 	LIST_TEMPS_HERE
     55 
     56 #define LIST_CONSTS\
     57 	X(0, libzahl_const_1e19, zsetu, 10000000000000000000ULL) /* The largest power of 10 < 2⁶⁴. */\
     58 	X(1, libzahl_const_1,    zsetu, 1)\
     59 	X(2, libzahl_const_2,    zsetu, 2)\
     60 	X(3, libzahl_const_4,    zsetu, 4)
     61 
     62 #define X(x, s)  extern z_t x;
     63 LIST_TEMPS_HERE
     64 #undef X
     65 #define X(i, x, f, v)  extern z_t x;
     66 LIST_CONSTS
     67 #undef X
     68 
     69 extern z_t libzahl_tmp_divmod_ds[BITS_PER_CHAR];
     70 extern jmp_buf libzahl_jmp_buf;
     71 extern int libzahl_set_up;
     72 extern int libzahl_error;
     73 extern zahl_char_t **libzahl_pool[sizeof(size_t) * 8];
     74 extern size_t libzahl_pool_n[sizeof(size_t) * 8];
     75 extern size_t libzahl_pool_alloc[sizeof(size_t) * 8];
     76 extern struct zahl **libzahl_temp_stack;
     77 extern struct zahl **libzahl_temp_stack_head;
     78 extern struct zahl **libzahl_temp_stack_end;
     79 extern void *libzahl_temp_allocation;
     80 
     81 #define likely(expr)                 ZAHL_LIKELY(expr)
     82 #define unlikely(expr)               ZAHL_UNLIKELY(expr)
     83 
     84 #if defined(ZAHL_UNSAFE)
     85 # define check(expr)                 0
     86 #else
     87 # define check(expr)                 unlikely(expr)
     88 #endif
     89 
     90 #define SET_SIGNUM(a, signum)        ZAHL_SET_SIGNUM(a, signum)
     91 #define SET(a, b)                    ZAHL_SET(a, b)
     92 #define ENSURE_SIZE(a, n)            ZAHL_ENSURE_SIZE(a, n)
     93 #define TRIM(a)                      ZAHL_TRIM(a)
     94 #define TRIM_NONZERO(a)              ZAHL_TRIM_NONZERO(a)
     95 #define TRIM_AND_ZERO(a)             ZAHL_TRIM_AND_ZERO(a)
     96 #define TRIM_AND_SIGN(a, s)          ZAHL_TRIM_AND_SIGN(a, s)
     97 #define SWAP(a, b, t, m)             ((t)->m = (a)->m, (a)->m = (b)->m, (b)->m = (t)->m)
     98 #define MIN(a, b)                    ((a) < (b) ? (a) : (b))
     99 #define MAX(a, b)                    ((a) > (b) ? (a) : (b))
    100 #define MIN_MAX_1(min, max, a, b)    ((min) = MIN(a, b), (max) = MAX(a, b))
    101 #define MIN_MAX_2(min, max, a, b)    ((min) = (a) + (b) - ((max) = MAX(a, b)))
    102 #define znegative(a)                 (zsignum(a) < 0)
    103 #define znegative1(a, b)             ((zsignum(a) | zsignum(b)) < 0)
    104 #define znegative2(a, b)             ((zsignum(a) & zsignum(b)) < 0)
    105 #define zpositive(a)                 (zsignum(a) > 0)
    106 #define zpositive1(a, b)             (zpositive(a) + zpositive(b) > 0)
    107 #define zpositive2(a, b)             (zsignum(a) + zsignum(b) == 2)
    108 #define zzero2(a, b)                 (!(zsignum(a) | zsignum(b)))
    109 #define zmemcpy(d, s, n)             libzahl_memcpy(d, s, n)
    110 #define zmemmove(d, s, n)            libzahl_memmove(d, s, n)
    111 #define zmemmovef(d, s, n)           libzahl_memmovef(d, s, n)
    112 #define zmemmoveb(d, s, n)           libzahl_memmoveb(d, s, n)
    113 #define zmemset(a, v, n)             libzahl_memset(a, v, n)
    114 #define zmemset_precise(a, v, n)     libzahl_memset_precise(a, v, n)
    115 
    116 static inline int
    117 zzero1(z_t a, z_t b)
    118 {
    119 	return zzero(a) || zzero(b);
    120 }
    121 
    122 static inline void
    123 zmemcpy_range(register zahl_char_t *restrict d, register const zahl_char_t *restrict s, size_t i, size_t n)
    124 {
    125 	d += i;
    126 	s += i;
    127 	n -= i;
    128 	zmemcpy(d, s, n);
    129 }
    130 
    131 static void
    132 libzahl_failure(int error)
    133 {
    134 	libzahl_error = (error);
    135 	if (libzahl_temp_stack)
    136 		while (libzahl_temp_stack_head != libzahl_temp_stack)
    137 			zfree(*--libzahl_temp_stack_head);
    138 	free(libzahl_temp_allocation);
    139 	libzahl_temp_allocation = 0;
    140 	longjmp(libzahl_jmp_buf, 1);
    141 }
    142 
    143 static inline void
    144 libzahl_memfailure(void)
    145 {
    146 	if (!errno) /* sigh... */
    147 		errno = ENOENT;
    148 	libzahl_failure(errno);
    149 }
    150 
    151 /*
    152  * libzahl_msb_nz_zu
    153  *         ^^^ ^^ ^^
    154  *         |   |  |
    155  *         |   |  \- size_t parameter
    156  *         |   \- non-zero input
    157  *         \- most significant bit
    158  */
    159 
    160 #if SIZE_MAX == ULONG_MAX
    161 # define libzahl_msb_nz_zu(x)        libzahl_msb_nz_lu(x)
    162 #else
    163 # define libzahl_msb_nz_zu(x)        libzahl_msb_nz_llu(x)
    164 #endif
    165 
    166 #if defined(__GNUC__) || defined(__clang__)
    167 # define libzahl_msb_nz_lu(x)        (8 * sizeof(unsigned long int) - 1 - (size_t)__builtin_clzl(x))
    168 # define libzahl_msb_nz_llu(x)       (8 * sizeof(unsigned long long int) - 1 - (size_t)__builtin_clzll(x))
    169 #else
    170 static inline size_t
    171 libzahl_msb_nz_lu(unsigned long int x)
    172 {
    173 	size_t r = 0;
    174 	for (; x; x >>= 1, r++);
    175 	return r - 1;
    176 }
    177 
    178 static inline size_t
    179 libzahl_msb_nz_llu(unsigned long long int x)
    180 {
    181 	size_t r = 0;
    182 	for (; x; x >>= 1, r++);
    183 	return r - 1;
    184 }
    185 #endif
    186 
    187 #if defined(__GNUC__) || defined(__clang__)
    188 # if INT64_MAX == LONG_MAX
    189 #  define libzahl_add_overflow(rp, a, b)  __builtin_uaddl_overflow(a, b, rp)
    190 # else
    191 #  define libzahl_add_overflow(rp, a, b)  __builtin_uaddll_overflow(a, b, rp)
    192 # endif
    193 #else
    194 static inline int
    195 libzahl_add_overflow(zahl_char_t *rp, zahl_char_t a, zahl_char_t b)
    196 {
    197 	int carry = ZAHL_CHAR_MAX - a < b;
    198 	*rp = a + b;
    199 	return carry;
    200 }
    201 #endif
    202 
    203 static inline void
    204 zsplit_pz(z_t high, z_t low, z_t a, size_t delim)
    205 {
    206 	if (unlikely(zzero(a))) {
    207 		SET_SIGNUM(high, 0);
    208 		SET_SIGNUM(low, 0);
    209 	} else {
    210 		zsplit(high, low, a, delim);
    211 	}
    212 }
    213 
    214 static inline void
    215 zrsh_taint(z_t a, size_t bits)
    216 {
    217 	size_t i, chars, cbits;
    218 
    219 	if (unlikely(!bits))
    220 		return;
    221 	if (unlikely(zzero(a)))
    222 		return;
    223 
    224 	chars = FLOOR_BITS_TO_CHARS(bits);
    225 
    226 	if (unlikely(chars >= a->used || zbits(a) <= bits)) {
    227 		SET_SIGNUM(a, 0);
    228 		return;
    229 	}
    230 
    231 	bits = BITS_IN_LAST_CHAR(bits);
    232 	cbits = BITS_PER_CHAR - bits;
    233 
    234 	if (likely(chars)) {
    235 		a->used -= chars;
    236 		a->chars += chars;
    237 	}
    238 
    239 	if (unlikely(bits)) { /* This if statement is very important in C. */
    240 		a->chars[0] >>= bits;
    241 		for (i = 1; i < a->used; i++) {
    242 			a->chars[i - 1] |= a->chars[i] << cbits;
    243 			a->chars[i] >>= bits;
    244 		}
    245 		TRIM_NONZERO(a);
    246 	}
    247 }
    248 
    249 static inline void
    250 zswap_tainted_unsigned(z_t a, z_t b)
    251 {
    252 	z_t t;
    253 	SWAP(a, b, t, used);
    254 	SWAP(b, a, t, chars);
    255 }
    256 
    257 static inline void
    258 zsplit_unsigned_fast_large_taint(z_t high, z_t low, z_t a, size_t n)
    259 {
    260 	n >>= LB_BITS_PER_CHAR;
    261 	high->sign = 1;
    262 	high->used = a->used - n;
    263 	high->chars = a->chars + n;
    264 #if 0
    265 	TRIM_AND_ZERO(high);
    266 #endif
    267 	low->sign = 1;
    268 	low->used = n;
    269 	low->chars = a->chars;
    270 	TRIM_AND_ZERO(low);
    271 }
    272 
    273 static inline void
    274 zsplit_unsigned_fast_small_auto(z_t high, z_t low, z_t a, size_t n)
    275 {
    276 	zahl_char_t mask = 1;
    277 	mask = (mask << n) - 1;
    278 
    279 	high->sign = 1;
    280 	high->used = 1;
    281 	high->chars[0] = a->chars[0] >> n;
    282 	if (a->used == 2) {
    283 		high->chars[1] = a->chars[1] >> n;
    284 		high->used += !!high->chars[1];
    285 		n = BITS_PER_CHAR - n;
    286 		high->chars[0] |= (a->chars[1] & mask) << n;
    287 	}
    288 #if 0
    289 	if (unlikely(!high->chars[high->used - 1]))
    290 		high->sign = 0;
    291 #endif
    292 
    293 	low->sign = 1;
    294 	low->used = 1;
    295 	low->chars[0] = a->chars[0] & mask;
    296 	if (unlikely(!low->chars[0]))
    297 		low->sign = 0;
    298 }
    299 
    300 /* Calls to these functions must be called in stack-order
    301  * For example, 
    302  * 
    303  *   zinit_temp(a);
    304  *   zinit_temp(b);
    305  *   zfree_temp(b);
    306  *   zinit_temp(c);
    307  *   zfree_temp(c);
    308  *   zfree_temp(a);
    309  * 
    310  * And not (swap the two last lines)
    311  * 
    312  *   zinit_temp(a);
    313  *   zinit_temp(b);
    314  *   zfree_temp(b);
    315  *   zinit_temp(c);
    316  *   zfree_temp(a);
    317  *   zfree_temp(c);
    318  * 
    319  * { */
    320 
    321 static inline void
    322 zinit_temp(z_t a)
    323 {
    324 	zinit(a);
    325 	if (unlikely(libzahl_temp_stack_head == libzahl_temp_stack_end)) {
    326 		size_t n = (size_t)(libzahl_temp_stack_end - libzahl_temp_stack);
    327 		void* old = libzahl_temp_stack;
    328 		libzahl_temp_stack = realloc(old, 2 * n * sizeof(*libzahl_temp_stack));
    329 		if (check(!libzahl_temp_stack)) {
    330 			libzahl_temp_stack = old;
    331 			libzahl_memfailure();
    332 		}
    333 		libzahl_temp_stack_head = libzahl_temp_stack + n;
    334 		libzahl_temp_stack_end = libzahl_temp_stack_head + n;
    335 	}
    336 	*libzahl_temp_stack_head++ = a;
    337 }
    338 
    339 static inline void
    340 zfree_temp(z_t a)
    341 {
    342 	zfree(a);
    343 	libzahl_temp_stack_head--;
    344 }
    345 
    346 /* } */
    347 
    348 #define ZMEM_2OP_PRECISE(a, b, c, n, OP)                                      \
    349 	do {                                                                  \
    350 		zahl_char_t *a__ = (a);                                       \
    351 		const zahl_char_t *b__ = (b);                                 \
    352 		const zahl_char_t *c__ = (c);                                 \
    353 		size_t i__, n__ = (n);                                        \
    354 		if (n__ <= 4) {                                               \
    355 			if (n__ >= 1)                                         \
    356 				a__[0] = b__[0] OP c__[0];                    \
    357 			if (n__ >= 2)                                         \
    358 				a__[1] = b__[1] OP c__[1];                    \
    359 			if (n__ >= 3)                                         \
    360 				a__[2] = b__[2] OP c__[2];                    \
    361 			if (n__ >= 4)                                         \
    362 				a__[3] = b__[3] OP c__[3];                    \
    363 		} else {                                                      \
    364 			for (i__ = 0; (i__ += 4) < n__;) {                    \
    365 				a__[i__ - 1] = b__[i__ - 1] OP c__[i__ - 1];  \
    366 				a__[i__ - 2] = b__[i__ - 2] OP c__[i__ - 2];  \
    367 				a__[i__ - 3] = b__[i__ - 3] OP c__[i__ - 3];  \
    368 				a__[i__ - 4] = b__[i__ - 4] OP c__[i__ - 4];  \
    369 			}                                                     \
    370 			if (i__ > n__)                                        \
    371 				for (i__ -= 4; i__ < n__; i__++)              \
    372 					a__[i__] = b__[i__] OP c__[i__];      \
    373 		}                                                             \
    374 	} while (0)
    375 
    376 #define ZMEM_2OP(a, b, c, n, OP)                                      \
    377 	do {                                                          \
    378 		zahl_char_t *a__ = (a);                               \
    379 		const zahl_char_t *b__ = (b);                         \
    380 		const zahl_char_t *c__ = (c);                         \
    381 		size_t i__, n__ = (n);                                \
    382 		for (i__ = 0; i__ < n__; i__ += 4) {                  \
    383 			a__[i__ + 0] = b__[i__ + 0] OP c__[i__ + 0];  \
    384 			a__[i__ + 1] = b__[i__ + 1] OP c__[i__ + 1];  \
    385 			a__[i__ + 2] = b__[i__ + 2] OP c__[i__ + 2];  \
    386 			a__[i__ + 3] = b__[i__ + 3] OP c__[i__ + 3];  \
    387 		}                                                     \
    388 	} while (0)
    389 
    390 #define ZMEM_1OP(a, b, n, OP)                             \
    391 	do {                                              \
    392 		zahl_char_t *a__ = (a);                   \
    393 		const zahl_char_t *b__ = (b);             \
    394 		size_t i__, n__ = (n);                    \
    395 		for (i__ = 0; i__ < n__; i__ += 4) {      \
    396 			a__[i__ + 0] = OP(b__[i__ + 0]);  \
    397 			a__[i__ + 1] = OP(b__[i__ + 1]);  \
    398 			a__[i__ + 2] = OP(b__[i__ + 2]);  \
    399 			a__[i__ + 3] = OP(b__[i__ + 3]);  \
    400 		}                                         \
    401 	} while (0)