zstr.c - libzahl - big integer library
 (HTM) git clone git://git.suckless.org/libzahl
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) 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 }