libzahl

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

zstr.c (2963B)


      1 /* See LICENSE file for copyright and license details. */
      2 #include "internals.h"
      3 
      4 #include <stdio.h>
      5 
      6 #define num  libzahl_tmp_str_num
      7 #define rem  libzahl_tmp_str_rem
      8 
      9 /* All 19 you see here is derived from that 10¹⁹ is the largest
     10  * power of than < 2⁶⁴, and 64 is the number of bits in
     11  * zahl_char_t. If zahl_char_t is chanced, the value 19, and
     12  * the cast to unsigned long long must be changed accordingly. */
     13 
     14 
     15 #define S1(P)     P"0"    P"1"    P"2"    P"3"    P"4"    P"5"    P"6"    P"7"    P"8"    P"9"
     16 #define S2(P)  S1(P"0")S1(P"1")S1(P"2")S1(P"3")S1(P"4")S1(P"5")S1(P"6")S1(P"7")S1(P"8")S1(P"9")
     17 
     18 
     19 static inline O2 void
     20 sprintint_fix(char *buf, zahl_char_t v)
     21 {
     22 	const char *partials = S2("");
     23 	uint16_t *buffer = (uint16_t *)(buf + 1);
     24 
     25 	buffer[8] = *(const uint16_t *)(partials + 2 * (v % 100)), v /= 100;
     26 	buffer[7] = *(const uint16_t *)(partials + 2 * (v % 100)), v /= 100;
     27 	buffer[6] = *(const uint16_t *)(partials + 2 * (v % 100)), v /= 100;
     28 	buffer[5] = *(const uint16_t *)(partials + 2 * (v % 100)), v /= 100;
     29 	buffer[4] = *(const uint16_t *)(partials + 2 * (v % 100)), v /= 100;
     30 	buffer[3] = *(const uint16_t *)(partials + 2 * (v % 100)), v /= 100;
     31 	buffer[2] = *(const uint16_t *)(partials + 2 * (v % 100)), v /= 100;
     32 	buffer[1] = *(const uint16_t *)(partials + 2 * (v % 100)), v /= 100;
     33 	buffer[0] = *(const uint16_t *)(partials + 2 * (v % 100)), v /= 100;
     34 	*buf = (char)('0' + v);
     35 	buf[19] = 0;
     36 }
     37 
     38 static inline void
     39 cmemmove(char *d, const char *s, long n)
     40 {
     41 	while (n--)
     42 		*d++ = *s++;
     43 }
     44 
     45 static inline size_t
     46 sprintint_min(char *buf, zahl_char_t v)
     47 {
     48 	long i = 0, j;
     49 	sprintint_fix(buf, v);
     50 	for (; buf[i] == '0'; i++);
     51 	cmemmove(buf, buf + i, j = 19 - i);
     52 	buf[j] = 0;
     53 	return (size_t)j;
     54 }
     55 
     56 
     57 char *
     58 zstr(z_t a, char *b, size_t n)
     59 {
     60 	char buf[19 + 1];
     61 	size_t len, neg, last, tot = 0;
     62 	char overridden = 0;
     63 
     64 	if (unlikely(zzero(a))) {
     65 		if (unlikely(!b) && unlikely(!(b = malloc(2))))
     66 			libzahl_memfailure();
     67 		b[0] = '0';
     68 		b[1] = 0;
     69 		return b;
     70 	}
     71 
     72 	if (!n) {
     73 		/* Calculate a value that is at least the number of
     74 		 * digits required to store the string. The overshoot
     75 		 * is not too signicant. */
     76 		n = (20 * BITS_PER_CHAR / 64 + (BITS_PER_CHAR == 8)) * a->used;
     77 		/* Note, depends on a ≠ as ensure above. */
     78 	}
     79 
     80 	if (unlikely(!b) && unlikely(!(b = libzahl_temp_allocation = malloc(n + 1))))
     81 		libzahl_memfailure();
     82 
     83 	neg = znegative(a);
     84 	zabs(num, a);
     85 	b[0] = '-';
     86 	b += neg;
     87 	n -= neg;
     88 	n = (last = n) > 19 ? (n - 19) : 0;
     89 
     90 	for (;;) {
     91 		zdivmod(num, rem, num, libzahl_const_1e19);
     92 		if (likely(!zzero(num))) {
     93 			sprintint_fix(b + n, zzero(rem) ? 0 : rem->chars[0]);
     94 			b[n + 19] = overridden;
     95 			overridden = b[n];
     96 			n = (last = n) > 19 ? (n - 19) : 0;
     97 			tot += 19;
     98 		} else {
     99 			len = sprintint_min(buf, rem->chars[0]);
    100 			if (tot) {
    101 				memcpy(b, buf, len);
    102 				memmove(b + len, b + last, tot + 1);
    103 			} else {
    104 				memcpy(b, buf, len + 1);
    105 			}
    106 			break;
    107 		}
    108 	}
    109 
    110 	libzahl_temp_allocation = 0;
    111 	return b - neg;
    112 }