LCOV - code coverage report
Current view: top level - gdk - gdk_atoms.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 602 806 74.7 %
Date: 2024-12-20 21:24:02 Functions: 79 92 85.9 %

          Line data    Source code
       1             : /*
       2             :  * SPDX-License-Identifier: MPL-2.0
       3             :  *
       4             :  * This Source Code Form is subject to the terms of the Mozilla Public
       5             :  * License, v. 2.0.  If a copy of the MPL was not distributed with this
       6             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       7             :  *
       8             :  * Copyright 2024 MonetDB Foundation;
       9             :  * Copyright August 2008 - 2023 MonetDB B.V.;
      10             :  * Copyright 1997 - July 2008 CWI.
      11             :  */
      12             : 
      13             : /*
      14             :  * @a M. L. Kersten, P. Boncz
      15             :  * @* Atomic types
      16             :  * The Binary Association Table library assumes efficient
      17             :  * implementation of the atoms making up the binary association.  This
      18             :  * section describes the preliminaries for handling both built-in and
      19             :  * user-defined atomic types.
      20             :  * New types, such as point and polygons, can be readily added to this
      21             :  * collection.
      22             :  */
      23             : /*
      24             :  * @- inline comparison routines
      25             :  * Return 0 on l==r, < 0 iff l < r, >0 iff l > r
      26             :  */
      27             : #include "monetdb_config.h"
      28             : #include "gdk.h"
      29             : #include "gdk_time.h"
      30             : #include "gdk_private.h"
      31             : 
      32             : /* the *Cmp functions return a value less than zero if the first
      33             :  * argument is less than the second; they return zero if the two
      34             :  * values are equal; and they return a value greater than zero if the
      35             :  * first argument is greater than the second.  Remember that in all
      36             :  * cases, nil is considered smaller than any other value and nil is
      37             :  * equal to itself (this has repercussions for the floating point
      38             :  * implementation if and when its NIL value is the floating point
      39             :  * NaN). */
      40             : 
      41             : static int
      42         282 : mskCmp(const msk *l, const msk *r)
      43             : {
      44         282 :         return (*l > *r) - (*l < *r);
      45             : }
      46             : 
      47             : static int
      48   687578728 : bteCmp(const bte *l, const bte *r)
      49             : {
      50   687578728 :         return (*l > *r) - (*l < *r);
      51             : }
      52             : 
      53             : static int
      54    60826177 : shtCmp(const sht *l, const sht *r)
      55             : {
      56    60826177 :         return (*l > *r) - (*l < *r);
      57             : }
      58             : 
      59             : static int
      60  2859627619 : intCmp(const int *l, const int *r)
      61             : {
      62  2859627619 :         return (*l > *r) - (*l < *r);
      63             : }
      64             : 
      65             : static int
      66   409336770 : fltCmp(const flt *l, const flt *r)
      67             : {
      68   409336770 :         return is_flt_nil(*l) ? -!is_flt_nil(*r) : is_flt_nil(*r) ? 1 : (*l > *r) - (*l < *r);
      69             : }
      70             : 
      71             : static int
      72  5740535667 : lngCmp(const lng *l, const lng *r)
      73             : {
      74  5740535667 :         return (*l > *r) - (*l < *r);
      75             : }
      76             : 
      77             : #ifdef HAVE_HGE
      78             : static int
      79   179588139 : hgeCmp(const hge *l, const hge *r)
      80             : {
      81   179588139 :         return (*l > *r) - (*l < *r);
      82             : }
      83             : #endif
      84             : 
      85             : static int
      86    50061030 : dblCmp(const dbl *l, const dbl *r)
      87             : {
      88    50061030 :         return is_dbl_nil(*l) ? -!is_dbl_nil(*r) : is_dbl_nil(*r) ? 1 : (*l > *r) - (*l < *r);
      89             : }
      90             : 
      91             : /*
      92             :  * @- inline hash routines
      93             :  * Return some positive integer derived from one atom value.
      94             :  */
      95             : static BUN
      96           0 : bteHash(const bte *v)
      97             : {
      98           0 :         return (BUN) mix_bte(*(const unsigned char *) v);
      99             : }
     100             : 
     101             : static BUN
     102           0 : shtHash(const sht *v)
     103             : {
     104           0 :         return (BUN) mix_sht(*(const unsigned short *) v);
     105             : }
     106             : 
     107             : static BUN
     108     1181440 : intHash(const int *v)
     109             : {
     110     1181440 :         return (BUN) mix_int(*(const unsigned int *) v);
     111             : }
     112             : 
     113             : static BUN
     114         871 : lngHash(const lng *v)
     115             : {
     116         871 :         return (BUN) mix_lng(*(const ulng *) v);
     117             : }
     118             : 
     119             : #ifdef HAVE_HGE
     120             : static BUN
     121           0 : hgeHash(const hge *v)
     122             : {
     123           0 :         return (BUN) mix_hge(*(const uhge *) v);
     124             : }
     125             : #endif
     126             : 
     127             : static BUN
     128      151519 : fltHash(const flt *v)
     129             : {
     130      151519 :         if (is_flt_nil(*v))
     131             :                 return (BUN) mix_int(GDK_int_min);
     132      151386 :         if (*v == 0)
     133             :                 return (BUN) mix_int(0);
     134      147435 :         return (BUN) mix_int(*(const unsigned int *) v);
     135             : }
     136             : 
     137             : static BUN
     138       42117 : dblHash(const dbl *v)
     139             : {
     140       42117 :         if (is_dbl_nil(*v))
     141             :                 return (BUN) mix_lng(GDK_lng_min);
     142       40146 :         if (*v == 0)
     143             :                 return (BUN) mix_lng(0);
     144       34804 :         return (BUN) mix_lng(*(const ulng *) v);
     145             : }
     146             : 
     147             : /*
     148             :  * @+ Standard Atoms
     149             :  */
     150             : 
     151             : /*
     152             :  * @+ Atomic Type Interface
     153             :  * The collection of built-in types supported for BATs can be extended
     154             :  * easily.  In essence, the user should specify conversion routines
     155             :  * from values stored anywhere in memory to its equivalent in the BAT,
     156             :  * and vice verse.  Some routines are required for coercion and to
     157             :  * support the BAT administration.
     158             :  *
     159             :  * A new type is incrementally build using the routine
     160             :  * ATOMallocate(id).  The parameter id denotes the type name; an entry
     161             :  * is created if the type is so far unknown.
     162             :  *
     163             :  * The size describes the amount of space to be reserved in the BUN.
     164             :  *
     165             :  * The routine put takes a pointer to a memory resident copy and
     166             :  * prepares a persistent copy in the BAT passed.  The inverse
     167             :  * operation is get.  A new value can be directly included into the
     168             :  * BAT using new, which should prepare a null-value representation.  A
     169             :  * value is removed from the BAT store using del, which can take care
     170             :  * of garbage collection and BAT administration.
     171             :  *
     172             :  * The pair tostr and fromstr should convert a reference to a
     173             :  * persistent value to a memory resident string equivalent. FromStr
     174             :  * takes a string and applies a put to store it within a BAT.  They
     175             :  * are used to prepare for readable output/input and to support
     176             :  * coercion.
     177             :  *
     178             :  * The routines cmp and eq are comparison routines used to build
     179             :  * access structures. The null returns a reference to a null value
     180             :  * representation.
     181             :  *
     182             :  * The incremental atom construction uses hardwired properties.  This
     183             :  * should be improved later on.
     184             :  */
     185             : static MT_Lock GDKatomLock = MT_LOCK_INITIALIZER(GDKatomLock);
     186             : 
     187             : int
     188        3148 : ATOMallocate(const char *id)
     189             : {
     190        3148 :         int t;
     191             : 
     192        3148 :         if (strlen(id) >= IDLENGTH) {
     193           0 :                 GDKerror("name too long");
     194           0 :                 return int_nil;
     195             :         }
     196             : 
     197        3148 :         MT_lock_set(&GDKatomLock);
     198        3148 :         t = ATOMindex(id);
     199        3148 :         if (t < 0) {
     200        3148 :                 t = -t;
     201        3148 :                 if (t == GDKatomcnt) {
     202        3148 :                         if (GDKatomcnt == MAXATOMS) {
     203           0 :                                 MT_lock_unset(&GDKatomLock);
     204           0 :                                 GDKerror("too many types");
     205           0 :                                 return int_nil;
     206             :                         }
     207        3148 :                         GDKatomcnt++;
     208             :                 }
     209        3148 :                 BATatoms[t] = (atomDesc) {
     210             :                         .size = sizeof(int),    /* default */
     211             :                         .linear = true,         /* default */
     212             :                         .storage = t,           /* default */
     213             :                 };
     214        3148 :                 strcpy(BATatoms[t].name, id);
     215             :         }
     216        3148 :         MT_lock_unset(&GDKatomLock);
     217        3148 :         return t;
     218             : }
     219             : 
     220             : int
     221       69443 : ATOMindex(const char *nme)
     222             : {
     223       69443 :         int t, j = GDKatomcnt;
     224             : 
     225      777272 :         for (t = 0; t < GDKatomcnt; t++) {
     226      773514 :                 if (!BATatoms[t].name[0]) {
     227           0 :                         if (j == GDKatomcnt)
     228      707829 :                                 j = t;
     229      773514 :                 } else if (strcmp(nme, BATatoms[t].name) == 0) {
     230       65685 :                         return t;
     231             :                 }
     232             : 
     233             :         }
     234        3758 :         return -j;
     235             : }
     236             : 
     237             : const char *
     238      409686 : ATOMname(int t)
     239             : {
     240      409686 :         return t >= 0 && t < GDKatomcnt && *BATatoms[t].name ? BATatoms[t].name : "null";
     241             : }
     242             : 
     243             : bool
     244      245482 : ATOMisdescendant(int tpe, int parent)
     245             : {
     246      245482 :         int cur = -1;
     247             : 
     248      498474 :         while (cur != tpe) {
     249      252992 :                 cur = tpe;
     250      252992 :                 if (cur == parent)
     251             :                         return true;
     252      252992 :                 tpe = ATOMstorage(tpe);
     253             :         }
     254             :         return false;
     255             : }
     256             : 
     257             : 
     258             : const bte bte_nil = GDK_bte_min-1;
     259             : const sht sht_nil = GDK_sht_min-1;
     260             : const int int_nil = GDK_int_min-1;
     261             : #ifdef NAN_CANNOT_BE_USED_AS_INITIALIZER
     262             : /* Definition of NAN is seriously broken on Intel compiler (at least
     263             :  * in some versions), so we work around it. */
     264             : const union _flt_nil_t _flt_nil_ = {
     265             :         .l = UINT32_C(0x7FC00000)
     266             : };
     267             : const union _dbl_nil_t _dbl_nil_ = {
     268             :         .l = UINT64_C(0x7FF8000000000000)
     269             : };
     270             : #else
     271             : const flt flt_nil = NAN;
     272             : const dbl dbl_nil = NAN;
     273             : #endif
     274             : const lng lng_nil = GDK_lng_min-1;
     275             : #ifdef HAVE_HGE
     276             : const hge hge_nil = GDK_hge_min-1;
     277             : #endif
     278             : const oid oid_nil = (oid) 1 << (sizeof(oid) * 8 - 1);
     279             : const ptr ptr_nil = NULL;
     280             : const uuid uuid_nil = {0};
     281             : 
     282             : ptr
     283          21 : ATOMnil(int t)
     284             : {
     285          21 :         const void *src = ATOMnilptr(t);
     286          21 :         size_t len = ATOMlen(ATOMtype(t), src);
     287          21 :         ptr dst = GDKmalloc(len);
     288             : 
     289          22 :         if (dst)
     290          22 :                 memcpy(dst, src, len);
     291          22 :         return dst;
     292             : }
     293             : 
     294             : /*
     295             :  * @- Atomic ADT functions
     296             :  */
     297             : size_t
     298     7408897 : ATOMlen(int t, const void *src)
     299             : {
     300     7408897 :         size_t (*l)(const void *) = BATatoms[t].atomLen;
     301             : 
     302     7408897 :         return l ? (*l) (src) : ATOMsize(t);
     303             : }
     304             : 
     305             : gdk_return
     306     1013035 : ATOMheap(int t, Heap *hp, size_t cap)
     307             : {
     308     1013035 :         gdk_return (*h) (Heap *, size_t) = BATatoms[t].atomHeap;
     309             : 
     310     1013035 :         if (h) {
     311     1013035 :                 return (*h) (hp, cap);
     312             :         }
     313             :         return GDK_SUCCEED;
     314             : }
     315             : 
     316             : /*
     317             :  * Atom print avoids coercion to strings for built-in types.
     318             :  * The comparison against the NULL value is hard coded for speed.
     319             :  */
     320             : #define LINE_LEN        60
     321             : 
     322             : int
     323         702 : ATOMprint(int t, const void *p, stream *s)
     324             : {
     325         702 :         ssize_t (*tostr) (char **, size_t *, const void *, bool);
     326         702 :         ssize_t res;
     327             : 
     328        1404 :         if (p && t >= 0 && t < GDKatomcnt && (tostr = BATatoms[t].atomToStr)) {
     329         702 :                 size_t sz;
     330             : 
     331         702 :                 if (t < TYPE_date) {
     332         237 :                         char buf[dblStrlen], *addr = buf;       /* use memory from stack */
     333             : 
     334         237 :                         sz = dblStrlen;
     335         237 :                         res = (*tostr) (&addr, &sz, p, true);
     336         237 :                         if (res > 0)
     337         237 :                                 res = mnstr_write(s, buf, (size_t) res, 1);
     338             :                 } else {
     339         465 :                         str buf = NULL;
     340             : 
     341         465 :                         sz = 0;
     342         465 :                         res = (*tostr) (&buf, &sz, p, true);
     343         465 :                         if (res > 0)
     344         465 :                                 res = mnstr_write(s, buf, (size_t) res, 1);
     345         465 :                         GDKfree(buf);
     346             :                 }
     347             :         } else {
     348           0 :                 res = mnstr_write(s, "nil", 1, 3);
     349             :         }
     350         702 :         if (res < 0)
     351           0 :                 GDKsyserror("ATOMprint: write failure\n");
     352         702 :         return (int) res;
     353             : }
     354             : 
     355             : 
     356             : char *
     357       27429 : ATOMformat(int t, const void *p)
     358             : {
     359       27429 :         ssize_t (*tostr) (char **, size_t *, const void *, bool);
     360             : 
     361       27429 :         if (p && 0 <= t && t < GDKatomcnt && (tostr = BATatoms[t].atomToStr)) {
     362       27441 :                 size_t sz = 0;
     363       27441 :                 char *buf = NULL;
     364       27441 :                 ssize_t res = (*tostr) (&buf, &sz, p, true);
     365       27450 :                 if (res < 0 && buf) {
     366           0 :                         GDKfree(buf);
     367           0 :                         buf = NULL;
     368             :                 }
     369       27450 :                 return buf;
     370             :         }
     371           0 :         return GDKstrdup("nil");
     372             : }
     373             : 
     374             : ptr
     375      115082 : ATOMdup(int t, const void *p)
     376             : {
     377      115082 :         size_t len = ATOMlen(t, p);
     378      115082 :         ptr n = GDKmalloc(len);
     379             : 
     380      115082 :         if (n)
     381      115082 :                 memcpy(n, p, len);
     382      115082 :         return n;
     383             : }
     384             : 
     385             : /*
     386             :  * @* Builtin Atomic Operator Implementations
     387             :  *
     388             :  * @+ Atom-from-String Conversions
     389             :  * These routines convert from string to atom. They are used during
     390             :  * conversion and BAT import. In order to avoid unnecessary
     391             :  * malloc()/free() sequences, the conversion functions have a meta
     392             :  * 'dst' pointer to a destination region, and an integer* 'len'
     393             :  * parameter, that denotes the length of that region (a char region
     394             :  * for ToStr functions, an atom region from FromStr conversions). Only
     395             :  * if necessary will the conversion routine do a GDKfree()/GDKmalloc()
     396             :  * sequence, and increment the 'len'.  Passing a pointer to a nil-ptr
     397             :  * as 'dst' and/or a *len==0 is valid; the conversion function will
     398             :  * then alloc some region for you.
     399             :  */
     400             : #define atommem(size)                                   \
     401             :         do {                                            \
     402             :                 if (*dst == NULL || *len < (size)) { \
     403             :                         GDKfree(*dst);                  \
     404             :                         *len = (size);                  \
     405             :                         *dst = GDKmalloc(*len);         \
     406             :                         if (*dst == NULL) {             \
     407             :                                 *len = 0;               \
     408             :                                 return -1;              \
     409             :                         }                               \
     410             :                 }                                       \
     411             :         } while (0)
     412             : 
     413             : #define is_ptr_nil(val)         ((val) == ptr_nil)
     414             : 
     415             : #define atomtostr(TYPE, FMT, FMTCAST)                                   \
     416             : ssize_t                                                                 \
     417             : TYPE##ToStr(char **dst, size_t *len, const TYPE *src, bool external)    \
     418             : {                                                                       \
     419             :         atommem(TYPE##Strlen);                                          \
     420             :         if (is_##TYPE##_nil(*src)) {                                    \
     421             :                 if (external) {                                         \
     422             :                         strcpy(*dst, "nil");                          \
     423             :                         return 3;                                       \
     424             :                 }                                                       \
     425             :                 strcpy(*dst, str_nil);                                  \
     426             :                 return 1;                                               \
     427             :         }                                                               \
     428             :         return snprintf(*dst, *len, FMT, FMTCAST *src);                 \
     429             : }
     430             : 
     431             : #define base10(x)       ((x) - '0')
     432             : 
     433             : #define base16(x)       (((x) >= 'a' && (x) <= 'f') ? ((x) - 'a' + 10) : ((x) >= 'A' && (x) <= 'F') ? ((x) - 'A' + 10) : (x) - '0')
     434             : #define mult16(x)       ((x) << 4)
     435             : 
     436             : static void *
     437           0 : voidRead(void *a, size_t *dstlen, stream *s, size_t cnt)
     438             : {
     439           0 :         (void) dstlen;
     440           0 :         (void) s;
     441           0 :         (void) cnt;
     442           0 :         return a;
     443             : }
     444             : 
     445             : static gdk_return
     446           0 : voidWrite(const void *a, stream *s, size_t cnt)
     447             : {
     448           0 :         (void) a;
     449           0 :         (void) s;
     450           0 :         (void) cnt;
     451           0 :         return GDK_SUCCEED;
     452             : }
     453             : 
     454             : /*
     455             :  * Converts string values such as TRUE/FALSE/true/false etc to 1/0/NULL.
     456             :  * Switched from byte-to-byte compare to library function strncasecmp,
     457             :  * experiments showed that library function is even slightly faster and we
     458             :  * now also support True/False (and trUe/FAlSE should this become a thing).
     459             :  */
     460             : static ssize_t
     461           0 : mskFromStr(const char *src, size_t *len, msk **dst, bool external)
     462             : {
     463           0 :         const char *p = src;
     464             : 
     465           0 :         (void) external;
     466           0 :         atommem(sizeof(msk));
     467             : 
     468           0 :         if (strNil(src))
     469             :                 return -1;
     470             : 
     471           0 :         while (GDKisspace(*p))
     472           0 :                 p++;
     473           0 :         if (*p == '0') {
     474           0 :                 **dst = 0;
     475           0 :                 p++;
     476           0 :         } else if (*p == '1') {
     477           0 :                 **dst = 1;
     478           0 :                 p++;
     479             :         } else {
     480             :                 return -1;
     481             :         }
     482           0 :         while (GDKisspace(*p))
     483           0 :                 p++;
     484           0 :         return (ssize_t) (p - src);
     485             : }
     486             : 
     487             : static ssize_t
     488           0 : mskToStr(char **dst, size_t *len, const msk *src, bool external)
     489             : {
     490           0 :         (void) external;
     491           0 :         atommem(2);
     492           0 :         strcpy(*dst, *src ? "1" : "0");
     493           0 :         return 1;
     494             : }
     495             : 
     496             : ssize_t
     497       15588 : bitFromStr(const char *src, size_t *len, bit **dst, bool external)
     498             : {
     499       15588 :         const char *p = src;
     500             : 
     501       15588 :         atommem(sizeof(bit));
     502             : 
     503       15589 :         **dst = bit_nil;
     504             : 
     505       15589 :         if (strNil(src))
     506             :                 return 1;
     507             : 
     508       15589 :         while (GDKisspace(*p))
     509           0 :                 p++;
     510       15589 :         if (*p == '0') {
     511         294 :                 **dst = FALSE;
     512         294 :                 p++;
     513       15295 :         } else if (*p == '1') {
     514          60 :                 **dst = TRUE;
     515          60 :                 p++;
     516       15235 :         } else if (strncasecmp(p, "true",  4) == 0) {
     517       10272 :                 **dst = TRUE;
     518       10272 :                 p += 4;
     519        4963 :         } else if (strncasecmp(p, "false", 5) == 0) {
     520        4931 :                 **dst = FALSE;
     521        4931 :                 p += 5;
     522          32 :         } else if (external && strncasecmp(p, "nil",   3) == 0) {
     523           0 :                 p += 3;
     524             :         } else {
     525             :                 return -1;
     526             :         }
     527       15557 :         while (GDKisspace(*p))
     528           0 :                 p++;
     529       15557 :         return (ssize_t) (p - src);
     530             : }
     531             : 
     532             : ssize_t
     533       70766 : bitToStr(char **dst, size_t *len, const bit *src, bool external)
     534             : {
     535       70766 :         atommem(6);
     536             : 
     537       70766 :         if (is_bit_nil(*src)) {
     538          25 :                 if (external) {
     539          25 :                         strcpy(*dst, "nil");
     540          25 :                         return 3;
     541             :                 }
     542           0 :                 strcpy(*dst, str_nil);
     543           0 :                 return 1;
     544             :         }
     545       70741 :         if (*src) {
     546       25325 :                 strcpy(*dst, "true");
     547       25325 :                 return 4;
     548             :         }
     549       45416 :         strcpy(*dst, "false");
     550       45416 :         return 5;
     551             : }
     552             : 
     553             : ssize_t
     554           0 : batFromStr(const char *src, size_t *len, bat **dst, bool external)
     555             : {
     556           0 :         char *s;
     557           0 :         const char *t, *r = src;
     558           0 :         int c;
     559           0 :         bat bid = 0;
     560             : 
     561           0 :         atommem(sizeof(bat));
     562             : 
     563           0 :         if (strNil(src)) {
     564           0 :                 **dst = bat_nil;
     565           0 :                 return 1;
     566             :         }
     567             : 
     568           0 :         while (GDKisspace(*r))
     569           0 :                 r++;
     570             : 
     571           0 :         if (external && strcmp(r, "nil") == 0) {
     572           0 :                 **dst = bat_nil;
     573           0 :                 return (ssize_t) (r - src) + 3;
     574             :         }
     575             : 
     576           0 :         if (*r == '<')
     577           0 :                 r++;
     578           0 :         t = r;
     579           0 :         while ((c = *t) && (c == '_' || GDKisalnum(c)))
     580           0 :                 t++;
     581             : 
     582           0 :         s = GDKstrndup(r, t - r);
     583           0 :         if (s == NULL)
     584             :                 return -1;
     585           0 :         bid = BBPindex(s);
     586           0 :         GDKfree(s);
     587           0 :         **dst = bid == 0 ? bat_nil : bid;
     588           0 :         return (ssize_t) (t + (c == '>') - src);
     589             : }
     590             : 
     591             : ssize_t
     592           0 : batToStr(char **dst, size_t *len, const bat *src, bool external)
     593             : {
     594           0 :         bat b = *src;
     595           0 :         size_t i;
     596           0 :         str s;
     597             : 
     598           0 :         if (is_bat_nil(b) || !BBPcheck(b) || (s = BBP_logical(b)) == NULL || *s == 0) {
     599           0 :                 atommem(4);
     600           0 :                 if (external) {
     601           0 :                         strcpy(*dst, "nil");
     602           0 :                         return 3;
     603             :                 }
     604           0 :                 strcpy(*dst, str_nil);
     605           0 :                 return 1;
     606             :         }
     607           0 :         i = strlen(s) + 3;
     608           0 :         atommem(i);
     609           0 :         return (ssize_t) strconcat_len(*dst, *len, "<", s, ">", NULL);
     610             : }
     611             : 
     612             : 
     613             : /*
     614             :  * numFromStr parses the head of the string for a number, accepting an
     615             :  * optional sign. The code has been prepared to continue parsing by
     616             :  * returning the number of characters read.  Both overflow and
     617             :  * incorrect syntax (not a number) result in the function returning 0
     618             :  * and setting the destination to nil.
     619             :  */
     620             : struct maxdiv {
     621             :         /* if we want to multiply a value with scale, the value must
     622             :          * be no larger than maxval for there to not be overflow */
     623             : #ifdef HAVE_HGE
     624             :         hge scale, maxval;
     625             : #else
     626             :         lng scale, maxval;
     627             : #endif
     628             : };
     629             : static const struct maxdiv maxdiv[] = {
     630             : #ifdef HAVE_HGE
     631             :         /* maximum hge value: 170141183460469231731687303715884105727 (2**127-1)
     632             :          * GCC doesn't currently support integer constants that don't
     633             :          * fit in 8 bytes, so we split large values up*/
     634             :         {(hge) LL_CONSTANT(1), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(10000000000000000000U)+ (hge) LL_CONSTANT(1687303715884105727)},
     635             :         {(hge) LL_CONSTANT(10), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(1000000000000000000) + (hge) LL_CONSTANT(168730371588410572)},
     636             :         {(hge) LL_CONSTANT(100), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(100000000000000000) + (hge) LL_CONSTANT(16873037158841057)},
     637             :         {(hge) LL_CONSTANT(1000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(10000000000000000) + (hge) LL_CONSTANT(1687303715884105)},
     638             :         {(hge) LL_CONSTANT(10000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(1000000000000000) + (hge) LL_CONSTANT(168730371588410)},
     639             :         {(hge) LL_CONSTANT(100000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(100000000000000) + (hge) LL_CONSTANT(16873037158841)},
     640             :         {(hge) LL_CONSTANT(1000000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(10000000000000) + (hge) LL_CONSTANT(1687303715884)},
     641             :         {(hge) LL_CONSTANT(10000000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(1000000000000) + (hge) LL_CONSTANT(168730371588)},
     642             :         {(hge) LL_CONSTANT(100000000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(100000000000) + (hge) LL_CONSTANT(16873037158)},
     643             :         {(hge) LL_CONSTANT(1000000000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(10000000000) + (hge) LL_CONSTANT(1687303715)},
     644             :         {(hge) LL_CONSTANT(10000000000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(1000000000) + (hge) LL_CONSTANT(168730371)},
     645             :         {(hge) LL_CONSTANT(100000000000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(100000000) + (hge) LL_CONSTANT(16873037)},
     646             :         {(hge) LL_CONSTANT(1000000000000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(10000000) + (hge) LL_CONSTANT(1687303)},
     647             :         {(hge) LL_CONSTANT(10000000000000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(1000000) + (hge) LL_CONSTANT(168730)},
     648             :         {(hge) LL_CONSTANT(100000000000000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(100000) + (hge) LL_CONSTANT(16873)},
     649             :         {(hge) LL_CONSTANT(1000000000000000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(10000) + (hge) LL_CONSTANT(1687)},
     650             :         {(hge) LL_CONSTANT(10000000000000000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(1000) + (hge) LL_CONSTANT(168)},
     651             :         {(hge) LL_CONSTANT(100000000000000000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(100) + (hge) LL_CONSTANT(16)},
     652             :         {(hge) LL_CONSTANT(1000000000000000000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(10) + (hge) LL_CONSTANT(1)},
     653             :         {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(1), (hge) LL_CONSTANT(17014118346046923173U)},
     654             :         {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(10), (hge) LL_CONSTANT(1701411834604692317)},
     655             :         {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(100), (hge) LL_CONSTANT(170141183460469231)},
     656             :         {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(1000), (hge) LL_CONSTANT(17014118346046923)},
     657             :         {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(10000), (hge) LL_CONSTANT(1701411834604692)},
     658             :         {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(100000), (hge) LL_CONSTANT(170141183460469)},
     659             :         {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(1000000), (hge) LL_CONSTANT(17014118346046)},
     660             :         {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(10000000), (hge) LL_CONSTANT(1701411834604)},
     661             :         {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(100000000), (hge) LL_CONSTANT(170141183460)},
     662             :         {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(1000000000), (hge) LL_CONSTANT(17014118346)},
     663             :         {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(10000000000), (hge) LL_CONSTANT(1701411834)},
     664             :         {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(100000000000), (hge) LL_CONSTANT(170141183)},
     665             :         {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(1000000000000), (hge) LL_CONSTANT(17014118)},
     666             :         {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(10000000000000), (hge) LL_CONSTANT(1701411)},
     667             :         {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(100000000000000), (hge) LL_CONSTANT(170141)},
     668             :         {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(1000000000000000), (hge) LL_CONSTANT(17014)},
     669             :         {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(10000000000000000), (hge) LL_CONSTANT(1701)},
     670             :         {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(100000000000000000), (hge) LL_CONSTANT(170)},
     671             :         {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(1000000000000000000), (hge) LL_CONSTANT(17)},
     672             :         {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(10000000000000000000U),(hge) LL_CONSTANT(1)},
     673             : #else
     674             :         /* maximum lng value: 9223372036854775807 (2**63-1) */
     675             :         {LL_CONSTANT(1), LL_CONSTANT(9223372036854775807)},
     676             :         {LL_CONSTANT(10), LL_CONSTANT(922337203685477580)},
     677             :         {LL_CONSTANT(100), LL_CONSTANT(92233720368547758)},
     678             :         {LL_CONSTANT(1000), LL_CONSTANT(9223372036854775)},
     679             :         {LL_CONSTANT(10000), LL_CONSTANT(922337203685477)},
     680             :         {LL_CONSTANT(100000), LL_CONSTANT(92233720368547)},
     681             :         {LL_CONSTANT(1000000), LL_CONSTANT(9223372036854)},
     682             :         {LL_CONSTANT(10000000), LL_CONSTANT(922337203685)},
     683             :         {LL_CONSTANT(100000000), LL_CONSTANT(92233720368)},
     684             :         {LL_CONSTANT(1000000000), LL_CONSTANT(9223372036)},
     685             :         {LL_CONSTANT(10000000000), LL_CONSTANT(922337203)},
     686             :         {LL_CONSTANT(100000000000), LL_CONSTANT(92233720)},
     687             :         {LL_CONSTANT(1000000000000), LL_CONSTANT(9223372)},
     688             :         {LL_CONSTANT(10000000000000), LL_CONSTANT(922337)},
     689             :         {LL_CONSTANT(100000000000000), LL_CONSTANT(92233)},
     690             :         {LL_CONSTANT(1000000000000000), LL_CONSTANT(9223)},
     691             :         {LL_CONSTANT(10000000000000000), LL_CONSTANT(922)},
     692             :         {LL_CONSTANT(100000000000000000), LL_CONSTANT(92)},
     693             :         {LL_CONSTANT(1000000000000000000), LL_CONSTANT(9)},
     694             : #endif
     695             : };
     696             : static const int maxmod10 = 7;  /* (int) (maxdiv[0].maxval % 10) */
     697             : 
     698             : static ssize_t
     699   234187511 : numFromStr(const char *src, size_t *len, void **dst, int tp, bool external)
     700             : {
     701   234187511 :         const char *p = src;
     702   234187511 :         size_t sz = ATOMsize(tp);
     703             : #ifdef HAVE_HGE
     704   234187511 :         hge base = 0;
     705             : #else
     706             :         lng base = 0;
     707             : #endif
     708   234187511 :         int sign = 1;
     709             : 
     710             :         /* a valid number has the following syntax:
     711             :          * [-+]?[0-9]+([eE][0-9]+)?(LL)? -- PCRE syntax, or in other words
     712             :          * optional sign, one or more digits, optional exponent, optional LL
     713             :          * the exponent has the following syntax:
     714             :          * lower or upper case letter E, one or more digits
     715             :          * embedded spaces are not allowed
     716             :          * the optional LL at the end are only allowed for lng and hge
     717             :          * values */
     718   234187511 :         atommem(sz);
     719             : 
     720   234187511 :         if (strNil(src)) {
     721           0 :                 memcpy(*dst, ATOMnilptr(tp), sz);
     722           0 :                 return 1;
     723             :         }
     724             : 
     725   234187609 :         while (GDKisspace(*p))
     726          98 :                 p++;
     727   234187511 :         if (!GDKisdigit(*p)) {
     728       11691 :                 switch (*p) {
     729           5 :                 case 'n':
     730           5 :                         if (external) {
     731           0 :                                 memcpy(*dst, ATOMnilptr(tp), sz);
     732           0 :                                 if (p[1] == 'i' && p[2] == 'l') {
     733           0 :                                         p += 3;
     734           0 :                                         return (ssize_t) (p - src);
     735             :                                 }
     736             :                         }
     737           5 :                         GDKerror("not a number");
     738           5 :                         goto bailout;
     739       11496 :                 case '-':
     740       11496 :                         sign = -1;
     741       11496 :                         p++;
     742       11496 :                         break;
     743           1 :                 case '+':
     744           1 :                         p++;
     745           1 :                         break;
     746             :                 }
     747       11686 :                 if (!GDKisdigit(*p)) {
     748         195 :                         GDKerror("not a number");
     749         195 :                         goto bailout;
     750             :                 }
     751             :         }
     752   568019006 :         do {
     753   568019006 :                 int dig = base10(*p);
     754   568019006 :                 if (base > maxdiv[1].maxval ||
     755           1 :                     (base == maxdiv[1].maxval && dig > maxmod10)) {
     756             :                         /* overflow */
     757           0 :                         goto overflow;
     758             :                 }
     759   568019006 :                 base = 10 * base + dig;
     760   568019006 :                 p++;
     761   568019006 :         } while (GDKisdigit(*p));
     762   234187311 :         if ((*p == 'e' || *p == 'E') && GDKisdigit(p[1])) {
     763           7 :                 p++;
     764           7 :                 if (base == 0) {
     765             :                         /* if base is 0, any exponent will do, the
     766             :                          * result is still 0 */
     767           0 :                         while (GDKisdigit(*p))
     768           0 :                                 p++;
     769             :                 } else {
     770             :                         int exp = 0;
     771          11 :                         do {
     772             :                                 /* this calculation cannot overflow */
     773          11 :                                 exp = exp * 10 + base10(*p);
     774          11 :                                 if (exp >= (int) (sizeof(maxdiv) / sizeof(maxdiv[0]))) {
     775             :                                         /* overflow */
     776           0 :                                         goto overflow;
     777             :                                 }
     778          11 :                                 p++;
     779          11 :                         } while (GDKisdigit(*p));
     780           7 :                         if (base > maxdiv[exp].maxval) {
     781             :                                 /* overflow */
     782           0 :                                 goto overflow;
     783             :                         }
     784           7 :                         base *= maxdiv[exp].scale;
     785             :                 }
     786             :         }
     787   234187311 :         base *= sign;
     788   234187311 :         switch (sz) {
     789       54663 :         case 1: {
     790       54663 :                 bte **dstbte = (bte **) dst;
     791       54663 :                 if (base < GDK_bte_min || base > GDK_bte_max) {
     792           0 :                         goto overflow;
     793             :                 }
     794       54663 :                 **dstbte = (bte) base;
     795       54663 :                 break;
     796             :         }
     797      329687 :         case 2: {
     798      329687 :                 sht **dstsht = (sht **) dst;
     799      329687 :                 if (base < GDK_sht_min || base > GDK_sht_max) {
     800           3 :                         goto overflow;
     801             :                 }
     802      329684 :                 **dstsht = (sht) base;
     803      329684 :                 break;
     804             :         }
     805   230169135 :         case 4: {
     806   230169135 :                 int **dstint = (int **) dst;
     807   230169135 :                 if (base < GDK_int_min || base > GDK_int_max) {
     808           2 :                         goto overflow;
     809             :                 }
     810   230169133 :                 **dstint = (int) base;
     811   230169133 :                 break;
     812             :         }
     813     1911885 :         case 8: {
     814     1911885 :                 lng **dstlng = (lng **) dst;
     815             : #ifdef HAVE_HGE
     816     1911885 :                 if (base < GDK_lng_min || base > GDK_lng_max) {
     817           4 :                         goto overflow;
     818             :                 }
     819             : #endif
     820     1911881 :                 **dstlng = (lng) base;
     821     1911881 :                 if (p[0] == 'L' && p[1] == 'L')
     822           0 :                         p += 2;
     823             :                 break;
     824             :         }
     825             : #ifdef HAVE_HGE
     826     1721941 :         case 16: {
     827     1721941 :                 hge **dsthge = (hge **) dst;
     828     1721941 :                 **dsthge = (hge) base;
     829     1721941 :                 if (p[0] == 'L' && p[1] == 'L')
     830           0 :                         p += 2;
     831             :                 break;
     832             :         }
     833             : #endif
     834             :         }
     835   234187418 :         while (GDKisspace(*p))
     836         116 :                 p++;
     837   234187302 :         return (ssize_t) (p - src);
     838             : 
     839             :   overflow:
     840           9 :         while (GDKisdigit(*p))
     841           0 :                 p++;
     842           9 :         GDKerror("overflow: \"%.*s\" does not fit in %s\n",
     843             :                  (int) (p - src), src, ATOMname(tp));
     844         209 :   bailout:
     845         209 :         memcpy(*dst, ATOMnilptr(tp), sz);
     846         209 :         return -1;
     847             : }
     848             : 
     849             : ssize_t
     850       54276 : bteFromStr(const char *src, size_t *len, bte **dst, bool external)
     851             : {
     852       54276 :         return numFromStr(src, len, (void **) dst, TYPE_bte, external);
     853             : }
     854             : 
     855             : ssize_t
     856      325299 : shtFromStr(const char *src, size_t *len, sht **dst, bool external)
     857             : {
     858      325299 :         return numFromStr(src, len, (void **) dst, TYPE_sht, external);
     859             : }
     860             : 
     861             : ssize_t
     862   221978359 : intFromStr(const char *src, size_t *len, int **dst, bool external)
     863             : {
     864   221978359 :         return numFromStr(src, len, (void **) dst, TYPE_int, external);
     865             : }
     866             : 
     867             : ssize_t
     868     1911857 : lngFromStr(const char *src, size_t *len, lng **dst, bool external)
     869             : {
     870     1911857 :         return numFromStr(src, len, (void **) dst, TYPE_lng, external);
     871             : }
     872             : 
     873             : #ifdef HAVE_HGE
     874             : ssize_t
     875     1721568 : hgeFromStr(const char *src, size_t *len, hge **dst, bool external)
     876             : {
     877     1721568 :         return numFromStr(src, len, (void **) dst, TYPE_hge, external);
     878             : }
     879             : #endif
     880             : 
     881             : #define atom_io(TYPE, NAME, CAST)                                       \
     882             : static TYPE *                                                           \
     883             : TYPE##Read(TYPE *A, size_t *dstlen, stream *s, size_t cnt)              \
     884             : {                                                                       \
     885             :         TYPE *a = A;                                                    \
     886             :         if (a == NULL || *dstlen < cnt * sizeof(TYPE)) {             \
     887             :                 if ((a = GDKrealloc(a, cnt * sizeof(TYPE))) == NULL)    \
     888             :                         return NULL;                                    \
     889             :                 *dstlen = cnt * sizeof(TYPE);                           \
     890             :         }                                                               \
     891             :         if (mnstr_read##NAME##Array(s, (CAST *) a, cnt) == 0 ||         \
     892             :             mnstr_errnr(s) != MNSTR_NO__ERROR) {                        \
     893             :                 if (a != A)                                             \
     894             :                         GDKfree(a);                                     \
     895             :                 return NULL;                                            \
     896             :         }                                                               \
     897             :         return a;                                                       \
     898             : }                                                                       \
     899             : static gdk_return                                                       \
     900             : TYPE##Write(const TYPE *a, stream *s, size_t cnt)                       \
     901             : {                                                                       \
     902             :         return mnstr_write##NAME##Array(s, (const CAST *) a, cnt) ?     \
     903             :                 GDK_SUCCEED : GDK_FAIL;                                 \
     904             : }
     905             : 
     906             : static gdk_return
     907      125350 : mskWrite(const msk *a, stream *s, size_t cnt)
     908             : {
     909      125350 :         if (cnt == 0)
     910             :                 return GDK_SUCCEED;
     911      125350 :         if (cnt == 1)
     912      125350 :                 return mnstr_writeBte(s, (int8_t) *a) ? GDK_SUCCEED : GDK_FAIL;
     913             :         return GDK_FAIL;
     914             : }
     915             : 
     916             : static void *
     917      124192 : mskRead(msk *A, size_t *dstlen, stream *s, size_t cnt)
     918             : {
     919      124192 :         int8_t v;
     920      124192 :         msk *a = A;
     921      124192 :         if (cnt != 1)
     922             :                 return NULL;
     923      124192 :         if (a == NULL || *dstlen == 0) {
     924           0 :                 if ((a = GDKrealloc(a, 1)) == NULL)
     925             :                         return NULL;
     926           0 :                 *dstlen = 1;
     927             :         }
     928      124192 :         if (mnstr_readBte(s, &v) != 1) {
     929           0 :                 if (a != A)
     930           0 :                         GDKfree(a);
     931           0 :                 return NULL;
     932             :         }
     933      124192 :         *a = v != 0;
     934      124192 :         return a;
     935             : }
     936             : 
     937        7283 : atom_io(bit, Bte, bte)
     938             : 
     939       43720 : atomtostr(bte, "%hhd", )
     940      256226 : atom_io(bte, Bte, bte)
     941             : 
     942     1073017 : atomtostr(sht, "%hd", )
     943        8423 : atom_io(sht, Sht, sht)
     944             : 
     945    15496624 : atomtostr(int, "%d", )
     946      220454 : atom_io(int, Int, int)
     947             : 
     948      165880 : atomtostr(lng, LLFMT, )
     949        5951 : atom_io(lng, Lng, lng)
     950             : 
     951             : #ifdef HAVE_HGE
     952             : #define HGE_LL018FMT "%018" PRId64
     953             : #define HGE_LL18DIGITS LL_CONSTANT(1000000000000000000)
     954             : #define HGE_ABS(a) (((a) < 0) ? -(a) : (a))
     955             : ssize_t
     956        3301 : hgeToStr(char **dst, size_t *len, const hge *src, bool external)
     957             : {
     958        3301 :         atommem(hgeStrlen);
     959        3301 :         if (is_hge_nil(*src)) {
     960           1 :                 if (external) {
     961           1 :                         assert(*len >= strlen("nil") + 1);
     962           1 :                         strcpy(*dst, "nil");
     963           1 :                         return 3;
     964             :                 }
     965           0 :                 assert(*len >= strlen(str_nil) + 1);
     966           0 :                 strcpy(*dst, str_nil);
     967           0 :                 return 1;
     968             :         }
     969        3300 :         if ((hge) GDK_lng_min <= *src && *src <= (hge) GDK_lng_max) {
     970        3183 :                 lng s = (lng) *src;
     971        3183 :                 return lngToStr(dst, len, &s, external);
     972             :         } else {
     973         117 :                 hge s = *src / HGE_LL18DIGITS;
     974         117 :                 ssize_t llen = hgeToStr(dst, len, &s, external);
     975         117 :                 if (llen < 0)
     976             :                         return llen;
     977         117 :                 snprintf(*dst + llen, *len - llen, HGE_LL018FMT,
     978         117 :                          (lng) HGE_ABS(*src % HGE_LL18DIGITS));
     979         117 :                 return strlen(*dst);
     980             :         }
     981             : }
     982         954 : atom_io(hge, Hge, hge)
     983             : #endif
     984             : 
     985             : ssize_t
     986           0 : ptrFromStr(const char *src, size_t *len, ptr **dst, bool external)
     987             : {
     988           0 :         size_t base = 0;
     989           0 :         const char *p = src;
     990             : 
     991           0 :         atommem(sizeof(ptr));
     992             : 
     993           0 :         **dst = ptr_nil;
     994           0 :         if (strNil(src))
     995             :                 return 1;
     996             : 
     997           0 :         while (GDKisspace(*p))
     998           0 :                 p++;
     999           0 :         if (external && strncmp(p, "nil", 3) == 0) {
    1000           0 :                 p += 3;
    1001             :         } else {
    1002           0 :                 if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) {
    1003           0 :                         p += 2;
    1004             :                 }
    1005           0 :                 if (!GDKisxdigit(*p)) {
    1006           0 :                         GDKerror("not a number\n");
    1007           0 :                         return -1;
    1008             :                 }
    1009           0 :                 while (GDKisxdigit(*p)) {
    1010           0 :                         if (base >= ((size_t) 1 << (8 * sizeof(size_t) - 4))) {
    1011           0 :                                 GDKerror("overflow\n");
    1012           0 :                                 return -1;
    1013             :                         }
    1014           0 :                         base = mult16(base) + base16(*p);
    1015           0 :                         p++;
    1016             :                 }
    1017           0 :                 **dst = (ptr) base;
    1018             :         }
    1019           0 :         while (GDKisspace(*p))
    1020           0 :                 p++;
    1021           0 :         return (ssize_t) (p - src);
    1022             : }
    1023             : 
    1024             : #ifdef _MSC_VER
    1025             : /* Windows doesn't put 0x in front whereas Linux does, so we do it ourselves */
    1026             : atomtostr(ptr, "0x%p", )
    1027             : #else
    1028           1 : atomtostr(ptr, "%p", )
    1029             : #endif
    1030             : 
    1031             : #if SIZEOF_VOID_P == SIZEOF_INT
    1032             : atom_io(ptr, Int, int)
    1033             : #else /* SIZEOF_VOID_P == SIZEOF_LNG */
    1034           0 : atom_io(ptr, Lng, lng)
    1035             : #endif
    1036             : 
    1037             : ssize_t
    1038      267809 : dblFromStr(const char *src, size_t *len, dbl **dst, bool external)
    1039             : {
    1040      267809 :         const char *p = src;
    1041      267809 :         ssize_t n = 0;
    1042      267809 :         double d;
    1043             : 
    1044             :         /* alloc memory */
    1045      267809 :         atommem(sizeof(dbl));
    1046             : 
    1047      267809 :         if (strNil(src)) {
    1048           0 :                 **dst = dbl_nil;
    1049           0 :                 return 1;
    1050             :         }
    1051             : 
    1052      267928 :         while (GDKisspace(*p))
    1053         119 :                 p++;
    1054      267809 :         if (external && strncmp(p, "nil", 3) == 0) {
    1055           0 :                 **dst = dbl_nil;
    1056           0 :                 p += 3;
    1057           0 :                 n = (ssize_t) (p - src);
    1058             :         } else {
    1059             :                 /* on overflow, strtod returns HUGE_VAL and sets
    1060             :                  * errno to ERANGE; on underflow, it returns a value
    1061             :                  * whose magnitude is no greater than the smallest
    1062             :                  * normalized double, and may or may not set errno to
    1063             :                  * ERANGE.  We accept underflow, but not overflow. */
    1064      267809 :                 char *pe;
    1065      267809 :                 errno = 0;
    1066      267809 :                 d = strtod(p, &pe);
    1067      282204 :                 if (p == pe)
    1068             :                         p = src; /* nothing converted */
    1069             :                 else
    1070      282170 :                         p = pe;
    1071      282204 :                 n = (ssize_t) (p - src);
    1072      282204 :                 if (n == 0 || (errno == ERANGE && (d < -1 || d > 1))
    1073      282162 :                     || !isfinite(d) /* no NaN or Infinite */
    1074             :                     ) {
    1075         104 :                         GDKerror("overflow or not a number\n");
    1076         104 :                         return -1;
    1077             :                 } else {
    1078      282150 :                         while (src[n] && GDKisspace(src[n]))
    1079          50 :                                 n++;
    1080      282100 :                         **dst = (dbl) d;
    1081             :                 }
    1082             :         }
    1083             :         return n;
    1084             : }
    1085             : 
    1086             : ssize_t
    1087       14050 : dblToStr(char **dst, size_t *len, const dbl *src, bool external)
    1088             : {
    1089       14050 :         int l = 0;
    1090             : 
    1091       14050 :         atommem(dblStrlen);
    1092       14050 :         if (is_dbl_nil(*src)) {
    1093           7 :                 if (external) {
    1094           7 :                         strcpy(*dst, "nil");
    1095           7 :                         return 3;
    1096             :                 }
    1097           0 :                 strcpy(*dst, str_nil);
    1098           0 :                 return 1;
    1099             :         }
    1100       14043 :         if (*src <= (dbl) 999999999999999 &&
    1101       13896 :             *src >= (dbl) -999999999999999 &&
    1102       13896 :             (dbl) (int) *src == *src) {
    1103        8604 :                 l = snprintf(*dst, *len, "%.0f", *src);
    1104        8604 :                 if (strtod(*dst, NULL) == *src)
    1105        8603 :                         return (ssize_t) l;
    1106             :         }
    1107       39238 :         for (int i = 4; i < 18; i++) {
    1108       39238 :                 l = snprintf(*dst, *len, "%.*g", i, *src);
    1109       39238 :                 if (strtod(*dst, NULL) == *src)
    1110             :                         break;
    1111             :         }
    1112        5438 :         return (ssize_t) l;
    1113             : }
    1114             : 
    1115         768 : atom_io(dbl, Lng, lng)
    1116             : 
    1117             : ssize_t
    1118     1828040 : fltFromStr(const char *src, size_t *len, flt **dst, bool external)
    1119             : {
    1120     1828040 :         const char *p = src;
    1121     1828040 :         ssize_t n = 0;
    1122     1828040 :         float f;
    1123             : 
    1124             :         /* alloc memory */
    1125     1828040 :         atommem(sizeof(flt));
    1126             : 
    1127     1828040 :         if (strNil(src)) {
    1128           0 :                 **dst = flt_nil;
    1129           0 :                 return 1;
    1130             :         }
    1131             : 
    1132     1828105 :         while (GDKisspace(*p))
    1133          65 :                 p++;
    1134     1828040 :         if (external && strncmp(p, "nil", 3) == 0) {
    1135           0 :                 **dst = flt_nil;
    1136           0 :                 p += 3;
    1137           0 :                 n = (ssize_t) (p - src);
    1138             :         } else {
    1139             :                 /* on overflow, strtof returns HUGE_VALF and sets
    1140             :                  * errno to ERANGE; on underflow, it returns a value
    1141             :                  * whose magnitude is no greater than the smallest
    1142             :                  * normalized float, and may or may not set errno to
    1143             :                  * ERANGE.  We accept underflow, but not overflow. */
    1144     1828040 :                 char *pe;
    1145     1828040 :                 errno = 0;
    1146     1828040 :                 f = strtof(p, &pe);
    1147     1834310 :                 if (p == pe)
    1148             :                         p = src; /* nothing converted */
    1149             :                 else
    1150     1834302 :                         p = pe;
    1151     1834310 :                 n = (ssize_t) (p - src);
    1152     1834310 :                 if (n == 0 || (errno == ERANGE && (f < -1 || f > 1))
    1153     1834294 :                     || !isfinite(f) /* no NaN or infinite */) {
    1154          58 :                         GDKerror("overflow or not a number\n");
    1155          58 :                         return -1;
    1156             :                 } else {
    1157     1834291 :                         while (src[n] && GDKisspace(src[n]))
    1158          39 :                                 n++;
    1159     1834252 :                         if (f == -0)
    1160        6550 :                                 f = 0;
    1161     1834252 :                         **dst = (flt) f;
    1162             :                 }
    1163             :         }
    1164             :         return n;
    1165             : }
    1166             : 
    1167             : ssize_t
    1168        1909 : fltToStr(char **dst, size_t *len, const flt *src, bool external)
    1169             : {
    1170        1909 :         int l = 0;
    1171             : 
    1172        1909 :         atommem(fltStrlen);
    1173        1909 :         if (is_flt_nil(*src)) {
    1174           5 :                 if (external) {
    1175           5 :                         strcpy(*dst, "nil");
    1176           5 :                         return 3;
    1177             :                 }
    1178           0 :                 strcpy(*dst, str_nil);
    1179           0 :                 return 1;
    1180             :         }
    1181        1904 :         if (*src <= (flt) 9999999 &&
    1182        1658 :             *src >= (flt) -9999999 &&
    1183        1658 :             (flt) (int) *src == *src) {
    1184        1239 :                 l = snprintf(*dst, *len, "%.0f", *src);
    1185        1239 :                 if (strtof(*dst, NULL) == *src)
    1186        1239 :                         return (ssize_t) l;
    1187             :         }
    1188        1972 :         for (int i = 4; i < 10; i++) {
    1189        1972 :                 l = snprintf(*dst, *len, "%.*g", i, *src);
    1190        1972 :                 if (strtof(*dst, NULL) == *src)
    1191             :                         break;
    1192             :         }
    1193         665 :         return (ssize_t) l;
    1194             : }
    1195             : 
    1196         217 : atom_io(flt, Int, int)
    1197             : 
    1198             : 
    1199             : /*
    1200             :  * String conversion routines.
    1201             :  */
    1202             : ssize_t
    1203          26 : OIDfromStr(const char *src, size_t *len, oid **dst, bool external)
    1204             : {
    1205             : #if SIZEOF_OID == SIZEOF_INT
    1206             :         int ui = 0, *uip = &ui;
    1207             : #else
    1208          26 :         lng ui = 0, *uip = &ui;
    1209             : #endif
    1210          26 :         size_t l = sizeof(ui);
    1211          26 :         ssize_t pos = 0;
    1212          26 :         const char *p = src;
    1213             : 
    1214          26 :         atommem(sizeof(oid));
    1215             : 
    1216          26 :         **dst = oid_nil;
    1217          26 :         if (strNil(src))
    1218             :                 return 1;
    1219             : 
    1220          26 :         while (GDKisspace(*p))
    1221           0 :                 p++;
    1222             : 
    1223          26 :         if (external && strncmp(p, "nil", 3) == 0)
    1224           0 :                 return (ssize_t) (p - src) + 3;
    1225             : 
    1226          26 :         if (*p >= '0' && *p <= '9') {
    1227             : #if SIZEOF_OID == SIZEOF_INT
    1228             :                 pos = intFromStr(p, &l, &uip, external);
    1229             : #else
    1230          25 :                 pos = lngFromStr(p, &l, &uip, external);
    1231             : #endif
    1232          25 :                 if (pos < 0)
    1233             :                         return pos;
    1234          25 :                 if (p[pos] == '@') {
    1235           7 :                         pos++;
    1236          14 :                         while (p[pos] >= '0' && p[pos] <= '9')
    1237           7 :                                 pos++;
    1238             :                 }
    1239          25 :                 if (ui >= 0) {
    1240          25 :                         **dst = ui;
    1241             :                 }
    1242          25 :                 p += pos;
    1243             :         } else {
    1244           1 :                 GDKerror("not an OID\n");
    1245           1 :                 return -1;
    1246             :         }
    1247          25 :         while (GDKisspace(*p))
    1248           0 :                 p++;
    1249          25 :         return (ssize_t) (p - src);
    1250             : }
    1251             : 
    1252             : ssize_t
    1253        4210 : OIDtoStr(char **dst, size_t *len, const oid *src, bool external)
    1254             : {
    1255        4210 :         atommem(oidStrlen);
    1256             : 
    1257        4210 :         if (is_oid_nil(*src)) {
    1258          16 :                 if (external) {
    1259          16 :                         strcpy(*dst, "nil");
    1260          16 :                         return 3;
    1261             :                 }
    1262           0 :                 strcpy(*dst, str_nil);
    1263           0 :                 return 1;
    1264             :         }
    1265        4194 :         return snprintf(*dst, *len, OIDFMT "@0", *src);
    1266             : }
    1267             : 
    1268             : static int
    1269     4144016 : UUIDcompare(const void *L, const void *R)
    1270             : {
    1271     4144016 :         const uuid *l = L, *r = R;
    1272     4144016 :         if (is_uuid_nil(*r))
    1273      441040 :                 return !is_uuid_nil(*l);
    1274     3702976 :         if (is_uuid_nil(*l))
    1275             :                 return -1;
    1276      401253 :         return memcmp(l->u, r->u, UUID_SIZE);
    1277             : }
    1278             : 
    1279             : static ssize_t
    1280         278 : UUIDfromString(const char *svalue, size_t *len, void **RETVAL, bool external)
    1281             : {
    1282         278 :         uuid **retval = (uuid **) RETVAL;
    1283         278 :         const char *s = svalue;
    1284             : 
    1285         278 :         if (*len < UUID_SIZE || *retval == NULL) {
    1286          54 :                 GDKfree(*retval);
    1287          54 :                 if ((*retval = GDKmalloc(UUID_SIZE)) == NULL)
    1288             :                         return -1;
    1289          54 :                 *len = UUID_SIZE;
    1290             :         }
    1291         278 :         if (external && strcmp(svalue, "nil") == 0) {
    1292           0 :                 **retval = uuid_nil;
    1293           0 :                 return 3;
    1294             :         }
    1295         278 :         if (strNil(svalue)) {
    1296          33 :                 **retval = uuid_nil;
    1297          33 :                 return 1;
    1298             :         }
    1299         247 :         while (GDKisspace(*s))
    1300           2 :                 s++;
    1301             :         /* we don't use uuid_parse since we accept UUIDs without hyphens */
    1302             :         uuid u;
    1303        3371 :         for (int i = 0, j = 0; i < UUID_SIZE; i++) {
    1304             :                 /* on select locations we allow a '-' in the source string */
    1305        3176 :                 if (j == 8 || j == 12 || j == 16 || j == 20) {
    1306         781 :                         if (*s == '-')
    1307         728 :                                 s++;
    1308             :                 }
    1309        3176 :                 if (*s >= '0' && *s <= '9')
    1310        1599 :                         u.u[i] = *s - '0';
    1311        1577 :                 else if ('a' <= *s && *s <= 'f')
    1312        1143 :                         u.u[i] = *s - 'a' + 10;
    1313         434 :                 else if ('A' <= *s && *s <= 'F')
    1314         402 :                         u.u[i] = *s - 'A' + 10;
    1315             :                 else
    1316          32 :                         goto bailout;
    1317        3144 :                 s++;
    1318        3144 :                 j++;
    1319        3144 :                 u.u[i] <<= 4;
    1320        3144 :                 if (*s >= '0' && *s <= '9')
    1321        1497 :                         u.u[i] |= *s - '0';
    1322        1647 :                 else if ('a' <= *s && *s <= 'f')
    1323        1277 :                         u.u[i] |= *s - 'a' + 10;
    1324         370 :                 else if ('A' <= *s && *s <= 'F')
    1325         352 :                         u.u[i] |= *s - 'A' + 10;
    1326             :                 else
    1327          18 :                         goto bailout;
    1328        3126 :                 s++;
    1329        3126 :                 j++;
    1330             :         }
    1331         201 :         while (GDKisspace(*s))
    1332           6 :                 s++;
    1333         195 :         if (*s != 0)
    1334          12 :                 goto bailout;
    1335         183 :         **retval = u;
    1336         183 :         return (ssize_t) (s - svalue);
    1337             : 
    1338          62 :   bailout:
    1339          62 :         **retval = uuid_nil;
    1340          62 :         return -1;
    1341             : }
    1342             : 
    1343             : static BUN
    1344           0 : UUIDhash(const void *v)
    1345             : {
    1346           0 :         return mix_uuid((const uuid *) v);
    1347             : }
    1348             : 
    1349             : static void *
    1350          22 : UUIDread(void *U, size_t *dstlen, stream *s, size_t cnt)
    1351             : {
    1352          22 :         uuid *u = U;
    1353          22 :         if (u == NULL || *dstlen < cnt * sizeof(uuid)) {
    1354           0 :                 if ((u = GDKrealloc(u, cnt * sizeof(uuid))) == NULL)
    1355             :                         return NULL;
    1356           0 :                 *dstlen = cnt * sizeof(uuid);
    1357             :         }
    1358          22 :         if (mnstr_read(s, u, UUID_SIZE, cnt) < (ssize_t) cnt) {
    1359           0 :                 if (u != U)
    1360           0 :                         GDKfree(u);
    1361           0 :                 return NULL;
    1362             :         }
    1363             :         return u;
    1364             : }
    1365             : 
    1366             : static gdk_return
    1367          23 : UUIDwrite(const void *u, stream *s, size_t cnt)
    1368             : {
    1369          23 :         return mnstr_write(s, u, UUID_SIZE, cnt) ? GDK_SUCCEED : GDK_FAIL;
    1370             : }
    1371             : 
    1372             : static ssize_t
    1373     1764853 : UUIDtoString(str *retval, size_t *len, const void *VALUE, bool external)
    1374             : {
    1375     1764853 :         const uuid *value = VALUE;
    1376     1764853 :         if (*len <= UUID_STRLEN || *retval == NULL) {
    1377         105 :                 if (*retval)
    1378           0 :                         GDKfree(*retval);
    1379         105 :                 if ((*retval = GDKmalloc(UUID_STRLEN + 1)) == NULL)
    1380             :                         return -1;
    1381           0 :                 *len = UUID_STRLEN + 1;
    1382             :         }
    1383     1764130 :         if (is_uuid_nil(*value)) {
    1384           0 :                 if (external) {
    1385           0 :                         assert(*len >= strlen("nil") + 1);
    1386           0 :                         strcpy(*retval, "nil");
    1387           0 :                         return 3;
    1388             :                 }
    1389           0 :                 assert(*len >= strlen(str_nil) + 1);
    1390           0 :                 strcpy(*retval, str_nil);
    1391           0 :                 return 1;
    1392             :         }
    1393     1764130 :         snprintf(*retval, *len,
    1394             :                          "%02x%02x%02x%02x-%02x%02x-%02x%02x"
    1395             :                          "-%02x%02x-%02x%02x%02x%02x%02x%02x",
    1396     1764130 :                          value->u[0], value->u[1], value->u[2], value->u[3],
    1397     1764130 :                          value->u[4], value->u[5], value->u[6], value->u[7],
    1398     1764130 :                          value->u[8], value->u[9], value->u[10], value->u[11],
    1399     1764130 :                          value->u[12], value->u[13], value->u[14], value->u[15]);
    1400     1764130 :         assert(strlen(*retval) == UUID_STRLEN);
    1401             :         return UUID_STRLEN;
    1402             : }
    1403             : 
    1404             : static const blob blob_nil = {
    1405             :         ~(size_t) 0
    1406             : };
    1407             : 
    1408             : size_t
    1409    14806110 : blobsize(size_t nitems)
    1410             : {
    1411    14806110 :         if (nitems == ~(size_t) 0)
    1412     5334273 :                 nitems = 0;
    1413    14806110 :         assert(offsetof(blob, data) + nitems <= VAR_MAX);
    1414    14806110 :         return (size_t) (offsetof(blob, data) + nitems);
    1415             : }
    1416             : 
    1417             : static int
    1418    14342226 : BLOBcmp(const void *L, const void *R)
    1419             : {
    1420    14342226 :         const blob *l = L, *r = R;
    1421    14342226 :         int c;
    1422    14342226 :         if (is_blob_nil(r))
    1423    10407001 :                 return !is_blob_nil(l);
    1424     3935225 :         if (is_blob_nil(l))
    1425             :                 return -1;
    1426        6670 :         if (l->nitems < r->nitems) {
    1427        2571 :                 c = memcmp(l->data, r->data, l->nitems);
    1428        2571 :                 if (c == 0)
    1429        2273 :                         return -1;
    1430             :         } else {
    1431        4099 :                 c = memcmp(l->data, r->data, r->nitems);
    1432        4099 :                 if (c == 0)
    1433        3559 :                         return l->nitems > r->nitems;
    1434             :         }
    1435             :         return c;
    1436             : }
    1437             : 
    1438             : static void
    1439          35 : BLOBdel(Heap *h, var_t *idx)
    1440             : {
    1441          35 :         HEAP_free(h, *idx);
    1442          35 : }
    1443             : 
    1444             : static BUN
    1445       11280 : BLOBhash(const void *B)
    1446             : {
    1447       11280 :         const blob *b = B;
    1448       11280 :         return (BUN) b->nitems;
    1449             : }
    1450             : 
    1451             : static void *
    1452          65 : BLOBread(void *A, size_t *dstlen, stream *s, size_t cnt)
    1453             : {
    1454          65 :         blob *a = A;
    1455          65 :         int len;
    1456             : 
    1457          65 :         (void) cnt;
    1458          65 :         assert(cnt == 1);
    1459          65 :         if (mnstr_readInt(s, &len) != 1 || len < 0)
    1460             :                 return NULL;
    1461          65 :         if (a == NULL || *dstlen < (size_t) len) {
    1462           0 :                 if ((a = GDKrealloc(a, (size_t) len)) == NULL)
    1463             :                         return NULL;
    1464           0 :                 *dstlen = (size_t) len;
    1465             :         }
    1466          65 :         if (mnstr_read(s, (char *) a, (size_t) len, 1) != 1) {
    1467           0 :                 GDKfree(a);
    1468           0 :                 return NULL;
    1469             :         }
    1470             :         return a;
    1471             : }
    1472             : 
    1473             : static gdk_return
    1474          65 : BLOBwrite(const void *A, stream *s, size_t cnt)
    1475             : {
    1476          65 :         const blob *a = A;
    1477          65 :         size_t len = blobsize(a->nitems);
    1478             : 
    1479          65 :         (void) cnt;
    1480          65 :         assert(cnt == 1);
    1481         130 :         if (!mnstr_writeInt(s, (int) len) /* 64bit: check for overflow */ ||
    1482          65 :                 mnstr_write(s, a, len, 1) < 0)
    1483           0 :                 return GDK_FAIL;
    1484             :         return GDK_SUCCEED;
    1485             : }
    1486             : 
    1487             : static size_t
    1488        1471 : BLOBlength(const void *P)
    1489             : {
    1490        1471 :         const blob *p = P;
    1491        1471 :         size_t l = blobsize(p->nitems); /* 64bit: check for overflow */
    1492        1471 :         assert(l <= (size_t) GDK_int_max);
    1493        1471 :         return l;
    1494             : }
    1495             : 
    1496             : static gdk_return
    1497         921 : BLOBheap(Heap *heap, size_t capacity)
    1498             : {
    1499         921 :         return HEAP_initialize(heap, capacity, 0, (int) sizeof(var_t));
    1500             : }
    1501             : 
    1502             : static var_t
    1503     7401090 : BLOBput(BAT *b, var_t *bun, const void *VAL)
    1504             : {
    1505     7401090 :         const blob *val = VAL;
    1506     7401090 :         char *base = NULL;
    1507             : 
    1508     7401090 :         *bun = HEAP_malloc(b, blobsize(val->nitems));
    1509     7401089 :         base = b->tvheap->base;
    1510     7401089 :         if (*bun != (var_t) -1) {
    1511     7401089 :                 memcpy(&base[*bun], val, blobsize(val->nitems));
    1512     7401089 :                 b->tvheap->dirty = true;
    1513             :         }
    1514     7401089 :         return *bun;
    1515             : }
    1516             : 
    1517             : static ssize_t
    1518         400 : BLOBtostr(str *tostr, size_t *l, const void *P, bool external)
    1519             : {
    1520         400 :         static const char hexit[] = "0123456789ABCDEF";
    1521         400 :         const blob *p = P;
    1522         400 :         char *s;
    1523         400 :         size_t i;
    1524         400 :         size_t expectedlen;
    1525             : 
    1526         400 :         if (is_blob_nil(p))
    1527           3 :                 expectedlen = external ? 4 : 2;
    1528             :         else
    1529         397 :                 expectedlen = p->nitems * 2 + 1;
    1530         400 :         if (*l < expectedlen || *tostr == NULL) {
    1531          55 :                 GDKfree(*tostr);
    1532          55 :                 *tostr = GDKmalloc(expectedlen);
    1533          55 :                 if (*tostr == NULL)
    1534             :                         return -1;
    1535          55 :                 *l = expectedlen;
    1536             :         }
    1537         400 :         if (is_blob_nil(p)) {
    1538           3 :                 if (external) {
    1539           3 :                         strcpy(*tostr, "nil");
    1540           3 :                         return 3;
    1541             :                 }
    1542           0 :                 strcpy(*tostr, str_nil);
    1543           0 :                 return 1;
    1544             :         }
    1545             : 
    1546         397 :         s = *tostr;
    1547             : 
    1548    25857596 :         for (i = 0; i < p->nitems; i++) {
    1549    25857199 :                 *s++ = hexit[(p->data[i] >> 4) & 15];
    1550    25857199 :                 *s++ = hexit[p->data[i] & 15];
    1551             :         }
    1552         397 :         *s = '\0';
    1553         397 :         return (ssize_t) (s - *tostr);
    1554             : }
    1555             : 
    1556             : static ssize_t
    1557        2393 : BLOBfromstr(const char *instr, size_t *l, void **VAL, bool external)
    1558             : {
    1559        2393 :         blob **val = (blob **) VAL;
    1560        2393 :         size_t i;
    1561        2393 :         size_t nitems;
    1562        2393 :         size_t nbytes;
    1563        2393 :         blob *result;
    1564        2393 :         const char *s = instr;
    1565             : 
    1566        4786 :         if (strNil(instr) || (external && strncmp(instr, "nil", 3) == 0)) {
    1567           0 :                 nbytes = blobsize(0);
    1568           0 :                 if (*l < nbytes || *val == NULL) {
    1569           0 :                         GDKfree(*val);
    1570           0 :                         if ((*val = GDKmalloc(nbytes)) == NULL)
    1571             :                                 return -1;
    1572             :                 }
    1573           0 :                 **val = blob_nil;
    1574           0 :                 return strNil(instr) ? 1 : 3;
    1575             :         }
    1576             : 
    1577             :         /* count hexits and check for hexits/space */
    1578    21957765 :         for (i = nitems = 0; instr[i]; i++) {
    1579    21955375 :                 if (GDKisxdigit(instr[i]))
    1580    21955372 :                         nitems++;
    1581           3 :                 else if (!GDKisspace(instr[i])) {
    1582           3 :                         GDKerror("Illegal char in blob\n");
    1583           3 :                         return -1;
    1584             :                 }
    1585             :         }
    1586        2390 :         if (nitems % 2 != 0) {
    1587           0 :                 GDKerror("Illegal blob length '%zu' (should be even)\n", nitems);
    1588           0 :                 return -1;
    1589             :         }
    1590        2390 :         nitems /= 2;
    1591        2390 :         nbytes = blobsize(nitems);
    1592             : 
    1593        2390 :         if (*l < nbytes || *val == NULL) {
    1594        2292 :                 GDKfree(*val);
    1595        2292 :                 *val = GDKmalloc(nbytes);
    1596        2292 :                 if( *val == NULL)
    1597             :                         return -1;
    1598        2292 :                 *l = nbytes;
    1599             :         }
    1600        2390 :         result = *val;
    1601        2390 :         result->nitems = nitems;
    1602             : 
    1603             :         /*
    1604             :            // Read the values of the blob.
    1605             :          */
    1606    10980076 :         for (i = 0; i < nitems; ++i) {
    1607    10977686 :                 int res = 0;
    1608             : 
    1609    10977686 :                 for (;;) {
    1610    10977686 :                         if (*s >= '0' && *s <= '9') {
    1611     5900546 :                                 res = *s - '0';
    1612     5077140 :                         } else if (*s >= 'A' && *s <= 'F') {
    1613     2651908 :                                 res = 10 + *s - 'A';
    1614     2425232 :                         } else if (*s >= 'a' && *s <= 'f') {
    1615     2425232 :                                 res = 10 + *s - 'a';
    1616             :                         } else {
    1617           0 :                                 assert(GDKisspace(*s));
    1618           0 :                                 s++;
    1619           0 :                                 continue;
    1620             :                         }
    1621    10977686 :                         break;
    1622             :                 }
    1623    10977686 :                 s++;
    1624    10977686 :                 res <<= 4;
    1625    10977686 :                 for (;;) {
    1626    10977686 :                         if (*s >= '0' && *s <= '9') {
    1627     5899417 :                                 res += *s - '0';
    1628     5078269 :                         } else if (*s >= 'A' && *s <= 'F') {
    1629     2654281 :                                 res += 10 + *s - 'A';
    1630     2423988 :                         } else if (*s >= 'a' && *s <= 'f') {
    1631     2423988 :                                 res += 10 + *s - 'a';
    1632             :                         } else {
    1633           0 :                                 assert(GDKisspace(*s));
    1634           0 :                                 s++;
    1635           0 :                                 continue;
    1636             :                         }
    1637    10977686 :                         break;
    1638             :                 }
    1639    10977686 :                 s++;
    1640             : 
    1641    10977686 :                 result->data[i] = (uint8_t) res;
    1642             :         }
    1643        2390 :         while (GDKisspace(*s))
    1644           0 :                 s++;
    1645             : 
    1646        2390 :         return (ssize_t) (s - instr);
    1647             : }
    1648             : 
    1649             : atomDesc BATatoms[MAXATOMS] = {
    1650             :         [TYPE_void] = {
    1651             :                 .name = "void",
    1652             :                 .storage = TYPE_void,
    1653             :                 .linear = true,
    1654             : #if SIZEOF_OID == SIZEOF_INT
    1655             :                 .atomNull = (void *) &int_nil,
    1656             :                 .atomCmp = (int (*)(const void *, const void *)) intCmp,
    1657             :                 .atomHash = (BUN (*)(const void *)) intHash,
    1658             : #else
    1659             :                 .atomNull = (void *) &lng_nil,
    1660             :                 .atomCmp = (int (*)(const void *, const void *)) lngCmp,
    1661             :                 .atomHash = (BUN (*)(const void *)) lngHash,
    1662             : #endif
    1663             :                 .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) OIDfromStr,
    1664             :                 .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) OIDtoStr,
    1665             :                 .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) voidRead,
    1666             :                 .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) voidWrite,
    1667             :         },
    1668             :         [TYPE_bit] = {
    1669             :                 .name = "bit",
    1670             :                 .storage = TYPE_bte,
    1671             :                 .linear = true,
    1672             :                 .size = sizeof(bit),
    1673             :                 .atomNull = (void *) &bte_nil,
    1674             :                 .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) bitFromStr,
    1675             :                 .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) bitToStr,
    1676             :                 .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) bitRead,
    1677             :                 .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) bitWrite,
    1678             :                 .atomCmp = (int (*)(const void *, const void *)) bteCmp,
    1679             :                 .atomHash = (BUN (*)(const void *)) bteHash,
    1680             :         },
    1681             :         [TYPE_msk] = {
    1682             :                 .name = "msk",
    1683             :                 .storage = TYPE_msk,
    1684             :                 .linear = false,
    1685             :                 .size = 1,      /* really 1/8 */
    1686             :                 .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) mskFromStr,
    1687             :                 .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) mskToStr,
    1688             :                 .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) mskRead,
    1689             :                 .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) mskWrite,
    1690             :                 .atomCmp = (int (*)(const void *, const void *)) mskCmp,
    1691             :         },
    1692             :         [TYPE_bte] = {
    1693             :                 .name = "bte",
    1694             :                 .storage = TYPE_bte,
    1695             :                 .linear = true,
    1696             :                 .size = sizeof(bte),
    1697             :                 .atomNull = (void *) &bte_nil,
    1698             :                 .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) bteFromStr,
    1699             :                 .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) bteToStr,
    1700             :                 .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) bteRead,
    1701             :                 .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) bteWrite,
    1702             :                 .atomCmp = (int (*)(const void *, const void *)) bteCmp,
    1703             :                 .atomHash = (BUN (*)(const void *)) bteHash,
    1704             :         },
    1705             :         [TYPE_sht] = {
    1706             :                 .name = "sht",
    1707             :                 .storage = TYPE_sht,
    1708             :                 .linear = true,
    1709             :                 .size = sizeof(sht),
    1710             :                 .atomNull = (void *) &sht_nil,
    1711             :                 .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) shtFromStr,
    1712             :                 .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) shtToStr,
    1713             :                 .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) shtRead,
    1714             :                 .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) shtWrite,
    1715             :                 .atomCmp = (int (*)(const void *, const void *)) shtCmp,
    1716             :                 .atomHash = (BUN (*)(const void *)) shtHash,
    1717             :         },
    1718             :         [TYPE_int] = {
    1719             :                 .name = "int",
    1720             :                 .storage = TYPE_int,
    1721             :                 .linear = true,
    1722             :                 .size = sizeof(int),
    1723             :                 .atomNull = (void *) &int_nil,
    1724             :                 .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) intFromStr,
    1725             :                 .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) intToStr,
    1726             :                 .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) intRead,
    1727             :                 .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) intWrite,
    1728             :                 .atomCmp = (int (*)(const void *, const void *)) intCmp,
    1729             :                 .atomHash = (BUN (*)(const void *)) intHash,
    1730             :         },
    1731             :         [TYPE_oid] = {
    1732             :                 .name = "oid",
    1733             :                 .linear = true,
    1734             :                 .size = sizeof(oid),
    1735             : #if SIZEOF_OID == SIZEOF_INT
    1736             :                 .storage = TYPE_int,
    1737             :                 .atomNull = (void *) &int_nil,
    1738             :                 .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) intRead,
    1739             :                 .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) intWrite,
    1740             :                 .atomCmp = (int (*)(const void *, const void *)) intCmp,
    1741             :                 .atomHash = (BUN (*)(const void *)) intHash,
    1742             : #else
    1743             :                 .storage = TYPE_lng,
    1744             :                 .atomNull = (void *) &lng_nil,
    1745             :                 .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) lngRead,
    1746             :                 .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) lngWrite,
    1747             :                 .atomCmp = (int (*)(const void *, const void *)) lngCmp,
    1748             :                 .atomHash = (BUN (*)(const void *)) lngHash,
    1749             : #endif
    1750             :                 .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) OIDfromStr,
    1751             :                 .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) OIDtoStr,
    1752             :         },
    1753             :         [TYPE_ptr] = {
    1754             :                 .name = "ptr",
    1755             :                 .storage = TYPE_ptr,
    1756             :                 .linear = true,
    1757             :                 .size = sizeof(void *),
    1758             :                 .atomNull = (void *) &ptr_nil,
    1759             :                 .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) ptrFromStr,
    1760             :                 .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) ptrToStr,
    1761             :                 .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) ptrRead,
    1762             :                 .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) ptrWrite,
    1763             : #if SIZEOF_VOID_P == SIZEOF_INT
    1764             :                 .atomCmp = (int (*)(const void *, const void *)) intCmp,
    1765             :                 .atomHash = (BUN (*)(const void *)) intHash,
    1766             : #else /* SIZEOF_VOID_P == SIZEOF_LNG */
    1767             :                 .atomCmp = (int (*)(const void *, const void *)) lngCmp,
    1768             :                 .atomHash = (BUN (*)(const void *)) lngHash,
    1769             : #endif
    1770             :         },
    1771             :         [TYPE_flt] = {
    1772             :                 .name = "flt",
    1773             :                 .storage = TYPE_flt,
    1774             :                 .linear = true,
    1775             :                 .size = sizeof(flt),
    1776             :                 .atomNull = (void *) &flt_nil,
    1777             :                 .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) fltFromStr,
    1778             :                 .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) fltToStr,
    1779             :                 .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) fltRead,
    1780             :                 .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) fltWrite,
    1781             :                 .atomCmp = (int (*)(const void *, const void *)) fltCmp,
    1782             :                 .atomHash = (BUN (*)(const void *)) fltHash,
    1783             :         },
    1784             :         [TYPE_dbl] = {
    1785             :                 .name = "dbl",
    1786             :                 .storage = TYPE_dbl,
    1787             :                 .linear = true,
    1788             :                 .size = sizeof(dbl),
    1789             :                 .atomNull = (void *) &dbl_nil,
    1790             :                 .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) dblFromStr,
    1791             :                 .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) dblToStr,
    1792             :                 .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) dblRead,
    1793             :                 .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) dblWrite,
    1794             :                 .atomCmp = (int (*)(const void *, const void *)) dblCmp,
    1795             :                 .atomHash = (BUN (*)(const void *)) dblHash,
    1796             :         },
    1797             :         [TYPE_lng] = {
    1798             :                 .name = "lng",
    1799             :                 .storage = TYPE_lng,
    1800             :                 .linear = true,
    1801             :                 .size = sizeof(lng),
    1802             :                 .atomNull = (void *) &lng_nil,
    1803             :                 .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) lngFromStr,
    1804             :                 .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) lngToStr,
    1805             :                 .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) lngRead,
    1806             :                 .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) lngWrite,
    1807             :                 .atomCmp = (int (*)(const void *, const void *)) lngCmp,
    1808             :                 .atomHash = (BUN (*)(const void *)) lngHash,
    1809             :         },
    1810             : #ifdef HAVE_HGE
    1811             :         [TYPE_hge] = {
    1812             :                 .name = "hge",
    1813             :                 .storage = TYPE_hge,
    1814             :                 .linear = true,
    1815             :                 .size = sizeof(hge),
    1816             :                 .atomNull = (void *) &hge_nil,
    1817             :                 .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) hgeFromStr,
    1818             :                 .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) hgeToStr,
    1819             :                 .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) hgeRead,
    1820             :                 .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) hgeWrite,
    1821             :                 .atomCmp = (int (*)(const void *, const void *)) hgeCmp,
    1822             :                 .atomHash = (BUN (*)(const void *)) hgeHash,
    1823             :         },
    1824             : #endif
    1825             :         [TYPE_date] = {
    1826             :                 .name = "date",
    1827             :                 .storage = TYPE_int,
    1828             :                 .linear = true,
    1829             :                 .size = sizeof(int),
    1830             :                 .atomNull = (void *) &int_nil,
    1831             :                 .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) date_fromstr,
    1832             :                 .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) date_tostr,
    1833             :                 .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) intRead,
    1834             :                 .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) intWrite,
    1835             :                 .atomCmp = (int (*)(const void *, const void *)) intCmp,
    1836             :                 .atomHash = (BUN (*)(const void *)) intHash,
    1837             :         },
    1838             :         [TYPE_daytime] = {
    1839             :                 .name = "daytime",
    1840             :                 .storage = TYPE_lng,
    1841             :                 .linear = true,
    1842             :                 .size = sizeof(lng),
    1843             :                 .atomNull = (void *) &lng_nil,
    1844             :                 .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) daytime_tz_fromstr,
    1845             :                 .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) daytime_tostr,
    1846             :                 .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) lngRead,
    1847             :                 .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) lngWrite,
    1848             :                 .atomCmp = (int (*)(const void *, const void *)) lngCmp,
    1849             :                 .atomHash = (BUN (*)(const void *)) lngHash,
    1850             :         },
    1851             :         [TYPE_timestamp] = {
    1852             :                 .name = "timestamp",
    1853             :                 .storage = TYPE_lng,
    1854             :                 .linear = true,
    1855             :                 .size = sizeof(lng),
    1856             :                 .atomNull = (void *) &lng_nil,
    1857             :                 .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) timestamp_fromstr,
    1858             :                 .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) timestamp_tostr,
    1859             :                 .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) lngRead,
    1860             :                 .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) lngWrite,
    1861             :                 .atomCmp = (int (*)(const void *, const void *)) lngCmp,
    1862             :                 .atomHash = (BUN (*)(const void *)) lngHash,
    1863             :         },
    1864             :         [TYPE_uuid] = {
    1865             :                 .name = "uuid",
    1866             :                 .storage = TYPE_uuid,
    1867             :                 .linear = true,
    1868             :                 .size = sizeof(uuid),
    1869             :                 .atomNull = (void *) &uuid_nil,
    1870             :                 .atomFromStr = UUIDfromString,
    1871             :                 .atomToStr = UUIDtoString,
    1872             :                 .atomRead = UUIDread,
    1873             :                 .atomWrite = UUIDwrite,
    1874             :                 .atomCmp = UUIDcompare,
    1875             :                 .atomHash = UUIDhash,
    1876             :         },
    1877             :         [TYPE_str] = {
    1878             :                 .name = "str",
    1879             :                 .storage = TYPE_str,
    1880             :                 .linear = true,
    1881             :                 .size = sizeof(var_t),
    1882             :                 .atomNull = (void *) str_nil,
    1883             :                 .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) strFromStr,
    1884             :                 .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) strToStr,
    1885             :                 .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) strRead,
    1886             :                 .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) strWrite,
    1887             :                 .atomCmp = (int (*)(const void *, const void *)) strCmp,
    1888             :                 .atomHash = (BUN (*)(const void *)) strHash,
    1889             :                 .atomPut = strPut,
    1890             :                 .atomLen = (size_t (*)(const void *)) strLen,
    1891             :                 .atomHeap = strHeap,
    1892             :         },
    1893             :         [TYPE_blob] = {
    1894             :                 .name = "blob",
    1895             :                 .storage = TYPE_blob,
    1896             :                 .linear = true,
    1897             :                 .size = sizeof(var_t),
    1898             :                 .atomNull = (void *) &blob_nil,
    1899             :                 .atomFromStr = BLOBfromstr,
    1900             :                 .atomToStr = BLOBtostr,
    1901             :                 .atomRead = BLOBread,
    1902             :                 .atomWrite = BLOBwrite,
    1903             :                 .atomCmp = BLOBcmp,
    1904             :                 .atomHash = BLOBhash,
    1905             :                 .atomPut = BLOBput,
    1906             :                 .atomDel = BLOBdel,
    1907             :                 .atomLen = BLOBlength,
    1908             :                 .atomHeap = BLOBheap,
    1909             :         },
    1910             : };
    1911             : 
    1912             : int GDKatomcnt = TYPE_blob + 1;
    1913             : 
    1914             : /*
    1915             :  * Sometimes a bat descriptor is loaded before the dynamic module
    1916             :  * defining the atom is loaded. To support this an extra set of
    1917             :  * unknown atoms is kept.  These can be accessed via the ATOMunknown
    1918             :  * interface. Finding an (negative) atom index can be done via
    1919             :  * ATOMunknown_find, which simply adds the atom if it's not in the
    1920             :  * unknown set. The index can be used to find the name of an unknown
    1921             :  * ATOM via ATOMunknown_name.
    1922             :  */
    1923             : static str unknown[MAXATOMS] = { NULL };
    1924             : 
    1925             : int
    1926         241 : ATOMunknown_find(const char *nme)
    1927             : {
    1928         241 :         int i, j = 0;
    1929             : 
    1930             :         /* first try to find the atom */
    1931         241 :         MT_lock_set(&GDKatomLock);
    1932        7428 :         for (i = 1; i < MAXATOMS; i++) {
    1933        7133 :                 if (unknown[i]) {
    1934         338 :                         if (strcmp(unknown[i], nme) == 0) {
    1935         187 :                                 MT_lock_unset(&GDKatomLock);
    1936         187 :                                 return -i;
    1937             :                         }
    1938        6795 :                 } else if (j == 0)
    1939        6946 :                         j = i;
    1940             :         }
    1941          54 :         if (j == 0) {
    1942             :                 /* no space for new atom (shouldn't happen) */
    1943           0 :                 MT_lock_unset(&GDKatomLock);
    1944           0 :                 return 0;
    1945             :         }
    1946          54 :         if ((unknown[j] = GDKstrdup(nme)) == NULL) {
    1947           0 :                 MT_lock_unset(&GDKatomLock);
    1948           0 :                 return 0;
    1949             :         }
    1950          54 :         MT_lock_unset(&GDKatomLock);
    1951          54 :         return -j;
    1952             : }
    1953             : 
    1954             : const char *
    1955         297 : ATOMunknown_name(int i)
    1956             : {
    1957         297 :         assert(i < 0);
    1958         297 :         assert(-i < MAXATOMS);
    1959         297 :         assert(unknown[-i]);
    1960         297 :         return unknown[-i];
    1961             : }
    1962             : 
    1963             : void
    1964         350 : ATOMunknown_clean(void)
    1965             : {
    1966         350 :         int i;
    1967             : 
    1968         350 :         MT_lock_set(&GDKatomLock);
    1969         754 :         for (i = 1; i < MAXATOMS; i++) {
    1970         404 :                 if(unknown[i]) {
    1971          54 :                         GDKfree(unknown[i]);
    1972          54 :                         unknown[i] = NULL;
    1973             :                 } else {
    1974             :                         break;
    1975             :                 }
    1976             :         }
    1977         350 :         MT_lock_unset(&GDKatomLock);
    1978         350 : }

Generated by: LCOV version 1.14