LCOV - code coverage report
Current view: top level - gdk - gdk_atoms.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 604 808 74.8 %
Date: 2024-12-20 20:06:10 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         200 : mskCmp(const msk *l, const msk *r)
      43             : {
      44         200 :         return (*l > *r) - (*l < *r);
      45             : }
      46             : 
      47             : static int
      48   899089250 : bteCmp(const bte *l, const bte *r)
      49             : {
      50   899089250 :         return (*l > *r) - (*l < *r);
      51             : }
      52             : 
      53             : static int
      54    75859564 : shtCmp(const sht *l, const sht *r)
      55             : {
      56    75859564 :         return (*l > *r) - (*l < *r);
      57             : }
      58             : 
      59             : static int
      60  3197066136 : intCmp(const int *l, const int *r)
      61             : {
      62  3197066136 :         return (*l > *r) - (*l < *r);
      63             : }
      64             : 
      65             : static int
      66   412724608 : fltCmp(const flt *l, const flt *r)
      67             : {
      68   412724608 :         return is_flt_nil(*l) ? -!is_flt_nil(*r) : is_flt_nil(*r) ? 1 : (*l > *r) - (*l < *r);
      69             : }
      70             : 
      71             : static int
      72  6492147627 : lngCmp(const lng *l, const lng *r)
      73             : {
      74  6492147627 :         return (*l > *r) - (*l < *r);
      75             : }
      76             : 
      77             : #ifdef HAVE_HGE
      78             : static int
      79   250677113 : hgeCmp(const hge *l, const hge *r)
      80             : {
      81   250677113 :         return (*l > *r) - (*l < *r);
      82             : }
      83             : #endif
      84             : 
      85             : static int
      86    54939463 : dblCmp(const dbl *l, const dbl *r)
      87             : {
      88    54939463 :         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     1147997 : intHash(const int *v)
     109             : {
     110     1147997 :         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      151958 : fltHash(const flt *v)
     129             : {
     130      151958 :         if (is_flt_nil(*v))
     131             :                 return (BUN) mix_int(GDK_int_min);
     132      151825 :         if (*v == 0)
     133             :                 return (BUN) mix_int(0);
     134      147836 :         return (BUN) mix_int(*(const unsigned int *) v);
     135             : }
     136             : 
     137             : static BUN
     138       47167 : dblHash(const dbl *v)
     139             : {
     140       47167 :         if (is_dbl_nil(*v))
     141             :                 return (BUN) mix_lng(GDK_lng_min);
     142       45232 :         if (*v == 0)
     143             :                 return (BUN) mix_lng(0);
     144       35783 :         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        3952 : ATOMallocate(const char *id)
     189             : {
     190        3952 :         int t;
     191             : 
     192        3952 :         if (strlen(id) >= IDLENGTH) {
     193           0 :                 GDKerror("name too long");
     194           0 :                 return int_nil;
     195             :         }
     196             : 
     197        3952 :         MT_lock_set(&GDKatomLock);
     198        3952 :         t = ATOMindex(id);
     199        3952 :         if (t < 0) {
     200        3952 :                 t = -t;
     201        3952 :                 if (t == GDKatomcnt) {
     202        3952 :                         if (GDKatomcnt == MAXATOMS) {
     203           0 :                                 MT_lock_unset(&GDKatomLock);
     204           0 :                                 GDKerror("too many types");
     205           0 :                                 return int_nil;
     206             :                         }
     207        3952 :                         GDKatomcnt++;
     208             :                 }
     209        3952 :                 BATatoms[t] = (atomDesc) {
     210             :                         .size = sizeof(int),    /* default */
     211             :                         .linear = true,         /* default */
     212             :                         .storage = t,           /* default */
     213             :                 };
     214        3952 :                 strcpy(BATatoms[t].name, id);
     215             :         }
     216        3952 :         MT_lock_unset(&GDKatomLock);
     217        3952 :         return t;
     218             : }
     219             : 
     220             : int
     221       65395 : ATOMindex(const char *nme)
     222             : {
     223       65395 :         int t, j = GDKatomcnt;
     224             : 
     225      779524 :         for (t = 0; t < GDKatomcnt; t++) {
     226      774982 :                 if (!BATatoms[t].name[0]) {
     227           0 :                         if (j == GDKatomcnt)
     228      714129 :                                 j = t;
     229      774982 :                 } else if (strcmp(nme, BATatoms[t].name) == 0) {
     230       60853 :                         return t;
     231             :                 }
     232             : 
     233             :         }
     234        4542 :         return -j;
     235             : }
     236             : 
     237             : const char *
     238      398961 : ATOMname(int t)
     239             : {
     240      398961 :         return t >= 0 && t < GDKatomcnt && *BATatoms[t].name ? BATatoms[t].name : "null";
     241             : }
     242             : 
     243             : bool
     244      245260 : ATOMisdescendant(int tpe, int parent)
     245             : {
     246      245260 :         int cur = -1;
     247             : 
     248      498278 :         while (cur != tpe) {
     249      253018 :                 cur = tpe;
     250      253018 :                 if (cur == parent)
     251             :                         return true;
     252      253018 :                 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          22 : ATOMnil(int t)
     284             : {
     285          22 :         const void *src = ATOMnilptr(t);
     286          22 :         size_t len = ATOMlen(ATOMtype(t), src);
     287          22 :         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     8045027 : ATOMlen(int t, const void *src)
     299             : {
     300     8045027 :         size_t (*l)(const void *) = BATatoms[t].atomLen;
     301             : 
     302     8045027 :         return l ? (*l) (src) : ATOMsize(t);
     303             : }
     304             : 
     305             : gdk_return
     306      717547 : ATOMheap(int t, Heap *hp, size_t cap)
     307             : {
     308      717547 :         gdk_return (*h) (Heap *, size_t) = BATatoms[t].atomHeap;
     309             : 
     310      717547 :         if (h) {
     311      717547 :                 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         716 : ATOMprint(int t, const void *p, stream *s)
     324             : {
     325         716 :         ssize_t (*tostr) (char **, size_t *, const void *, bool);
     326         716 :         ssize_t res;
     327             : 
     328        1432 :         if (p && t >= 0 && t < GDKatomcnt && (tostr = BATatoms[t].atomToStr)) {
     329         716 :                 size_t sz;
     330             : 
     331         716 :                 if (t < TYPE_date) {
     332         246 :                         char buf[dblStrlen], *addr = buf;       /* use memory from stack */
     333             : 
     334         246 :                         sz = dblStrlen;
     335         246 :                         res = (*tostr) (&addr, &sz, p, true);
     336         246 :                         if (res > 0)
     337         246 :                                 res = mnstr_write(s, buf, (size_t) res, 1);
     338             :                 } else {
     339         470 :                         str buf = NULL;
     340             : 
     341         470 :                         sz = 0;
     342         470 :                         res = (*tostr) (&buf, &sz, p, true);
     343         470 :                         if (res > 0)
     344         470 :                                 res = mnstr_write(s, buf, (size_t) res, 1);
     345         470 :                         GDKfree(buf);
     346             :                 }
     347             :         } else {
     348           0 :                 res = mnstr_write(s, "nil", 1, 3);
     349             :         }
     350         716 :         if (res < 0)
     351           0 :                 GDKsyserror("ATOMprint: write failure\n");
     352         716 :         return (int) res;
     353             : }
     354             : 
     355             : 
     356             : char *
     357       23035 : ATOMformat(int t, const void *p)
     358             : {
     359       23035 :         ssize_t (*tostr) (char **, size_t *, const void *, bool);
     360             : 
     361       23035 :         if (p && 0 <= t && t < GDKatomcnt && (tostr = BATatoms[t].atomToStr)) {
     362       23035 :                 size_t sz = 0;
     363       23035 :                 char *buf = NULL;
     364       23035 :                 ssize_t res = (*tostr) (&buf, &sz, p, true);
     365       23036 :                 if (res < 0 && buf) {
     366           0 :                         GDKfree(buf);
     367           0 :                         buf = NULL;
     368             :                 }
     369       23036 :                 return buf;
     370             :         }
     371           0 :         return GDKstrdup("nil");
     372             : }
     373             : 
     374             : ptr
     375       55978 : ATOMdup(int t, const void *p)
     376             : {
     377       55978 :         size_t len = ATOMlen(t, p);
     378       55978 :         ptr n = GDKmalloc(len);
     379             : 
     380       55978 :         if (n)
     381       55978 :                 memcpy(n, p, len);
     382       55978 :         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       15590 : bitFromStr(const char *src, size_t *len, bit **dst, bool external)
     498             : {
     499       15590 :         const char *p = src;
     500             : 
     501       15590 :         atommem(sizeof(bit));
     502             : 
     503       15590 :         **dst = bit_nil;
     504             : 
     505       15590 :         if (strNil(src))
     506             :                 return 1;
     507             : 
     508       15590 :         while (GDKisspace(*p))
     509           0 :                 p++;
     510       15590 :         if (*p == '0') {
     511         294 :                 **dst = FALSE;
     512         294 :                 p++;
     513       15296 :         } else if (*p == '1') {
     514          60 :                 **dst = TRUE;
     515          60 :                 p++;
     516       15236 :         } else if (strncasecmp(p, "true",  4) == 0) {
     517       10272 :                 **dst = TRUE;
     518       10272 :                 p += 4;
     519        4964 :         } else if (strncasecmp(p, "false", 5) == 0) {
     520        4932 :                 **dst = FALSE;
     521        4932 :                 p += 5;
     522          32 :         } else if (external && strncasecmp(p, "nil",   3) == 0) {
     523           0 :                 p += 3;
     524             :         } else {
     525             :                 return -1;
     526             :         }
     527       15558 :         while (GDKisspace(*p))
     528           0 :                 p++;
     529       15558 :         return (ssize_t) (p - src);
     530             : }
     531             : 
     532             : ssize_t
     533       70458 : bitToStr(char **dst, size_t *len, const bit *src, bool external)
     534             : {
     535       70458 :         atommem(6);
     536             : 
     537       70458 :         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       70433 :         if (*src) {
     546       25039 :                 strcpy(*dst, "true");
     547       25039 :                 return 4;
     548             :         }
     549       45394 :         strcpy(*dst, "false");
     550       45394 :         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   247668885 : numFromStr(const char *src, size_t *len, void **dst, int tp, bool external)
     700             : {
     701   247668885 :         const char *p = src;
     702   247668885 :         size_t sz = ATOMsize(tp);
     703             : #ifdef HAVE_HGE
     704   247668885 :         hge base = 0;
     705             : #else
     706             :         lng base = 0;
     707             : #endif
     708   247668885 :         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   247668885 :         atommem(sz);
     719             : 
     720   247668885 :         if (strNil(src)) {
     721           0 :                 memcpy(*dst, ATOMnilptr(tp), sz);
     722           0 :                 return 1;
     723             :         }
     724             : 
     725   247668983 :         while (GDKisspace(*p))
     726          98 :                 p++;
     727   247668885 :         if (!GDKisdigit(*p)) {
     728       11704 :                 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       11515 :                 case '-':
     740       11515 :                         sign = -1;
     741       11515 :                         p++;
     742       11515 :                         break;
     743           1 :                 case '+':
     744           1 :                         p++;
     745           1 :                         break;
     746             :                 }
     747       11699 :                 if (!GDKisdigit(*p)) {
     748         189 :                         GDKerror("not a number");
     749         189 :                         goto bailout;
     750             :                 }
     751             :         }
     752   654442467 :         do {
     753   654442467 :                 int dig = base10(*p);
     754   654442467 :                 if (base > maxdiv[1].maxval ||
     755           1 :                     (base == maxdiv[1].maxval && dig > maxmod10)) {
     756             :                         /* overflow */
     757           0 :                         goto overflow;
     758             :                 }
     759   654442467 :                 base = 10 * base + dig;
     760   654442467 :                 p++;
     761   654442467 :         } while (GDKisdigit(*p));
     762   247668691 :         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   247668691 :         base *= sign;
     788   247668691 :         switch (sz) {
     789       53787 :         case 1: {
     790       53787 :                 bte **dstbte = (bte **) dst;
     791       53787 :                 if (base < GDK_bte_min || base > GDK_bte_max) {
     792           0 :                         goto overflow;
     793             :                 }
     794       53787 :                 **dstbte = (bte) base;
     795       53787 :                 break;
     796             :         }
     797      394664 :         case 2: {
     798      394664 :                 sht **dstsht = (sht **) dst;
     799      394664 :                 if (base < GDK_sht_min || base > GDK_sht_max) {
     800           3 :                         goto overflow;
     801             :                 }
     802      394661 :                 **dstsht = (sht) base;
     803      394661 :                 break;
     804             :         }
     805   243659535 :         case 4: {
     806   243659535 :                 int **dstint = (int **) dst;
     807   243659535 :                 if (base < GDK_int_min || base > GDK_int_max) {
     808           2 :                         goto overflow;
     809             :                 }
     810   243659533 :                 **dstint = (int) base;
     811   243659533 :                 break;
     812             :         }
     813     1912302 :         case 8: {
     814     1912302 :                 lng **dstlng = (lng **) dst;
     815             : #ifdef HAVE_HGE
     816     1912302 :                 if (base < GDK_lng_min || base > GDK_lng_max) {
     817           4 :                         goto overflow;
     818             :                 }
     819             : #endif
     820     1912298 :                 **dstlng = (lng) base;
     821     1912298 :                 if (p[0] == 'L' && p[1] == 'L')
     822           0 :                         p += 2;
     823             :                 break;
     824             :         }
     825             : #ifdef HAVE_HGE
     826     1648403 :         case 16: {
     827     1648403 :                 hge **dsthge = (hge **) dst;
     828     1648403 :                 **dsthge = (hge) base;
     829     1648403 :                 if (p[0] == 'L' && p[1] == 'L')
     830           0 :                         p += 2;
     831             :                 break;
     832             :         }
     833             : #endif
     834             :         }
     835   247668782 :         while (GDKisspace(*p))
     836         100 :                 p++;
     837   247668682 :         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         203 :   bailout:
     845         203 :         memcpy(*dst, ATOMnilptr(tp), sz);
     846         203 :         return -1;
     847             : }
     848             : 
     849             : ssize_t
     850       53818 : bteFromStr(const char *src, size_t *len, bte **dst, bool external)
     851             : {
     852       53818 :         return numFromStr(src, len, (void **) dst, TYPE_bte, external);
     853             : }
     854             : 
     855             : ssize_t
     856      394796 : shtFromStr(const char *src, size_t *len, sht **dst, bool external)
     857             : {
     858      394796 :         return numFromStr(src, len, (void **) dst, TYPE_sht, external);
     859             : }
     860             : 
     861             : ssize_t
     862   244617062 : intFromStr(const char *src, size_t *len, int **dst, bool external)
     863             : {
     864   244617062 :         return numFromStr(src, len, (void **) dst, TYPE_int, external);
     865             : }
     866             : 
     867             : ssize_t
     868     1912342 : lngFromStr(const char *src, size_t *len, lng **dst, bool external)
     869             : {
     870     1912342 :         return numFromStr(src, len, (void **) dst, TYPE_lng, external);
     871             : }
     872             : 
     873             : #ifdef HAVE_HGE
     874             : ssize_t
     875     1648415 : hgeFromStr(const char *src, size_t *len, hge **dst, bool external)
     876             : {
     877     1648415 :         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      124145 : mskWrite(const msk *a, stream *s, size_t cnt)
     908             : {
     909      124145 :         if (cnt == 0)
     910             :                 return GDK_SUCCEED;
     911      124145 :         if (cnt == 1)
     912      124145 :                 return mnstr_writeBte(s, (int8_t) *a) ? GDK_SUCCEED : GDK_FAIL;
     913             :         return GDK_FAIL;
     914             : }
     915             : 
     916             : static void *
     917      122953 : mskRead(msk *A, size_t *dstlen, stream *s, size_t cnt)
     918             : {
     919      122953 :         int8_t v;
     920      122953 :         msk *a = A;
     921      122953 :         if (cnt != 1)
     922             :                 return NULL;
     923      122953 :         if (a == NULL || *dstlen == 0) {
     924           0 :                 if ((a = GDKrealloc(a, 1)) == NULL)
     925             :                         return NULL;
     926           0 :                 *dstlen = 1;
     927             :         }
     928      122953 :         if (mnstr_readBte(s, &v) != 1) {
     929           0 :                 if (a != A)
     930           0 :                         GDKfree(a);
     931           0 :                 return NULL;
     932             :         }
     933      122953 :         *a = v != 0;
     934      122953 :         return a;
     935             : }
     936             : 
     937        7241 : atom_io(bit, Bte, bte)
     938             : 
     939       43061 : atomtostr(bte, "%hhd", )
     940      254280 : atom_io(bte, Bte, bte)
     941             : 
     942     1073017 : atomtostr(sht, "%hd", )
     943        8363 : atom_io(sht, Sht, sht)
     944             : 
     945    15536064 : atomtostr(int, "%d", )
     946      222310 : atom_io(int, Int, int)
     947             : 
     948      163330 : atomtostr(lng, LLFMT, )
     949        5893 : 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        3295 : hgeToStr(char **dst, size_t *len, const hge *src, bool external)
     957             : {
     958        3295 :         atommem(hgeStrlen);
     959        3295 :         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        3294 :         if ((hge) GDK_lng_min <= *src && *src <= (hge) GDK_lng_max) {
     970        3177 :                 lng s = (lng) *src;
     971        3177 :                 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      309058 : dblFromStr(const char *src, size_t *len, dbl **dst, bool external)
    1039             : {
    1040      309058 :         const char *p = src;
    1041      309058 :         ssize_t n = 0;
    1042      309058 :         double d;
    1043             : 
    1044             :         /* alloc memory */
    1045      309058 :         atommem(sizeof(dbl));
    1046             : 
    1047      309058 :         if (strNil(src)) {
    1048           0 :                 **dst = dbl_nil;
    1049           0 :                 return 1;
    1050             :         }
    1051             : 
    1052      309177 :         while (GDKisspace(*p))
    1053         119 :                 p++;
    1054      309058 :         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      309058 :                 char *pe;
    1065      309058 :                 errno = 0;
    1066      309058 :                 d = strtod(p, &pe);
    1067      332472 :                 if (p == pe)
    1068             :                         p = src; /* nothing converted */
    1069             :                 else
    1070      332438 :                         p = pe;
    1071      332472 :                 n = (ssize_t) (p - src);
    1072      332472 :                 if (n == 0 || (errno == ERANGE && (d < -1 || d > 1))
    1073      332430 :                     || !isfinite(d) /* no NaN or Infinite */
    1074             :                     ) {
    1075         104 :                         GDKerror("overflow or not a number\n");
    1076         104 :                         return -1;
    1077             :                 } else {
    1078      332408 :                         while (src[n] && GDKisspace(src[n]))
    1079          40 :                                 n++;
    1080      332368 :                         **dst = (dbl) d;
    1081             :                 }
    1082             :         }
    1083             :         return n;
    1084             : }
    1085             : 
    1086             : ssize_t
    1087       14049 : dblToStr(char **dst, size_t *len, const dbl *src, bool external)
    1088             : {
    1089       14049 :         int l = 0;
    1090             : 
    1091       14049 :         atommem(dblStrlen);
    1092       14049 :         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       14042 :         if (*src <= (dbl) 999999999999999 &&
    1101       13895 :             *src >= (dbl) -999999999999999 &&
    1102       13895 :             (dbl) (int) *src == *src) {
    1103        8602 :                 l = snprintf(*dst, *len, "%.0f", *src);
    1104        8602 :                 if (strtod(*dst, NULL) == *src)
    1105        8603 :                         return (ssize_t) l;
    1106             :         }
    1107       39293 :         for (int i = 4; i < 18; i++) {
    1108       39293 :                 l = snprintf(*dst, *len, "%.*g", i, *src);
    1109       39293 :                 if (strtod(*dst, NULL) == *src)
    1110             :                         break;
    1111             :         }
    1112        5440 :         return (ssize_t) l;
    1113             : }
    1114             : 
    1115         759 : atom_io(dbl, Lng, lng)
    1116             : 
    1117             : ssize_t
    1118     1842213 : fltFromStr(const char *src, size_t *len, flt **dst, bool external)
    1119             : {
    1120     1842213 :         const char *p = src;
    1121     1842213 :         ssize_t n = 0;
    1122     1842213 :         float f;
    1123             : 
    1124             :         /* alloc memory */
    1125     1842213 :         atommem(sizeof(flt));
    1126             : 
    1127     1842213 :         if (strNil(src)) {
    1128           0 :                 **dst = flt_nil;
    1129           0 :                 return 1;
    1130             :         }
    1131             : 
    1132     1842278 :         while (GDKisspace(*p))
    1133          65 :                 p++;
    1134     1842213 :         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     1842213 :                 char *pe;
    1145     1842213 :                 errno = 0;
    1146     1842213 :                 f = strtof(p, &pe);
    1147     1849113 :                 if (p == pe)
    1148             :                         p = src; /* nothing converted */
    1149             :                 else
    1150     1849105 :                         p = pe;
    1151     1849113 :                 n = (ssize_t) (p - src);
    1152     1849113 :                 if (n == 0 || (errno == ERANGE && (f < -1 || f > 1))
    1153     1849097 :                     || !isfinite(f) /* no NaN or infinite */) {
    1154          58 :                         GDKerror("overflow or not a number\n");
    1155          58 :                         return -1;
    1156             :                 } else {
    1157     1849094 :                         while (src[n] && GDKisspace(src[n]))
    1158          39 :                                 n++;
    1159     1849055 :                         if (f == -0)
    1160        6595 :                                 f = 0;
    1161     1849055 :                         **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         211 : atom_io(flt, Int, int)
    1197             : 
    1198             : 
    1199             : /*
    1200             :  * String conversion routines.
    1201             :  */
    1202             : ssize_t
    1203           8 : 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           8 :         lng ui = 0, *uip = &ui;
    1209             : #endif
    1210           8 :         size_t l = sizeof(ui);
    1211           8 :         ssize_t pos = 0;
    1212           8 :         const char *p = src;
    1213             : 
    1214           8 :         atommem(sizeof(oid));
    1215             : 
    1216           8 :         **dst = oid_nil;
    1217           8 :         if (strNil(src))
    1218             :                 return 1;
    1219             : 
    1220           8 :         while (GDKisspace(*p))
    1221           0 :                 p++;
    1222             : 
    1223           8 :         if (external && strncmp(p, "nil", 3) == 0)
    1224           0 :                 return (ssize_t) (p - src) + 3;
    1225             : 
    1226           8 :         if (*p >= '0' && *p <= '9') {
    1227             : #if SIZEOF_OID == SIZEOF_INT
    1228             :                 pos = intFromStr(p, &l, &uip, external);
    1229             : #else
    1230           7 :                 pos = lngFromStr(p, &l, &uip, external);
    1231             : #endif
    1232           7 :                 if (pos < 0)
    1233             :                         return pos;
    1234           7 :                 if (p[pos] == '@') {
    1235           7 :                         pos++;
    1236          14 :                         while (p[pos] >= '0' && p[pos] <= '9')
    1237           7 :                                 pos++;
    1238             :                 }
    1239           7 :                 if (ui >= 0) {
    1240           7 :                         **dst = ui;
    1241             :                 }
    1242           7 :                 p += pos;
    1243             :         } else {
    1244           1 :                 GDKerror("not an OID\n");
    1245           1 :                 return -1;
    1246             :         }
    1247           7 :         while (GDKisspace(*p))
    1248           0 :                 p++;
    1249           7 :         return (ssize_t) (p - src);
    1250             : }
    1251             : 
    1252             : ssize_t
    1253        4168 : OIDtoStr(char **dst, size_t *len, const oid *src, bool external)
    1254             : {
    1255        4168 :         atommem(oidStrlen);
    1256             : 
    1257        4168 :         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        4152 :         return snprintf(*dst, *len, OIDFMT "@0", *src);
    1266             : }
    1267             : 
    1268             : static int
    1269     4774043 : UUIDcompare(const void *L, const void *R)
    1270             : {
    1271     4774043 :         const uuid *l = L, *r = R;
    1272     4774043 :         if (is_uuid_nil(*r))
    1273      441913 :                 return !is_uuid_nil(*l);
    1274     4332130 :         if (is_uuid_nil(*l))
    1275             :                 return -1;
    1276      401032 :         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        1610 :                         u.u[i] = *s - '0';
    1311        1566 :                 else if ('a' <= *s && *s <= 'f')
    1312        1132 :                         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        1503 :                         u.u[i] |= *s - '0';
    1322        1641 :                 else if ('a' <= *s && *s <= 'f')
    1323        1271 :                         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          21 : UUIDread(void *U, size_t *dstlen, stream *s, size_t cnt)
    1351             : {
    1352          21 :         uuid *u = U;
    1353          21 :         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          21 :         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          22 : UUIDwrite(const void *u, stream *s, size_t cnt)
    1368             : {
    1369          22 :         return mnstr_write(s, u, UUID_SIZE, cnt) ? GDK_SUCCEED : GDK_FAIL;
    1370             : }
    1371             : 
    1372             : static ssize_t
    1373     1960962 : UUIDtoString(str *retval, size_t *len, const void *VALUE, bool external)
    1374             : {
    1375     1960962 :         const uuid *value = VALUE;
    1376     1960962 :         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     1960038 :         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     1960038 :         snprintf(*retval, *len,
    1394             :                          "%02x%02x%02x%02x-%02x%02x-%02x%02x"
    1395             :                          "-%02x%02x-%02x%02x%02x%02x%02x%02x",
    1396     1960038 :                          value->u[0], value->u[1], value->u[2], value->u[3],
    1397     1960038 :                          value->u[4], value->u[5], value->u[6], value->u[7],
    1398     1960038 :                          value->u[8], value->u[9], value->u[10], value->u[11],
    1399     1960038 :                          value->u[12], value->u[13], value->u[14], value->u[15]);
    1400     1960038 :         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    14806097 : blobsize(size_t nitems)
    1410             : {
    1411    14806097 :         if (nitems == ~(size_t) 0)
    1412     5334258 :                 nitems = 0;
    1413    14806097 :         assert(offsetof(blob, data) + nitems <= VAR_MAX);
    1414    14806097 :         return (size_t) (offsetof(blob, data) + nitems);
    1415             : }
    1416             : 
    1417             : static int
    1418    18404187 : BLOBcmp(const void *L, const void *R)
    1419             : {
    1420    18404187 :         const blob *l = L, *r = R;
    1421    18404187 :         int c;
    1422    18404187 :         if (is_blob_nil(r))
    1423    13346077 :                 return !is_blob_nil(l);
    1424     5058110 :         if (is_blob_nil(l))
    1425             :                 return -1;
    1426       10840 :         if (l->nitems < r->nitems) {
    1427        4570 :                 c = memcmp(l->data, r->data, l->nitems);
    1428        4570 :                 if (c == 0)
    1429        4269 :                         return -1;
    1430             :         } else {
    1431        6270 :                 c = memcmp(l->data, r->data, r->nitems);
    1432        6270 :                 if (c == 0)
    1433        5706 :                         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       12292 : BLOBhash(const void *B)
    1446             : {
    1447       12292 :         const blob *b = B;
    1448       12292 :         return (BUN) b->nitems;
    1449             : }
    1450             : 
    1451             : static void *
    1452          63 : BLOBread(void *A, size_t *dstlen, stream *s, size_t cnt)
    1453             : {
    1454          63 :         blob *a = A;
    1455          63 :         int len;
    1456             : 
    1457          63 :         (void) cnt;
    1458          63 :         assert(cnt == 1);
    1459          63 :         if (mnstr_readInt(s, &len) != 1 || len < 0)
    1460             :                 return NULL;
    1461          63 :         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          63 :         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          63 : BLOBwrite(const void *A, stream *s, size_t cnt)
    1475             : {
    1476          63 :         const blob *a = A;
    1477          63 :         size_t len = blobsize(a->nitems);
    1478             : 
    1479          63 :         (void) cnt;
    1480          63 :         assert(cnt == 1);
    1481         126 :         if (!mnstr_writeInt(s, (int) len) /* 64bit: check for overflow */ ||
    1482          63 :                 mnstr_write(s, a, len, 1) < 0)
    1483           0 :                 return GDK_FAIL;
    1484             :         return GDK_SUCCEED;
    1485             : }
    1486             : 
    1487             : static size_t
    1488        1468 : BLOBlength(const void *P)
    1489             : {
    1490        1468 :         const blob *p = P;
    1491        1468 :         size_t l = blobsize(p->nitems); /* 64bit: check for overflow */
    1492        1468 :         assert(l <= (size_t) GDK_int_max);
    1493        1468 :         return l;
    1494             : }
    1495             : 
    1496             : static gdk_return
    1497         868 : BLOBheap(Heap *heap, size_t capacity)
    1498             : {
    1499         868 :         return HEAP_initialize(heap, capacity, 0, (int) sizeof(var_t));
    1500             : }
    1501             : 
    1502             : static var_t
    1503     7401084 : BLOBput(BAT *b, var_t *bun, const void *VAL)
    1504             : {
    1505     7401084 :         const blob *val = VAL;
    1506     7401084 :         char *base = NULL;
    1507             : 
    1508     7401084 :         *bun = HEAP_malloc(b, blobsize(val->nitems));
    1509     7401084 :         base = b->tvheap->base;
    1510     7401084 :         if (*bun != (var_t) -1) {
    1511     7401084 :                 memcpy(&base[*bun], val, blobsize(val->nitems));
    1512     7401084 :                 b->tvheap->dirty = true;
    1513             :         }
    1514     7401084 :         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 :                 int val = (p->data[i] >> 4) & 15;
    1550             : 
    1551    25857199 :                 *s++ = hexit[val];
    1552    25857199 :                 val = p->data[i] & 15;
    1553    25857199 :                 *s++ = hexit[val];
    1554             :         }
    1555         397 :         *s = '\0';
    1556         397 :         return (ssize_t) (s - *tostr);
    1557             : }
    1558             : 
    1559             : static ssize_t
    1560        2393 : BLOBfromstr(const char *instr, size_t *l, void **VAL, bool external)
    1561             : {
    1562        2393 :         blob **val = (blob **) VAL;
    1563        2393 :         size_t i;
    1564        2393 :         size_t nitems;
    1565        2393 :         size_t nbytes;
    1566        2393 :         blob *result;
    1567        2393 :         const char *s = instr;
    1568             : 
    1569        4786 :         if (strNil(instr) || (external && strncmp(instr, "nil", 3) == 0)) {
    1570           0 :                 nbytes = blobsize(0);
    1571           0 :                 if (*l < nbytes || *val == NULL) {
    1572           0 :                         GDKfree(*val);
    1573           0 :                         if ((*val = GDKmalloc(nbytes)) == NULL)
    1574             :                                 return -1;
    1575             :                 }
    1576           0 :                 **val = blob_nil;
    1577           0 :                 return strNil(instr) ? 1 : 3;
    1578             :         }
    1579             : 
    1580             :         /* count hexits and check for hexits/space */
    1581    21957765 :         for (i = nitems = 0; instr[i]; i++) {
    1582    21955375 :                 if (GDKisxdigit(instr[i]))
    1583    21955372 :                         nitems++;
    1584           3 :                 else if (!GDKisspace(instr[i])) {
    1585           3 :                         GDKerror("Illegal char in blob\n");
    1586           3 :                         return -1;
    1587             :                 }
    1588             :         }
    1589        2390 :         if (nitems % 2 != 0) {
    1590           0 :                 GDKerror("Illegal blob length '%zu' (should be even)\n", nitems);
    1591           0 :                 return -1;
    1592             :         }
    1593        2390 :         nitems /= 2;
    1594        2390 :         nbytes = blobsize(nitems);
    1595             : 
    1596        2390 :         if (*l < nbytes || *val == NULL) {
    1597        2292 :                 GDKfree(*val);
    1598        2292 :                 *val = GDKmalloc(nbytes);
    1599        2292 :                 if( *val == NULL)
    1600             :                         return -1;
    1601        2292 :                 *l = nbytes;
    1602             :         }
    1603        2390 :         result = *val;
    1604        2390 :         result->nitems = nitems;
    1605             : 
    1606             :         /*
    1607             :            // Read the values of the blob.
    1608             :          */
    1609    10980076 :         for (i = 0; i < nitems; ++i) {
    1610    10977686 :                 char res = 0;
    1611             : 
    1612    10977686 :                 for (;;) {
    1613    10977686 :                         if (*s >= '0' && *s <= '9') {
    1614     5900546 :                                 res = *s - '0';
    1615     5077140 :                         } else if (*s >= 'A' && *s <= 'F') {
    1616     2651908 :                                 res = 10 + *s - 'A';
    1617     2425232 :                         } else if (*s >= 'a' && *s <= 'f') {
    1618     2425232 :                                 res = 10 + *s - 'a';
    1619             :                         } else {
    1620           0 :                                 assert(GDKisspace(*s));
    1621           0 :                                 s++;
    1622           0 :                                 continue;
    1623             :                         }
    1624    10977686 :                         break;
    1625             :                 }
    1626    10977686 :                 s++;
    1627    10977686 :                 res <<= 4;
    1628    10977686 :                 for (;;) {
    1629    10977686 :                         if (*s >= '0' && *s <= '9') {
    1630     5899417 :                                 res += *s - '0';
    1631     5078269 :                         } else if (*s >= 'A' && *s <= 'F') {
    1632     2654281 :                                 res += 10 + *s - 'A';
    1633     2423988 :                         } else if (*s >= 'a' && *s <= 'f') {
    1634     2423988 :                                 res += 10 + *s - 'a';
    1635             :                         } else {
    1636           0 :                                 assert(GDKisspace(*s));
    1637           0 :                                 s++;
    1638           0 :                                 continue;
    1639             :                         }
    1640    10977686 :                         break;
    1641             :                 }
    1642    10977686 :                 s++;
    1643             : 
    1644    10977686 :                 result->data[i] = res;
    1645             :         }
    1646        2390 :         while (GDKisspace(*s))
    1647           0 :                 s++;
    1648             : 
    1649        2390 :         return (ssize_t) (s - instr);
    1650             : }
    1651             : 
    1652             : atomDesc BATatoms[MAXATOMS] = {
    1653             :         [TYPE_void] = {
    1654             :                 .name = "void",
    1655             :                 .storage = TYPE_void,
    1656             :                 .linear = true,
    1657             : #if SIZEOF_OID == SIZEOF_INT
    1658             :                 .atomNull = (void *) &int_nil,
    1659             :                 .atomCmp = (int (*)(const void *, const void *)) intCmp,
    1660             :                 .atomHash = (BUN (*)(const void *)) intHash,
    1661             : #else
    1662             :                 .atomNull = (void *) &lng_nil,
    1663             :                 .atomCmp = (int (*)(const void *, const void *)) lngCmp,
    1664             :                 .atomHash = (BUN (*)(const void *)) lngHash,
    1665             : #endif
    1666             :                 .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) OIDfromStr,
    1667             :                 .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) OIDtoStr,
    1668             :                 .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) voidRead,
    1669             :                 .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) voidWrite,
    1670             :         },
    1671             :         [TYPE_bit] = {
    1672             :                 .name = "bit",
    1673             :                 .storage = TYPE_bte,
    1674             :                 .linear = true,
    1675             :                 .size = sizeof(bit),
    1676             :                 .atomNull = (void *) &bte_nil,
    1677             :                 .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) bitFromStr,
    1678             :                 .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) bitToStr,
    1679             :                 .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) bitRead,
    1680             :                 .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) bitWrite,
    1681             :                 .atomCmp = (int (*)(const void *, const void *)) bteCmp,
    1682             :                 .atomHash = (BUN (*)(const void *)) bteHash,
    1683             :         },
    1684             :         [TYPE_msk] = {
    1685             :                 .name = "msk",
    1686             :                 .storage = TYPE_msk,
    1687             :                 .linear = false,
    1688             :                 .size = 1,      /* really 1/8 */
    1689             :                 .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) mskFromStr,
    1690             :                 .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) mskToStr,
    1691             :                 .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) mskRead,
    1692             :                 .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) mskWrite,
    1693             :                 .atomCmp = (int (*)(const void *, const void *)) mskCmp,
    1694             :         },
    1695             :         [TYPE_bte] = {
    1696             :                 .name = "bte",
    1697             :                 .storage = TYPE_bte,
    1698             :                 .linear = true,
    1699             :                 .size = sizeof(bte),
    1700             :                 .atomNull = (void *) &bte_nil,
    1701             :                 .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) bteFromStr,
    1702             :                 .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) bteToStr,
    1703             :                 .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) bteRead,
    1704             :                 .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) bteWrite,
    1705             :                 .atomCmp = (int (*)(const void *, const void *)) bteCmp,
    1706             :                 .atomHash = (BUN (*)(const void *)) bteHash,
    1707             :         },
    1708             :         [TYPE_sht] = {
    1709             :                 .name = "sht",
    1710             :                 .storage = TYPE_sht,
    1711             :                 .linear = true,
    1712             :                 .size = sizeof(sht),
    1713             :                 .atomNull = (void *) &sht_nil,
    1714             :                 .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) shtFromStr,
    1715             :                 .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) shtToStr,
    1716             :                 .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) shtRead,
    1717             :                 .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) shtWrite,
    1718             :                 .atomCmp = (int (*)(const void *, const void *)) shtCmp,
    1719             :                 .atomHash = (BUN (*)(const void *)) shtHash,
    1720             :         },
    1721             :         [TYPE_int] = {
    1722             :                 .name = "int",
    1723             :                 .storage = TYPE_int,
    1724             :                 .linear = true,
    1725             :                 .size = sizeof(int),
    1726             :                 .atomNull = (void *) &int_nil,
    1727             :                 .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) intFromStr,
    1728             :                 .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) intToStr,
    1729             :                 .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) intRead,
    1730             :                 .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) intWrite,
    1731             :                 .atomCmp = (int (*)(const void *, const void *)) intCmp,
    1732             :                 .atomHash = (BUN (*)(const void *)) intHash,
    1733             :         },
    1734             :         [TYPE_oid] = {
    1735             :                 .name = "oid",
    1736             :                 .linear = true,
    1737             :                 .size = sizeof(oid),
    1738             : #if SIZEOF_OID == SIZEOF_INT
    1739             :                 .storage = TYPE_int,
    1740             :                 .atomNull = (void *) &int_nil,
    1741             :                 .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) intRead,
    1742             :                 .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) intWrite,
    1743             :                 .atomCmp = (int (*)(const void *, const void *)) intCmp,
    1744             :                 .atomHash = (BUN (*)(const void *)) intHash,
    1745             : #else
    1746             :                 .storage = TYPE_lng,
    1747             :                 .atomNull = (void *) &lng_nil,
    1748             :                 .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) lngRead,
    1749             :                 .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) lngWrite,
    1750             :                 .atomCmp = (int (*)(const void *, const void *)) lngCmp,
    1751             :                 .atomHash = (BUN (*)(const void *)) lngHash,
    1752             : #endif
    1753             :                 .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) OIDfromStr,
    1754             :                 .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) OIDtoStr,
    1755             :         },
    1756             :         [TYPE_ptr] = {
    1757             :                 .name = "ptr",
    1758             :                 .storage = TYPE_ptr,
    1759             :                 .linear = true,
    1760             :                 .size = sizeof(void *),
    1761             :                 .atomNull = (void *) &ptr_nil,
    1762             :                 .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) ptrFromStr,
    1763             :                 .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) ptrToStr,
    1764             :                 .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) ptrRead,
    1765             :                 .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) ptrWrite,
    1766             : #if SIZEOF_VOID_P == SIZEOF_INT
    1767             :                 .atomCmp = (int (*)(const void *, const void *)) intCmp,
    1768             :                 .atomHash = (BUN (*)(const void *)) intHash,
    1769             : #else /* SIZEOF_VOID_P == SIZEOF_LNG */
    1770             :                 .atomCmp = (int (*)(const void *, const void *)) lngCmp,
    1771             :                 .atomHash = (BUN (*)(const void *)) lngHash,
    1772             : #endif
    1773             :         },
    1774             :         [TYPE_flt] = {
    1775             :                 .name = "flt",
    1776             :                 .storage = TYPE_flt,
    1777             :                 .linear = true,
    1778             :                 .size = sizeof(flt),
    1779             :                 .atomNull = (void *) &flt_nil,
    1780             :                 .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) fltFromStr,
    1781             :                 .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) fltToStr,
    1782             :                 .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) fltRead,
    1783             :                 .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) fltWrite,
    1784             :                 .atomCmp = (int (*)(const void *, const void *)) fltCmp,
    1785             :                 .atomHash = (BUN (*)(const void *)) fltHash,
    1786             :         },
    1787             :         [TYPE_dbl] = {
    1788             :                 .name = "dbl",
    1789             :                 .storage = TYPE_dbl,
    1790             :                 .linear = true,
    1791             :                 .size = sizeof(dbl),
    1792             :                 .atomNull = (void *) &dbl_nil,
    1793             :                 .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) dblFromStr,
    1794             :                 .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) dblToStr,
    1795             :                 .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) dblRead,
    1796             :                 .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) dblWrite,
    1797             :                 .atomCmp = (int (*)(const void *, const void *)) dblCmp,
    1798             :                 .atomHash = (BUN (*)(const void *)) dblHash,
    1799             :         },
    1800             :         [TYPE_lng] = {
    1801             :                 .name = "lng",
    1802             :                 .storage = TYPE_lng,
    1803             :                 .linear = true,
    1804             :                 .size = sizeof(lng),
    1805             :                 .atomNull = (void *) &lng_nil,
    1806             :                 .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) lngFromStr,
    1807             :                 .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) lngToStr,
    1808             :                 .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) lngRead,
    1809             :                 .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) lngWrite,
    1810             :                 .atomCmp = (int (*)(const void *, const void *)) lngCmp,
    1811             :                 .atomHash = (BUN (*)(const void *)) lngHash,
    1812             :         },
    1813             : #ifdef HAVE_HGE
    1814             :         [TYPE_hge] = {
    1815             :                 .name = "hge",
    1816             :                 .storage = TYPE_hge,
    1817             :                 .linear = true,
    1818             :                 .size = sizeof(hge),
    1819             :                 .atomNull = (void *) &hge_nil,
    1820             :                 .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) hgeFromStr,
    1821             :                 .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) hgeToStr,
    1822             :                 .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) hgeRead,
    1823             :                 .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) hgeWrite,
    1824             :                 .atomCmp = (int (*)(const void *, const void *)) hgeCmp,
    1825             :                 .atomHash = (BUN (*)(const void *)) hgeHash,
    1826             :         },
    1827             : #endif
    1828             :         [TYPE_date] = {
    1829             :                 .name = "date",
    1830             :                 .storage = TYPE_int,
    1831             :                 .linear = true,
    1832             :                 .size = sizeof(int),
    1833             :                 .atomNull = (void *) &int_nil,
    1834             :                 .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) date_fromstr,
    1835             :                 .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) date_tostr,
    1836             :                 .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) intRead,
    1837             :                 .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) intWrite,
    1838             :                 .atomCmp = (int (*)(const void *, const void *)) intCmp,
    1839             :                 .atomHash = (BUN (*)(const void *)) intHash,
    1840             :         },
    1841             :         [TYPE_daytime] = {
    1842             :                 .name = "daytime",
    1843             :                 .storage = TYPE_lng,
    1844             :                 .linear = true,
    1845             :                 .size = sizeof(lng),
    1846             :                 .atomNull = (void *) &lng_nil,
    1847             :                 .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) daytime_tz_fromstr,
    1848             :                 .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) daytime_tostr,
    1849             :                 .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) lngRead,
    1850             :                 .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) lngWrite,
    1851             :                 .atomCmp = (int (*)(const void *, const void *)) lngCmp,
    1852             :                 .atomHash = (BUN (*)(const void *)) lngHash,
    1853             :         },
    1854             :         [TYPE_timestamp] = {
    1855             :                 .name = "timestamp",
    1856             :                 .storage = TYPE_lng,
    1857             :                 .linear = true,
    1858             :                 .size = sizeof(lng),
    1859             :                 .atomNull = (void *) &lng_nil,
    1860             :                 .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) timestamp_fromstr,
    1861             :                 .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) timestamp_tostr,
    1862             :                 .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) lngRead,
    1863             :                 .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) lngWrite,
    1864             :                 .atomCmp = (int (*)(const void *, const void *)) lngCmp,
    1865             :                 .atomHash = (BUN (*)(const void *)) lngHash,
    1866             :         },
    1867             :         [TYPE_uuid] = {
    1868             :                 .name = "uuid",
    1869             :                 .storage = TYPE_uuid,
    1870             :                 .linear = true,
    1871             :                 .size = sizeof(uuid),
    1872             :                 .atomNull = (void *) &uuid_nil,
    1873             :                 .atomFromStr = UUIDfromString,
    1874             :                 .atomToStr = UUIDtoString,
    1875             :                 .atomRead = UUIDread,
    1876             :                 .atomWrite = UUIDwrite,
    1877             :                 .atomCmp = UUIDcompare,
    1878             :                 .atomHash = UUIDhash,
    1879             :         },
    1880             :         [TYPE_str] = {
    1881             :                 .name = "str",
    1882             :                 .storage = TYPE_str,
    1883             :                 .linear = true,
    1884             :                 .size = sizeof(var_t),
    1885             :                 .atomNull = (void *) str_nil,
    1886             :                 .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) strFromStr,
    1887             :                 .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) strToStr,
    1888             :                 .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) strRead,
    1889             :                 .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) strWrite,
    1890             :                 .atomCmp = (int (*)(const void *, const void *)) strCmp,
    1891             :                 .atomHash = (BUN (*)(const void *)) strHash,
    1892             :                 .atomPut = strPut,
    1893             :                 .atomLen = (size_t (*)(const void *)) strLen,
    1894             :                 .atomHeap = strHeap,
    1895             :         },
    1896             :         [TYPE_blob] = {
    1897             :                 .name = "blob",
    1898             :                 .storage = TYPE_blob,
    1899             :                 .linear = true,
    1900             :                 .size = sizeof(var_t),
    1901             :                 .atomNull = (void *) &blob_nil,
    1902             :                 .atomFromStr = BLOBfromstr,
    1903             :                 .atomToStr = BLOBtostr,
    1904             :                 .atomRead = BLOBread,
    1905             :                 .atomWrite = BLOBwrite,
    1906             :                 .atomCmp = BLOBcmp,
    1907             :                 .atomHash = BLOBhash,
    1908             :                 .atomPut = BLOBput,
    1909             :                 .atomDel = BLOBdel,
    1910             :                 .atomLen = BLOBlength,
    1911             :                 .atomHeap = BLOBheap,
    1912             :         },
    1913             : };
    1914             : 
    1915             : int GDKatomcnt = TYPE_blob + 1;
    1916             : 
    1917             : /*
    1918             :  * Sometimes a bat descriptor is loaded before the dynamic module
    1919             :  * defining the atom is loaded. To support this an extra set of
    1920             :  * unknown atoms is kept.  These can be accessed via the ATOMunknown
    1921             :  * interface. Finding an (negative) atom index can be done via
    1922             :  * ATOMunknown_find, which simply adds the atom if it's not in the
    1923             :  * unknown set. The index can be used to find the name of an unknown
    1924             :  * ATOM via ATOMunknown_name.
    1925             :  */
    1926             : static str unknown[MAXATOMS] = { NULL };
    1927             : 
    1928             : int
    1929         241 : ATOMunknown_find(const char *nme)
    1930             : {
    1931         241 :         int i, j = 0;
    1932             : 
    1933             :         /* first try to find the atom */
    1934         241 :         MT_lock_set(&GDKatomLock);
    1935        7428 :         for (i = 1; i < MAXATOMS; i++) {
    1936        7133 :                 if (unknown[i]) {
    1937         338 :                         if (strcmp(unknown[i], nme) == 0) {
    1938         187 :                                 MT_lock_unset(&GDKatomLock);
    1939         187 :                                 return -i;
    1940             :                         }
    1941        6795 :                 } else if (j == 0)
    1942        6946 :                         j = i;
    1943             :         }
    1944          54 :         if (j == 0) {
    1945             :                 /* no space for new atom (shouldn't happen) */
    1946           0 :                 MT_lock_unset(&GDKatomLock);
    1947           0 :                 return 0;
    1948             :         }
    1949          54 :         if ((unknown[j] = GDKstrdup(nme)) == NULL) {
    1950           0 :                 MT_lock_unset(&GDKatomLock);
    1951           0 :                 return 0;
    1952             :         }
    1953          54 :         MT_lock_unset(&GDKatomLock);
    1954          54 :         return -j;
    1955             : }
    1956             : 
    1957             : const char *
    1958         297 : ATOMunknown_name(int i)
    1959             : {
    1960         297 :         assert(i < 0);
    1961         297 :         assert(-i < MAXATOMS);
    1962         297 :         assert(unknown[-i]);
    1963         297 :         return unknown[-i];
    1964             : }
    1965             : 
    1966             : void
    1967         330 : ATOMunknown_clean(void)
    1968             : {
    1969         330 :         int i;
    1970             : 
    1971         330 :         MT_lock_set(&GDKatomLock);
    1972         714 :         for (i = 1; i < MAXATOMS; i++) {
    1973         384 :                 if(unknown[i]) {
    1974          54 :                         GDKfree(unknown[i]);
    1975          54 :                         unknown[i] = NULL;
    1976             :                 } else {
    1977             :                         break;
    1978             :                 }
    1979             :         }
    1980         330 :         MT_lock_unset(&GDKatomLock);
    1981         330 : }

Generated by: LCOV version 1.14