quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

cutils.h (11097B)


      1 /*
      2  * C utilities
      3  *
      4  * Copyright (c) 2017 Fabrice Bellard
      5  * Copyright (c) 2018 Charlie Gordon
      6  *
      7  * Permission is hereby granted, free of charge, to any person obtaining a copy
      8  * of this software and associated documentation files (the "Software"), to deal
      9  * in the Software without restriction, including without limitation the rights
     10  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     11  * copies of the Software, and to permit persons to whom the Software is
     12  * furnished to do so, subject to the following conditions:
     13  *
     14  * The above copyright notice and this permission notice shall be included in
     15  * all copies or substantial portions of the Software.
     16  *
     17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     20  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     23  * THE SOFTWARE.
     24  */
     25 #ifndef CUTILS_H
     26 #define CUTILS_H
     27 
     28 #include <stddef.h>
     29 #include <stdlib.h>
     30 #include <string.h>
     31 #include <inttypes.h>
     32 
     33 #define likely(x)       __builtin_expect(!!(x), 1)
     34 #define unlikely(x)     __builtin_expect(!!(x), 0)
     35 #define force_inline inline __attribute__((always_inline))
     36 #define no_inline __attribute__((noinline))
     37 #define __maybe_unused __attribute__((unused))
     38 
     39 #define xglue(x, y) x ## y
     40 #define glue(x, y) xglue(x, y)
     41 #define stringify(s)    tostring(s)
     42 #define tostring(s)     #s
     43 
     44 #ifndef countof
     45 #define countof(x) (sizeof(x) / sizeof((x)[0]))
     46 #endif
     47 #ifndef container_of
     48 /* return the pointer of type 'type *' containing 'ptr' as field 'member' */
     49 #define container_of(ptr, type, member) ((type *)((uint8_t *)(ptr) - offsetof(type, member)))
     50 #endif
     51 
     52 #if !defined(_MSC_VER) && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
     53 #define minimum_length(n)  static n
     54 #else
     55 #define minimum_length(n)  n
     56 #endif
     57 
     58 typedef int BOOL;
     59 
     60 #ifndef FALSE
     61 enum {
     62     FALSE = 0,
     63     TRUE = 1,
     64 };
     65 #endif
     66 
     67 void pstrcpy(char *buf, int buf_size, const char *str);
     68 char *pstrcat(char *buf, int buf_size, const char *s);
     69 int strstart(const char *str, const char *val, const char **ptr);
     70 int has_suffix(const char *str, const char *suffix);
     71 
     72 /* Prevent UB when n == 0 and (src == NULL or dest == NULL) */
     73 static inline void memcpy_no_ub(void *dest, const void *src, size_t n) {
     74     if (n)
     75         memcpy(dest, src, n);
     76 }
     77 
     78 static inline int max_int(int a, int b)
     79 {
     80     if (a > b)
     81         return a;
     82     else
     83         return b;
     84 }
     85 
     86 static inline int min_int(int a, int b)
     87 {
     88     if (a < b)
     89         return a;
     90     else
     91         return b;
     92 }
     93 
     94 static inline uint32_t max_uint32(uint32_t a, uint32_t b)
     95 {
     96     if (a > b)
     97         return a;
     98     else
     99         return b;
    100 }
    101 
    102 static inline uint32_t min_uint32(uint32_t a, uint32_t b)
    103 {
    104     if (a < b)
    105         return a;
    106     else
    107         return b;
    108 }
    109 
    110 static inline int64_t max_int64(int64_t a, int64_t b)
    111 {
    112     if (a > b)
    113         return a;
    114     else
    115         return b;
    116 }
    117 
    118 static inline int64_t min_int64(int64_t a, int64_t b)
    119 {
    120     if (a < b)
    121         return a;
    122     else
    123         return b;
    124 }
    125 
    126 /* WARNING: undefined if a = 0 */
    127 static inline int clz32(unsigned int a)
    128 {
    129     return __builtin_clz(a);
    130 }
    131 
    132 /* WARNING: undefined if a = 0 */
    133 static inline int clz64(uint64_t a)
    134 {
    135     return __builtin_clzll(a);
    136 }
    137 
    138 /* WARNING: undefined if a = 0 */
    139 static inline int ctz32(unsigned int a)
    140 {
    141     return __builtin_ctz(a);
    142 }
    143 
    144 /* WARNING: undefined if a = 0 */
    145 static inline int ctz64(uint64_t a)
    146 {
    147     return __builtin_ctzll(a);
    148 }
    149 
    150 struct __attribute__((packed)) packed_u64 {
    151     uint64_t v;
    152 };
    153 
    154 struct __attribute__((packed)) packed_u32 {
    155     uint32_t v;
    156 };
    157 
    158 struct __attribute__((packed)) packed_u16 {
    159     uint16_t v;
    160 };
    161 
    162 static inline uint64_t get_u64(const uint8_t *tab)
    163 {
    164     return ((const struct packed_u64 *)tab)->v;
    165 }
    166 
    167 static inline int64_t get_i64(const uint8_t *tab)
    168 {
    169     return (int64_t)((const struct packed_u64 *)tab)->v;
    170 }
    171 
    172 static inline void put_u64(uint8_t *tab, uint64_t val)
    173 {
    174     ((struct packed_u64 *)tab)->v = val;
    175 }
    176 
    177 static inline uint32_t get_u32(const uint8_t *tab)
    178 {
    179     return ((const struct packed_u32 *)tab)->v;
    180 }
    181 
    182 static inline int32_t get_i32(const uint8_t *tab)
    183 {
    184     return (int32_t)((const struct packed_u32 *)tab)->v;
    185 }
    186 
    187 static inline void put_u32(uint8_t *tab, uint32_t val)
    188 {
    189     ((struct packed_u32 *)tab)->v = val;
    190 }
    191 
    192 static inline uint32_t get_u16(const uint8_t *tab)
    193 {
    194     return ((const struct packed_u16 *)tab)->v;
    195 }
    196 
    197 static inline int32_t get_i16(const uint8_t *tab)
    198 {
    199     return (int16_t)((const struct packed_u16 *)tab)->v;
    200 }
    201 
    202 static inline void put_u16(uint8_t *tab, uint16_t val)
    203 {
    204     ((struct packed_u16 *)tab)->v = val;
    205 }
    206 
    207 static inline uint32_t get_u8(const uint8_t *tab)
    208 {
    209     return *tab;
    210 }
    211 
    212 static inline int32_t get_i8(const uint8_t *tab)
    213 {
    214     return (int8_t)*tab;
    215 }
    216 
    217 static inline void put_u8(uint8_t *tab, uint8_t val)
    218 {
    219     *tab = val;
    220 }
    221 
    222 #ifndef bswap16
    223 static inline uint16_t bswap16(uint16_t x)
    224 {
    225     return (x >> 8) | (x << 8);
    226 }
    227 #endif
    228 
    229 #ifndef bswap32
    230 static inline uint32_t bswap32(uint32_t v)
    231 {
    232     return ((v & 0xff000000) >> 24) | ((v & 0x00ff0000) >>  8) |
    233         ((v & 0x0000ff00) <<  8) | ((v & 0x000000ff) << 24);
    234 }
    235 #endif
    236 
    237 #ifndef bswap64
    238 static inline uint64_t bswap64(uint64_t v)
    239 {
    240     return ((v & ((uint64_t)0xff << (7 * 8))) >> (7 * 8)) |
    241         ((v & ((uint64_t)0xff << (6 * 8))) >> (5 * 8)) |
    242         ((v & ((uint64_t)0xff << (5 * 8))) >> (3 * 8)) |
    243         ((v & ((uint64_t)0xff << (4 * 8))) >> (1 * 8)) |
    244         ((v & ((uint64_t)0xff << (3 * 8))) << (1 * 8)) |
    245         ((v & ((uint64_t)0xff << (2 * 8))) << (3 * 8)) |
    246         ((v & ((uint64_t)0xff << (1 * 8))) << (5 * 8)) |
    247         ((v & ((uint64_t)0xff << (0 * 8))) << (7 * 8));
    248 }
    249 #endif
    250 
    251 /* XXX: should take an extra argument to pass slack information to the caller */
    252 typedef void *DynBufReallocFunc(void *opaque, void *ptr, size_t size);
    253 
    254 typedef struct DynBuf {
    255     uint8_t *buf;
    256     size_t size;
    257     size_t allocated_size;
    258     BOOL error; /* true if a memory allocation error occurred */
    259     DynBufReallocFunc *realloc_func;
    260     void *opaque; /* for realloc_func */
    261 } DynBuf;
    262 
    263 void dbuf_init(DynBuf *s);
    264 void dbuf_init2(DynBuf *s, void *opaque, DynBufReallocFunc *realloc_func);
    265 int dbuf_claim(DynBuf *s, size_t len);
    266 int dbuf_put(DynBuf *s, const uint8_t *data, size_t len);
    267 int dbuf_put_self(DynBuf *s, size_t offset, size_t len);
    268 int dbuf_putstr(DynBuf *s, const char *str);
    269 int __dbuf_putc(DynBuf *s, uint8_t c);
    270 int __dbuf_put_u16(DynBuf *s, uint16_t val);
    271 int __dbuf_put_u32(DynBuf *s, uint32_t val);
    272 int __dbuf_put_u64(DynBuf *s, uint64_t val);
    273 
    274 static inline int dbuf_putc(DynBuf *s, uint8_t val)
    275 {
    276     if (unlikely((s->allocated_size - s->size) < 1)) {
    277         return __dbuf_putc(s, val);
    278     } else {
    279         s->buf[s->size++] = val;
    280         return 0;
    281     }
    282 }
    283 
    284 static inline int dbuf_put_u16(DynBuf *s, uint16_t val)
    285 {
    286     if (unlikely((s->allocated_size - s->size) < 2)) {
    287         return __dbuf_put_u16(s, val);
    288     } else {
    289         put_u16(s->buf + s->size, val);
    290         s->size += 2;
    291         return 0;
    292     }
    293 }
    294 
    295 static inline int dbuf_put_u32(DynBuf *s, uint32_t val)
    296 {
    297     if (unlikely((s->allocated_size - s->size) < 4)) {
    298         return __dbuf_put_u32(s, val);
    299     } else {
    300         put_u32(s->buf + s->size, val);
    301         s->size += 4;
    302         return 0;
    303     }
    304 }
    305 
    306 static inline int dbuf_put_u64(DynBuf *s, uint64_t val)
    307 {
    308     if (unlikely((s->allocated_size - s->size) < 8)) {
    309         return __dbuf_put_u64(s, val);
    310     } else {
    311         put_u64(s->buf + s->size, val);
    312         s->size += 8;
    313         return 0;
    314     }
    315 }
    316 
    317 int __attribute__((format(printf, 2, 3))) dbuf_printf(DynBuf *s,
    318                                                       const char *fmt, ...);
    319 void dbuf_free(DynBuf *s);
    320 static inline BOOL dbuf_error(DynBuf *s) {
    321     return s->error;
    322 }
    323 static inline void dbuf_set_error(DynBuf *s)
    324 {
    325     s->error = TRUE;
    326 }
    327 
    328 #define UTF8_CHAR_LEN_MAX 6
    329 
    330 int unicode_to_utf8(uint8_t *buf, unsigned int c);
    331 int unicode_from_utf8(const uint8_t *p, int max_len, const uint8_t **pp);
    332 
    333 static inline BOOL is_surrogate(uint32_t c)
    334 {
    335     return (c >> 11) == (0xD800 >> 11); // 0xD800-0xDFFF
    336 }
    337 
    338 static inline BOOL is_hi_surrogate(uint32_t c)
    339 {
    340     return (c >> 10) == (0xD800 >> 10); // 0xD800-0xDBFF
    341 }
    342 
    343 static inline BOOL is_lo_surrogate(uint32_t c)
    344 {
    345     return (c >> 10) == (0xDC00 >> 10); // 0xDC00-0xDFFF
    346 }
    347 
    348 static inline uint32_t get_hi_surrogate(uint32_t c)
    349 {
    350     return (c >> 10) - (0x10000 >> 10) + 0xD800;
    351 }
    352 
    353 static inline uint32_t get_lo_surrogate(uint32_t c)
    354 {
    355     return (c & 0x3FF) | 0xDC00;
    356 }
    357 
    358 static inline uint32_t from_surrogate(uint32_t hi, uint32_t lo)
    359 {
    360     return 0x10000 + 0x400 * (hi - 0xD800) + (lo - 0xDC00);
    361 }
    362 
    363 static inline int from_hex(int c)
    364 {
    365     if (c >= '0' && c <= '9')
    366         return c - '0';
    367     else if (c >= 'A' && c <= 'F')
    368         return c - 'A' + 10;
    369     else if (c >= 'a' && c <= 'f')
    370         return c - 'a' + 10;
    371     else
    372         return -1;
    373 }
    374 
    375 void rqsort(void *base, size_t nmemb, size_t size,
    376             int (*cmp)(const void *, const void *, void *),
    377             void *arg);
    378 
    379 static inline uint64_t float64_as_uint64(double d)
    380 {
    381     union {
    382         double d;
    383         uint64_t u64;
    384     } u;
    385     u.d = d;
    386     return u.u64;
    387 }
    388 
    389 static inline double uint64_as_float64(uint64_t u64)
    390 {
    391     union {
    392         double d;
    393         uint64_t u64;
    394     } u;
    395     u.u64 = u64;
    396     return u.d;
    397 }
    398 
    399 static inline double fromfp16(uint16_t v)
    400 {
    401     double d;
    402     uint32_t v1;
    403     v1 = v & 0x7fff;
    404     if (unlikely(v1 >= 0x7c00))
    405         v1 += 0x1f8000; /* NaN or infinity */
    406     d = uint64_as_float64(((uint64_t)(v >> 15) << 63) | ((uint64_t)v1 << (52 - 10)));
    407     return d * 0x1p1008;
    408 }
    409 
    410 static inline uint16_t tofp16(double d)
    411 {
    412     uint64_t a, addend;
    413     uint32_t v, sgn;
    414     int shift;
    415     
    416     a = float64_as_uint64(d);
    417     sgn = a >> 63;
    418     a = a & 0x7fffffffffffffff;
    419     if (unlikely(a > 0x7ff0000000000000)) {
    420         /* nan */
    421         v = 0x7c01;
    422     } else if (a < 0x3f10000000000000) { /* 0x1p-14 */
    423         /* subnormal f16 number or zero */
    424         if (a <= 0x3e60000000000000) { /* 0x1p-25 */
    425             v = 0x0000; /* zero */
    426         } else {
    427             shift = 1051 - (a >> 52);
    428             a = ((uint64_t)1 << 52) | (a & (((uint64_t)1 << 52) - 1));
    429             addend = ((a >> shift) & 1) + (((uint64_t)1 << (shift - 1)) - 1);
    430             v = (a + addend) >> shift;
    431         }
    432     } else {
    433         /* normal number or infinity */
    434         a -= 0x3f00000000000000; /* adjust the exponent */
    435         /* round */
    436         addend = ((a >> (52 - 10)) & 1) + (((uint64_t)1 << (52 - 11)) - 1);
    437         v = (a + addend) >> (52 - 10);
    438         /* overflow ? */
    439         if (unlikely(v > 0x7c00))
    440             v = 0x7c00;
    441     }
    442     return v | (sgn << 15);
    443 }
    444 
    445 static inline int isfp16nan(uint16_t v)
    446 {
    447     return (v & 0x7FFF) > 0x7C00;
    448 }
    449 
    450 static inline int isfp16zero(uint16_t v)
    451 {
    452     return (v & 0x7FFF) == 0;
    453 }
    454 
    455 #endif  /* CUTILS_H */