LCOV - code coverage report
Current view: top level - gdk - gdk_atoms.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 592 796 74.4 %
Date: 2024-10-04 20:04:04 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         190 : mskCmp(const msk *l, const msk *r)
      43             : {
      44         190 :         return (*l > *r) - (*l < *r);
      45             : }
      46             : 
      47             : static int
      48   637343851 : bteCmp(const bte *l, const bte *r)
      49             : {
      50   637343851 :         return (*l > *r) - (*l < *r);
      51             : }
      52             : 
      53             : static int
      54    76683414 : shtCmp(const sht *l, const sht *r)
      55             : {
      56    76683414 :         return (*l > *r) - (*l < *r);
      57             : }
      58             : 
      59             : static int
      60  1601453851 : intCmp(const int *l, const int *r)
      61             : {
      62  1601453851 :         return (*l > *r) - (*l < *r);
      63             : }
      64             : 
      65             : static int
      66   411952865 : fltCmp(const flt *l, const flt *r)
      67             : {
      68   411952865 :         return is_flt_nil(*l) ? -!is_flt_nil(*r) : is_flt_nil(*r) ? 1 : (*l > *r) - (*l < *r);
      69             : }
      70             : 
      71             : static int
      72  2039402434 : lngCmp(const lng *l, const lng *r)
      73             : {
      74  2039402434 :         return (*l > *r) - (*l < *r);
      75             : }
      76             : 
      77             : #ifdef HAVE_HGE
      78             : static int
      79   209418945 : hgeCmp(const hge *l, const hge *r)
      80             : {
      81   209418945 :         return (*l > *r) - (*l < *r);
      82             : }
      83             : #endif
      84             : 
      85             : static int
      86    47040996 : dblCmp(const dbl *l, const dbl *r)
      87             : {
      88    47040996 :         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     1136742 : intHash(const int *v)
     109             : {
     110     1136742 :         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      151515 : fltHash(const flt *v)
     129             : {
     130      151515 :         if (is_flt_nil(*v))
     131             :                 return (BUN) mix_int(GDK_int_min);
     132      151386 :         if (*v == 0)
     133             :                 return (BUN) mix_int(0);
     134      147443 :         return (BUN) mix_int(*(const unsigned int *) v);
     135             : }
     136             : 
     137             : static BUN
     138       45227 : dblHash(const dbl *v)
     139             : {
     140       45227 :         if (is_dbl_nil(*v))
     141             :                 return (BUN) mix_lng(GDK_lng_min);
     142       43283 :         if (*v == 0)
     143             :                 return (BUN) mix_lng(0);
     144       33843 :         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        3928 : ATOMallocate(const char *id)
     189             : {
     190        3928 :         int t;
     191             : 
     192        3928 :         if (strlen(id) >= IDLENGTH) {
     193           0 :                 GDKerror("name too long");
     194           0 :                 return int_nil;
     195             :         }
     196             : 
     197        3928 :         MT_lock_set(&GDKatomLock);
     198        3928 :         t = ATOMindex(id);
     199        3928 :         if (t < 0) {
     200        3928 :                 t = -t;
     201        3928 :                 if (t == GDKatomcnt) {
     202        3928 :                         if (GDKatomcnt == MAXATOMS) {
     203           0 :                                 MT_lock_unset(&GDKatomLock);
     204           0 :                                 GDKerror("too many types");
     205           0 :                                 return int_nil;
     206             :                         }
     207        3928 :                         GDKatomcnt++;
     208             :                 }
     209        3928 :                 BATatoms[t] = (atomDesc) {
     210             :                         .size = sizeof(int),    /* default */
     211             :                         .linear = true,         /* default */
     212             :                         .storage = t,           /* default */
     213             :                 };
     214        3928 :                 strcpy(BATatoms[t].name, id);
     215             :         }
     216        3928 :         MT_lock_unset(&GDKatomLock);
     217        3928 :         return t;
     218             : }
     219             : 
     220             : int
     221       64661 : ATOMindex(const char *nme)
     222             : {
     223       64661 :         int t, j = GDKatomcnt;
     224             : 
     225      771587 :         for (t = 0; t < GDKatomcnt; t++) {
     226      767071 :                 if (!BATatoms[t].name[0]) {
     227           0 :                         if (j == GDKatomcnt)
     228      706926 :                                 j = t;
     229      767071 :                 } else if (strcmp(nme, BATatoms[t].name) == 0) {
     230       60145 :                         return t;
     231             :                 }
     232             : 
     233             :         }
     234        4516 :         return -j;
     235             : }
     236             : 
     237             : const char *
     238      398095 : ATOMname(int t)
     239             : {
     240      398095 :         return t >= 0 && t < GDKatomcnt && *BATatoms[t].name ? BATatoms[t].name : "null";
     241             : }
     242             : 
     243             : bool
     244      245932 : ATOMisdescendant(int tpe, int parent)
     245             : {
     246      245932 :         int cur = -1;
     247             : 
     248      499736 :         while (cur != tpe) {
     249      253804 :                 cur = tpe;
     250      253804 :                 if (cur == parent)
     251             :                         return true;
     252      253804 :                 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     7299961 : ATOMlen(int t, const void *src)
     299             : {
     300     7299961 :         size_t (*l)(const void *) = BATatoms[t].atomLen;
     301             : 
     302     7299961 :         return l ? (*l) (src) : ATOMsize(t);
     303             : }
     304             : 
     305             : gdk_return
     306      646675 : ATOMheap(int t, Heap *hp, size_t cap)
     307             : {
     308      646675 :         gdk_return (*h) (Heap *, size_t) = BATatoms[t].atomHeap;
     309             : 
     310      646675 :         if (h) {
     311      646675 :                 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         717 : ATOMprint(int t, const void *p, stream *s)
     324             : {
     325         717 :         ssize_t (*tostr) (char **, size_t *, const void *, bool);
     326         717 :         ssize_t res;
     327             : 
     328        1434 :         if (p && t >= 0 && t < GDKatomcnt && (tostr = BATatoms[t].atomToStr)) {
     329         717 :                 size_t sz;
     330             : 
     331         717 :                 if (t < TYPE_date) {
     332         247 :                         char buf[dblStrlen], *addr = buf;       /* use memory from stack */
     333             : 
     334         247 :                         sz = dblStrlen;
     335         247 :                         res = (*tostr) (&addr, &sz, p, true);
     336         247 :                         if (res > 0)
     337         247 :                                 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         717 :         if (res < 0)
     351           0 :                 GDKsyserror("ATOMprint: write failure\n");
     352         717 :         return (int) res;
     353             : }
     354             : 
     355             : 
     356             : char *
     357       23854 : ATOMformat(int t, const void *p)
     358             : {
     359       23854 :         ssize_t (*tostr) (char **, size_t *, const void *, bool);
     360             : 
     361       23854 :         if (p && 0 <= t && t < GDKatomcnt && (tostr = BATatoms[t].atomToStr)) {
     362       23854 :                 size_t sz = 0;
     363       23854 :                 char *buf = NULL;
     364       23854 :                 ssize_t res = (*tostr) (&buf, &sz, p, true);
     365       23852 :                 if (res < 0 && buf) {
     366           0 :                         GDKfree(buf);
     367           0 :                         buf = NULL;
     368             :                 }
     369       23852 :                 return buf;
     370             :         }
     371           0 :         return GDKstrdup("nil");
     372             : }
     373             : 
     374             : ptr
     375       56296 : ATOMdup(int t, const void *p)
     376             : {
     377       56296 :         size_t len = ATOMlen(t, p);
     378       56296 :         ptr n = GDKmalloc(len);
     379             : 
     380       56296 :         if (n)
     381       56296 :                 memcpy(n, p, len);
     382       56296 :         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       70646 : bitToStr(char **dst, size_t *len, const bit *src, bool external)
     534             : {
     535       70646 :         atommem(6);
     536             : 
     537       70646 :         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       70621 :         if (*src) {
     546       25063 :                 strcpy(*dst, "true");
     547       25063 :                 return 4;
     548             :         }
     549       45558 :         strcpy(*dst, "false");
     550       45558 :         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   249437566 : numFromStr(const char *src, size_t *len, void **dst, int tp, bool external)
     700             : {
     701   249437566 :         const char *p = src;
     702   249437566 :         size_t sz = ATOMsize(tp);
     703             : #ifdef HAVE_HGE
     704   249437566 :         hge base = 0;
     705             : #else
     706             :         lng base = 0;
     707             : #endif
     708   249437566 :         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   249437566 :         atommem(sz);
     719             : 
     720   249437566 :         if (strNil(src)) {
     721           0 :                 memcpy(*dst, ATOMnilptr(tp), sz);
     722           0 :                 return 1;
     723             :         }
     724             : 
     725   249437664 :         while (GDKisspace(*p))
     726          98 :                 p++;
     727   249437566 :         if (!GDKisdigit(*p)) {
     728       11590 :                 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       11512 :                 case '-':
     740       11512 :                         sign = -1;
     741       11512 :                         p++;
     742       11512 :                         break;
     743           1 :                 case '+':
     744           1 :                         p++;
     745           1 :                         break;
     746             :                 }
     747       11585 :                 if (!GDKisdigit(*p)) {
     748          78 :                         GDKerror("not a number");
     749          78 :                         goto bailout;
     750             :                 }
     751             :         }
     752   664756581 :         do {
     753   664756581 :                 int dig = base10(*p);
     754   664756581 :                 if (base > maxdiv[1].maxval ||
     755           1 :                     (base == maxdiv[1].maxval && dig > maxmod10)) {
     756             :                         /* overflow */
     757           0 :                         goto overflow;
     758             :                 }
     759   664756581 :                 base = 10 * base + dig;
     760   664756581 :                 p++;
     761   664756581 :         } while (GDKisdigit(*p));
     762   249437483 :         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   249437483 :         base *= sign;
     788   249437483 :         switch (sz) {
     789       54185 :         case 1: {
     790       54185 :                 bte **dstbte = (bte **) dst;
     791       54185 :                 if (base < GDK_bte_min || base > GDK_bte_max) {
     792           0 :                         goto overflow;
     793             :                 }
     794       54185 :                 **dstbte = (bte) base;
     795       54185 :                 break;
     796             :         }
     797      394698 :         case 2: {
     798      394698 :                 sht **dstsht = (sht **) dst;
     799      394698 :                 if (base < GDK_sht_min || base > GDK_sht_max) {
     800           3 :                         goto overflow;
     801             :                 }
     802      394695 :                 **dstsht = (sht) base;
     803      394695 :                 break;
     804             :         }
     805   245370009 :         case 4: {
     806   245370009 :                 int **dstint = (int **) dst;
     807   245370009 :                 if (base < GDK_int_min || base > GDK_int_max) {
     808           2 :                         goto overflow;
     809             :                 }
     810   245370007 :                 **dstint = (int) base;
     811   245370007 :                 break;
     812             :         }
     813     1912505 :         case 8: {
     814     1912505 :                 lng **dstlng = (lng **) dst;
     815             : #ifdef HAVE_HGE
     816     1912505 :                 if (base < GDK_lng_min || base > GDK_lng_max) {
     817           4 :                         goto overflow;
     818             :                 }
     819             : #endif
     820     1912501 :                 **dstlng = (lng) base;
     821     1912501 :                 if (p[0] == 'L' && p[1] == 'L')
     822           0 :                         p += 2;
     823             :                 break;
     824             :         }
     825             : #ifdef HAVE_HGE
     826     1706086 :         case 16: {
     827     1706086 :                 hge **dsthge = (hge **) dst;
     828     1706086 :                 **dsthge = (hge) base;
     829     1706086 :                 if (p[0] == 'L' && p[1] == 'L')
     830           0 :                         p += 2;
     831             :                 break;
     832             :         }
     833             : #endif
     834             :         }
     835   249437574 :         while (GDKisspace(*p))
     836         100 :                 p++;
     837   249437474 :         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          92 :   bailout:
     845          92 :         memcpy(*dst, ATOMnilptr(tp), sz);
     846          92 :         return -1;
     847             : }
     848             : 
     849             : ssize_t
     850       54196 : bteFromStr(const char *src, size_t *len, bte **dst, bool external)
     851             : {
     852       54196 :         return numFromStr(src, len, (void **) dst, TYPE_bte, external);
     853             : }
     854             : 
     855             : ssize_t
     856      394788 : shtFromStr(const char *src, size_t *len, sht **dst, bool external)
     857             : {
     858      394788 :         return numFromStr(src, len, (void **) dst, TYPE_sht, external);
     859             : }
     860             : 
     861             : ssize_t
     862   246576545 : intFromStr(const char *src, size_t *len, int **dst, bool external)
     863             : {
     864   246576545 :         return numFromStr(src, len, (void **) dst, TYPE_int, external);
     865             : }
     866             : 
     867             : ssize_t
     868     1912509 : lngFromStr(const char *src, size_t *len, lng **dst, bool external)
     869             : {
     870     1912509 :         return numFromStr(src, len, (void **) dst, TYPE_lng, external);
     871             : }
     872             : 
     873             : #ifdef HAVE_HGE
     874             : ssize_t
     875     1705810 : hgeFromStr(const char *src, size_t *len, hge **dst, bool external)
     876             : {
     877     1705810 :         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      125293 : mskWrite(const msk *a, stream *s, size_t cnt)
     908             : {
     909      125293 :         if (cnt == 0)
     910             :                 return GDK_SUCCEED;
     911      125293 :         if (cnt == 1)
     912      125293 :                 return mnstr_writeBte(s, (int8_t) *a) ? GDK_SUCCEED : GDK_FAIL;
     913             :         return GDK_FAIL;
     914             : }
     915             : 
     916             : static void *
     917      122782 : mskRead(msk *A, size_t *dstlen, stream *s, size_t cnt)
     918             : {
     919      122782 :         int8_t v;
     920      122782 :         msk *a = A;
     921      122782 :         if (cnt != 1)
     922             :                 return NULL;
     923      122782 :         if (a == NULL || *dstlen == 0) {
     924           0 :                 if ((a = GDKrealloc(a, 1)) == NULL)
     925             :                         return NULL;
     926           0 :                 *dstlen = 1;
     927             :         }
     928      122782 :         if (mnstr_readBte(s, &v) != 1) {
     929           0 :                 if (a != A)
     930           0 :                         GDKfree(a);
     931           0 :                 return NULL;
     932             :         }
     933      122782 :         *a = v != 0;
     934      122782 :         return a;
     935             : }
     936             : 
     937        7209 : atom_io(bit, Bte, bte)
     938             : 
     939       43033 : atomtostr(bte, "%hhd", )
     940      254020 : atom_io(bte, Bte, bte)
     941             : 
     942     1072916 : atomtostr(sht, "%hd", )
     943        8327 : atom_io(sht, Sht, sht)
     944             : 
     945    15592938 : atomtostr(int, "%d", )
     946      221706 : atom_io(int, Int, int)
     947             : 
     948      163665 : atomtostr(lng, LLFMT, )
     949       18757 : 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      331129 : dblFromStr(const char *src, size_t *len, dbl **dst, bool external)
    1039             : {
    1040      331129 :         const char *p = src;
    1041      331129 :         ssize_t n = 0;
    1042      331129 :         double d;
    1043             : 
    1044             :         /* alloc memory */
    1045      331129 :         atommem(sizeof(dbl));
    1046             : 
    1047      331129 :         if (strNil(src)) {
    1048           0 :                 **dst = dbl_nil;
    1049           0 :                 return 1;
    1050             :         }
    1051             : 
    1052      331248 :         while (GDKisspace(*p))
    1053         119 :                 p++;
    1054      331129 :         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      331129 :                 char *pe;
    1065      331129 :                 errno = 0;
    1066      331129 :                 d = strtod(p, &pe);
    1067      333108 :                 if (p == pe)
    1068             :                         p = src; /* nothing converted */
    1069             :                 else
    1070      333074 :                         p = pe;
    1071      333108 :                 n = (ssize_t) (p - src);
    1072      333108 :                 if (n == 0 || (errno == ERANGE && (d < -1 || d > 1))
    1073      333066 :                     || !isfinite(d) /* no NaN or Infinite */
    1074             :                     ) {
    1075         104 :                         GDKerror("overflow or not a number\n");
    1076         104 :                         return -1;
    1077             :                 } else {
    1078      333044 :                         while (src[n] && GDKisspace(src[n]))
    1079          40 :                                 n++;
    1080      333004 :                         **dst = (dbl) d;
    1081             :                 }
    1082             :         }
    1083             :         return n;
    1084             : }
    1085             : 
    1086             : ssize_t
    1087       13956 : dblToStr(char **dst, size_t *len, const dbl *src, bool external)
    1088             : {
    1089       13956 :         int i;
    1090             : 
    1091       13956 :         atommem(dblStrlen);
    1092       13956 :         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       50368 :         for (i = 4; i < 18; i++) {
    1101       50367 :                 snprintf(*dst, *len, "%.*g", i, *src);
    1102       50367 :                 if (strtod(*dst, NULL) == *src)
    1103             :                         break;
    1104             :         }
    1105       13952 :         return (ssize_t) strlen(*dst);
    1106             : }
    1107             : 
    1108         763 : atom_io(dbl, Lng, lng)
    1109             : 
    1110             : ssize_t
    1111     1842972 : fltFromStr(const char *src, size_t *len, flt **dst, bool external)
    1112             : {
    1113     1842972 :         const char *p = src;
    1114     1842972 :         ssize_t n = 0;
    1115     1842972 :         float f;
    1116             : 
    1117             :         /* alloc memory */
    1118     1842972 :         atommem(sizeof(flt));
    1119             : 
    1120     1842972 :         if (strNil(src)) {
    1121           0 :                 **dst = flt_nil;
    1122           0 :                 return 1;
    1123             :         }
    1124             : 
    1125     1843037 :         while (GDKisspace(*p))
    1126          65 :                 p++;
    1127     1842972 :         if (external && strncmp(p, "nil", 3) == 0) {
    1128           0 :                 **dst = flt_nil;
    1129           0 :                 p += 3;
    1130           0 :                 n = (ssize_t) (p - src);
    1131             :         } else {
    1132             :                 /* on overflow, strtof returns HUGE_VALF and sets
    1133             :                  * errno to ERANGE; on underflow, it returns a value
    1134             :                  * whose magnitude is no greater than the smallest
    1135             :                  * normalized float, and may or may not set errno to
    1136             :                  * ERANGE.  We accept underflow, but not overflow. */
    1137     1842972 :                 char *pe;
    1138     1842972 :                 errno = 0;
    1139     1842972 :                 f = strtof(p, &pe);
    1140     1849161 :                 if (p == pe)
    1141             :                         p = src; /* nothing converted */
    1142             :                 else
    1143     1849153 :                         p = pe;
    1144     1849161 :                 n = (ssize_t) (p - src);
    1145     1849161 :                 if (n == 0 || (errno == ERANGE && (f < -1 || f > 1))
    1146     1849145 :                     || !isfinite(f) /* no NaN or infinite */) {
    1147          58 :                         GDKerror("overflow or not a number\n");
    1148          58 :                         return -1;
    1149             :                 } else {
    1150     1849142 :                         while (src[n] && GDKisspace(src[n]))
    1151          39 :                                 n++;
    1152     1849103 :                         if (f == -0)
    1153        6586 :                                 f = 0;
    1154     1849103 :                         **dst = (flt) f;
    1155             :                 }
    1156             :         }
    1157             :         return n;
    1158             : }
    1159             : 
    1160             : ssize_t
    1161        1864 : fltToStr(char **dst, size_t *len, const flt *src, bool external)
    1162             : {
    1163        1864 :         int i;
    1164             : 
    1165        1864 :         atommem(fltStrlen);
    1166        1864 :         if (is_flt_nil(*src)) {
    1167           5 :                 if (external) {
    1168           5 :                         strcpy(*dst, "nil");
    1169           5 :                         return 3;
    1170             :                 }
    1171           0 :                 strcpy(*dst, str_nil);
    1172           0 :                 return 1;
    1173             :         }
    1174        3333 :         for (i = 4; i < 10; i++) {
    1175        3333 :                 snprintf(*dst, *len, "%.*g", i, *src);
    1176        3333 :                 if (strtof(*dst, NULL) == *src)
    1177             :                         break;
    1178             :         }
    1179        1859 :         return (ssize_t) strlen(*dst);
    1180             : }
    1181             : 
    1182         211 : atom_io(flt, Int, int)
    1183             : 
    1184             : 
    1185             : /*
    1186             :  * String conversion routines.
    1187             :  */
    1188             : ssize_t
    1189           8 : OIDfromStr(const char *src, size_t *len, oid **dst, bool external)
    1190             : {
    1191             : #if SIZEOF_OID == SIZEOF_INT
    1192             :         int ui = 0, *uip = &ui;
    1193             : #else
    1194           8 :         lng ui = 0, *uip = &ui;
    1195             : #endif
    1196           8 :         size_t l = sizeof(ui);
    1197           8 :         ssize_t pos = 0;
    1198           8 :         const char *p = src;
    1199             : 
    1200           8 :         atommem(sizeof(oid));
    1201             : 
    1202           8 :         **dst = oid_nil;
    1203           8 :         if (strNil(src))
    1204             :                 return 1;
    1205             : 
    1206           8 :         while (GDKisspace(*p))
    1207           0 :                 p++;
    1208             : 
    1209           8 :         if (external && strncmp(p, "nil", 3) == 0)
    1210           0 :                 return (ssize_t) (p - src) + 3;
    1211             : 
    1212           8 :         if (*p >= '0' && *p <= '9') {
    1213             : #if SIZEOF_OID == SIZEOF_INT
    1214             :                 pos = intFromStr(p, &l, &uip, external);
    1215             : #else
    1216           7 :                 pos = lngFromStr(p, &l, &uip, external);
    1217             : #endif
    1218           7 :                 if (pos < 0)
    1219             :                         return pos;
    1220           7 :                 if (p[pos] == '@') {
    1221           7 :                         pos++;
    1222          14 :                         while (p[pos] >= '0' && p[pos] <= '9')
    1223           7 :                                 pos++;
    1224             :                 }
    1225           7 :                 if (ui >= 0) {
    1226           7 :                         **dst = ui;
    1227             :                 }
    1228           7 :                 p += pos;
    1229             :         } else {
    1230           1 :                 GDKerror("not an OID\n");
    1231           1 :                 return -1;
    1232             :         }
    1233           7 :         while (GDKisspace(*p))
    1234           0 :                 p++;
    1235           7 :         return (ssize_t) (p - src);
    1236             : }
    1237             : 
    1238             : ssize_t
    1239        4168 : OIDtoStr(char **dst, size_t *len, const oid *src, bool external)
    1240             : {
    1241        4168 :         atommem(oidStrlen);
    1242             : 
    1243        4168 :         if (is_oid_nil(*src)) {
    1244          16 :                 if (external) {
    1245          16 :                         strcpy(*dst, "nil");
    1246          16 :                         return 3;
    1247             :                 }
    1248           0 :                 strcpy(*dst, str_nil);
    1249           0 :                 return 1;
    1250             :         }
    1251        4152 :         return snprintf(*dst, *len, OIDFMT "@0", *src);
    1252             : }
    1253             : 
    1254             : static int
    1255     4784847 : UUIDcompare(const void *L, const void *R)
    1256             : {
    1257     4784847 :         const uuid *l = L, *r = R;
    1258     4784847 :         if (is_uuid_nil(*r))
    1259      441849 :                 return !is_uuid_nil(*l);
    1260     4342998 :         if (is_uuid_nil(*l))
    1261             :                 return -1;
    1262      401032 :         return memcmp(l->u, r->u, UUID_SIZE);
    1263             : }
    1264             : 
    1265             : static ssize_t
    1266         278 : UUIDfromString(const char *svalue, size_t *len, void **RETVAL, bool external)
    1267             : {
    1268         278 :         uuid **retval = (uuid **) RETVAL;
    1269         278 :         const char *s = svalue;
    1270             : 
    1271         278 :         if (*len < UUID_SIZE || *retval == NULL) {
    1272          54 :                 GDKfree(*retval);
    1273          54 :                 if ((*retval = GDKmalloc(UUID_SIZE)) == NULL)
    1274             :                         return -1;
    1275          54 :                 *len = UUID_SIZE;
    1276             :         }
    1277         278 :         if (external && strcmp(svalue, "nil") == 0) {
    1278           0 :                 **retval = uuid_nil;
    1279           0 :                 return 3;
    1280             :         }
    1281         278 :         if (strNil(svalue)) {
    1282          33 :                 **retval = uuid_nil;
    1283          33 :                 return 1;
    1284             :         }
    1285         247 :         while (GDKisspace(*s))
    1286           2 :                 s++;
    1287             :         /* we don't use uuid_parse since we accept UUIDs without hyphens */
    1288             :         uuid u;
    1289        3371 :         for (int i = 0, j = 0; i < UUID_SIZE; i++) {
    1290             :                 /* on select locations we allow a '-' in the source string */
    1291        3176 :                 if (j == 8 || j == 12 || j == 16 || j == 20) {
    1292         781 :                         if (*s == '-')
    1293         728 :                                 s++;
    1294             :                 }
    1295        3176 :                 if (*s >= '0' && *s <= '9')
    1296        1607 :                         u.u[i] = *s - '0';
    1297        1569 :                 else if ('a' <= *s && *s <= 'f')
    1298        1135 :                         u.u[i] = *s - 'a' + 10;
    1299         434 :                 else if ('A' <= *s && *s <= 'F')
    1300         402 :                         u.u[i] = *s - 'A' + 10;
    1301             :                 else
    1302          32 :                         goto bailout;
    1303        3144 :                 s++;
    1304        3144 :                 j++;
    1305        3144 :                 u.u[i] <<= 4;
    1306        3144 :                 if (*s >= '0' && *s <= '9')
    1307        1507 :                         u.u[i] |= *s - '0';
    1308        1637 :                 else if ('a' <= *s && *s <= 'f')
    1309        1267 :                         u.u[i] |= *s - 'a' + 10;
    1310         370 :                 else if ('A' <= *s && *s <= 'F')
    1311         352 :                         u.u[i] |= *s - 'A' + 10;
    1312             :                 else
    1313          18 :                         goto bailout;
    1314        3126 :                 s++;
    1315        3126 :                 j++;
    1316             :         }
    1317         201 :         while (GDKisspace(*s))
    1318           6 :                 s++;
    1319         195 :         if (*s != 0)
    1320          12 :                 goto bailout;
    1321         183 :         **retval = u;
    1322         183 :         return (ssize_t) (s - svalue);
    1323             : 
    1324          62 :   bailout:
    1325          62 :         **retval = uuid_nil;
    1326          62 :         return -1;
    1327             : }
    1328             : 
    1329             : static BUN
    1330           0 : UUIDhash(const void *v)
    1331             : {
    1332           0 :         return mix_uuid((const uuid *) v);
    1333             : }
    1334             : 
    1335             : static void *
    1336          21 : UUIDread(void *U, size_t *dstlen, stream *s, size_t cnt)
    1337             : {
    1338          21 :         uuid *u = U;
    1339          21 :         if (u == NULL || *dstlen < cnt * sizeof(uuid)) {
    1340           0 :                 if ((u = GDKrealloc(u, cnt * sizeof(uuid))) == NULL)
    1341             :                         return NULL;
    1342           0 :                 *dstlen = cnt * sizeof(uuid);
    1343             :         }
    1344          21 :         if (mnstr_read(s, u, UUID_SIZE, cnt) < (ssize_t) cnt) {
    1345           0 :                 if (u != U)
    1346           0 :                         GDKfree(u);
    1347           0 :                 return NULL;
    1348             :         }
    1349             :         return u;
    1350             : }
    1351             : 
    1352             : static gdk_return
    1353          22 : UUIDwrite(const void *u, stream *s, size_t cnt)
    1354             : {
    1355          22 :         return mnstr_write(s, u, UUID_SIZE, cnt) ? GDK_SUCCEED : GDK_FAIL;
    1356             : }
    1357             : 
    1358             : static ssize_t
    1359     1966939 : UUIDtoString(str *retval, size_t *len, const void *VALUE, bool external)
    1360             : {
    1361     1966939 :         const uuid *value = VALUE;
    1362     1966939 :         if (*len <= UUID_STRLEN || *retval == NULL) {
    1363         105 :                 if (*retval)
    1364           0 :                         GDKfree(*retval);
    1365         105 :                 if ((*retval = GDKmalloc(UUID_STRLEN + 1)) == NULL)
    1366             :                         return -1;
    1367           0 :                 *len = UUID_STRLEN + 1;
    1368             :         }
    1369     1966565 :         if (is_uuid_nil(*value)) {
    1370           0 :                 if (external) {
    1371           0 :                         assert(*len >= strlen("nil") + 1);
    1372           0 :                         strcpy(*retval, "nil");
    1373           0 :                         return 3;
    1374             :                 }
    1375           0 :                 assert(*len >= strlen(str_nil) + 1);
    1376           0 :                 strcpy(*retval, str_nil);
    1377           0 :                 return 1;
    1378             :         }
    1379     1966565 :         snprintf(*retval, *len,
    1380             :                          "%02x%02x%02x%02x-%02x%02x-%02x%02x"
    1381             :                          "-%02x%02x-%02x%02x%02x%02x%02x%02x",
    1382     1966565 :                          value->u[0], value->u[1], value->u[2], value->u[3],
    1383     1966565 :                          value->u[4], value->u[5], value->u[6], value->u[7],
    1384     1966565 :                          value->u[8], value->u[9], value->u[10], value->u[11],
    1385     1966565 :                          value->u[12], value->u[13], value->u[14], value->u[15]);
    1386     1966565 :         assert(strlen(*retval) == UUID_STRLEN);
    1387             :         return UUID_STRLEN;
    1388             : }
    1389             : 
    1390             : static const blob blob_nil = {
    1391             :         ~(size_t) 0
    1392             : };
    1393             : 
    1394             : size_t
    1395    14806100 : blobsize(size_t nitems)
    1396             : {
    1397    14806100 :         if (nitems == ~(size_t) 0)
    1398     5334261 :                 nitems = 0;
    1399    14806100 :         assert(offsetof(blob, data) + nitems <= VAR_MAX);
    1400    14806100 :         return (size_t) (offsetof(blob, data) + nitems);
    1401             : }
    1402             : 
    1403             : static int
    1404    16852231 : BLOBcmp(const void *L, const void *R)
    1405             : {
    1406    16852231 :         const blob *l = L, *r = R;
    1407    16852231 :         int c;
    1408    16852231 :         if (is_blob_nil(r))
    1409    12647631 :                 return !is_blob_nil(l);
    1410     4204600 :         if (is_blob_nil(l))
    1411             :                 return -1;
    1412        6697 :         if (l->nitems < r->nitems) {
    1413        2571 :                 c = memcmp(l->data, r->data, l->nitems);
    1414        2571 :                 if (c == 0)
    1415        2272 :                         return -1;
    1416             :         } else {
    1417        4126 :                 c = memcmp(l->data, r->data, r->nitems);
    1418        4126 :                 if (c == 0)
    1419        3573 :                         return l->nitems > r->nitems;
    1420             :         }
    1421             :         return c;
    1422             : }
    1423             : 
    1424             : static void
    1425          35 : BLOBdel(Heap *h, var_t *idx)
    1426             : {
    1427          35 :         HEAP_free(h, *idx);
    1428          35 : }
    1429             : 
    1430             : static BUN
    1431       11280 : BLOBhash(const void *B)
    1432             : {
    1433       11280 :         const blob *b = B;
    1434       11280 :         return (BUN) b->nitems;
    1435             : }
    1436             : 
    1437             : static void *
    1438          63 : BLOBread(void *A, size_t *dstlen, stream *s, size_t cnt)
    1439             : {
    1440          63 :         blob *a = A;
    1441          63 :         int len;
    1442             : 
    1443          63 :         (void) cnt;
    1444          63 :         assert(cnt == 1);
    1445          63 :         if (mnstr_readInt(s, &len) != 1 || len < 0)
    1446             :                 return NULL;
    1447          63 :         if (a == NULL || *dstlen < (size_t) len) {
    1448           0 :                 if ((a = GDKrealloc(a, (size_t) len)) == NULL)
    1449             :                         return NULL;
    1450           0 :                 *dstlen = (size_t) len;
    1451             :         }
    1452          63 :         if (mnstr_read(s, (char *) a, (size_t) len, 1) != 1) {
    1453           0 :                 GDKfree(a);
    1454           0 :                 return NULL;
    1455             :         }
    1456             :         return a;
    1457             : }
    1458             : 
    1459             : static gdk_return
    1460          63 : BLOBwrite(const void *A, stream *s, size_t cnt)
    1461             : {
    1462          63 :         const blob *a = A;
    1463          63 :         size_t len = blobsize(a->nitems);
    1464             : 
    1465          63 :         (void) cnt;
    1466          63 :         assert(cnt == 1);
    1467         126 :         if (!mnstr_writeInt(s, (int) len) /* 64bit: check for overflow */ ||
    1468          63 :                 mnstr_write(s, a, len, 1) < 0)
    1469           0 :                 return GDK_FAIL;
    1470             :         return GDK_SUCCEED;
    1471             : }
    1472             : 
    1473             : static size_t
    1474        1471 : BLOBlength(const void *P)
    1475             : {
    1476        1471 :         const blob *p = P;
    1477        1471 :         size_t l = blobsize(p->nitems); /* 64bit: check for overflow */
    1478        1471 :         assert(l <= (size_t) GDK_int_max);
    1479        1471 :         return l;
    1480             : }
    1481             : 
    1482             : static gdk_return
    1483         866 : BLOBheap(Heap *heap, size_t capacity)
    1484             : {
    1485         866 :         return HEAP_initialize(heap, capacity, 0, (int) sizeof(var_t));
    1486             : }
    1487             : 
    1488             : static var_t
    1489     7401084 : BLOBput(BAT *b, var_t *bun, const void *VAL)
    1490             : {
    1491     7401084 :         const blob *val = VAL;
    1492     7401084 :         char *base = NULL;
    1493             : 
    1494     7401084 :         *bun = HEAP_malloc(b, blobsize(val->nitems));
    1495     7401084 :         base = b->tvheap->base;
    1496     7401084 :         if (*bun != (var_t) -1) {
    1497     7401084 :                 memcpy(&base[*bun], val, blobsize(val->nitems));
    1498     7401084 :                 b->tvheap->dirty = true;
    1499             :         }
    1500     7401084 :         return *bun;
    1501             : }
    1502             : 
    1503             : static ssize_t
    1504         400 : BLOBtostr(str *tostr, size_t *l, const void *P, bool external)
    1505             : {
    1506         400 :         static const char hexit[] = "0123456789ABCDEF";
    1507         400 :         const blob *p = P;
    1508         400 :         char *s;
    1509         400 :         size_t i;
    1510         400 :         size_t expectedlen;
    1511             : 
    1512         400 :         if (is_blob_nil(p))
    1513           3 :                 expectedlen = external ? 4 : 2;
    1514             :         else
    1515         397 :                 expectedlen = p->nitems * 2 + 1;
    1516         400 :         if (*l < expectedlen || *tostr == NULL) {
    1517          55 :                 GDKfree(*tostr);
    1518          55 :                 *tostr = GDKmalloc(expectedlen);
    1519          55 :                 if (*tostr == NULL)
    1520             :                         return -1;
    1521          55 :                 *l = expectedlen;
    1522             :         }
    1523         400 :         if (is_blob_nil(p)) {
    1524           3 :                 if (external) {
    1525           3 :                         strcpy(*tostr, "nil");
    1526           3 :                         return 3;
    1527             :                 }
    1528           0 :                 strcpy(*tostr, str_nil);
    1529           0 :                 return 1;
    1530             :         }
    1531             : 
    1532         397 :         s = *tostr;
    1533             : 
    1534    25857596 :         for (i = 0; i < p->nitems; i++) {
    1535    25857199 :                 int val = (p->data[i] >> 4) & 15;
    1536             : 
    1537    25857199 :                 *s++ = hexit[val];
    1538    25857199 :                 val = p->data[i] & 15;
    1539    25857199 :                 *s++ = hexit[val];
    1540             :         }
    1541         397 :         *s = '\0';
    1542         397 :         return (ssize_t) (s - *tostr);
    1543             : }
    1544             : 
    1545             : static ssize_t
    1546        2393 : BLOBfromstr(const char *instr, size_t *l, void **VAL, bool external)
    1547             : {
    1548        2393 :         blob **val = (blob **) VAL;
    1549        2393 :         size_t i;
    1550        2393 :         size_t nitems;
    1551        2393 :         size_t nbytes;
    1552        2393 :         blob *result;
    1553        2393 :         const char *s = instr;
    1554             : 
    1555        4786 :         if (strNil(instr) || (external && strncmp(instr, "nil", 3) == 0)) {
    1556           0 :                 nbytes = blobsize(0);
    1557           0 :                 if (*l < nbytes || *val == NULL) {
    1558           0 :                         GDKfree(*val);
    1559           0 :                         if ((*val = GDKmalloc(nbytes)) == NULL)
    1560             :                                 return -1;
    1561             :                 }
    1562           0 :                 **val = blob_nil;
    1563           0 :                 return strNil(instr) ? 1 : 3;
    1564             :         }
    1565             : 
    1566             :         /* count hexits and check for hexits/space */
    1567    21957765 :         for (i = nitems = 0; instr[i]; i++) {
    1568    21955375 :                 if (GDKisxdigit(instr[i]))
    1569    21955372 :                         nitems++;
    1570           3 :                 else if (!GDKisspace(instr[i])) {
    1571           3 :                         GDKerror("Illegal char in blob\n");
    1572           3 :                         return -1;
    1573             :                 }
    1574             :         }
    1575        2390 :         if (nitems % 2 != 0) {
    1576           0 :                 GDKerror("Illegal blob length '%zu' (should be even)\n", nitems);
    1577           0 :                 return -1;
    1578             :         }
    1579        2390 :         nitems /= 2;
    1580        2390 :         nbytes = blobsize(nitems);
    1581             : 
    1582        2390 :         if (*l < nbytes || *val == NULL) {
    1583        2292 :                 GDKfree(*val);
    1584        2292 :                 *val = GDKmalloc(nbytes);
    1585        2292 :                 if( *val == NULL)
    1586             :                         return -1;
    1587        2292 :                 *l = nbytes;
    1588             :         }
    1589        2390 :         result = *val;
    1590        2390 :         result->nitems = nitems;
    1591             : 
    1592             :         /*
    1593             :            // Read the values of the blob.
    1594             :          */
    1595    10980076 :         for (i = 0; i < nitems; ++i) {
    1596    10977686 :                 char res = 0;
    1597             : 
    1598    10977686 :                 for (;;) {
    1599    10977686 :                         if (*s >= '0' && *s <= '9') {
    1600     5900546 :                                 res = *s - '0';
    1601     5077140 :                         } else if (*s >= 'A' && *s <= 'F') {
    1602     2651908 :                                 res = 10 + *s - 'A';
    1603     2425232 :                         } else if (*s >= 'a' && *s <= 'f') {
    1604     2425232 :                                 res = 10 + *s - 'a';
    1605             :                         } else {
    1606           0 :                                 assert(GDKisspace(*s));
    1607           0 :                                 s++;
    1608           0 :                                 continue;
    1609             :                         }
    1610    10977686 :                         break;
    1611             :                 }
    1612    10977686 :                 s++;
    1613    10977686 :                 res <<= 4;
    1614    10977686 :                 for (;;) {
    1615    10977686 :                         if (*s >= '0' && *s <= '9') {
    1616     5899417 :                                 res += *s - '0';
    1617     5078269 :                         } else if (*s >= 'A' && *s <= 'F') {
    1618     2654281 :                                 res += 10 + *s - 'A';
    1619     2423988 :                         } else if (*s >= 'a' && *s <= 'f') {
    1620     2423988 :                                 res += 10 + *s - 'a';
    1621             :                         } else {
    1622           0 :                                 assert(GDKisspace(*s));
    1623           0 :                                 s++;
    1624           0 :                                 continue;
    1625             :                         }
    1626    10977686 :                         break;
    1627             :                 }
    1628    10977686 :                 s++;
    1629             : 
    1630    10977686 :                 result->data[i] = res;
    1631             :         }
    1632        2390 :         while (GDKisspace(*s))
    1633           0 :                 s++;
    1634             : 
    1635        2390 :         return (ssize_t) (s - instr);
    1636             : }
    1637             : 
    1638             : atomDesc BATatoms[MAXATOMS] = {
    1639             :         [TYPE_void] = {
    1640             :                 .name = "void",
    1641             :                 .storage = TYPE_void,
    1642             :                 .linear = true,
    1643             : #if SIZEOF_OID == SIZEOF_INT
    1644             :                 .atomNull = (void *) &int_nil,
    1645             :                 .atomCmp = (int (*)(const void *, const void *)) intCmp,
    1646             :                 .atomHash = (BUN (*)(const void *)) intHash,
    1647             : #else
    1648             :                 .atomNull = (void *) &lng_nil,
    1649             :                 .atomCmp = (int (*)(const void *, const void *)) lngCmp,
    1650             :                 .atomHash = (BUN (*)(const void *)) lngHash,
    1651             : #endif
    1652             :                 .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) OIDfromStr,
    1653             :                 .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) OIDtoStr,
    1654             :                 .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) voidRead,
    1655             :                 .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) voidWrite,
    1656             :         },
    1657             :         [TYPE_bit] = {
    1658             :                 .name = "bit",
    1659             :                 .storage = TYPE_bte,
    1660             :                 .linear = true,
    1661             :                 .size = sizeof(bit),
    1662             :                 .atomNull = (void *) &bte_nil,
    1663             :                 .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) bitFromStr,
    1664             :                 .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) bitToStr,
    1665             :                 .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) bitRead,
    1666             :                 .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) bitWrite,
    1667             :                 .atomCmp = (int (*)(const void *, const void *)) bteCmp,
    1668             :                 .atomHash = (BUN (*)(const void *)) bteHash,
    1669             :         },
    1670             :         [TYPE_msk] = {
    1671             :                 .name = "msk",
    1672             :                 .storage = TYPE_msk,
    1673             :                 .linear = false,
    1674             :                 .size = 1,      /* really 1/8 */
    1675             :                 .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) mskFromStr,
    1676             :                 .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) mskToStr,
    1677             :                 .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) mskRead,
    1678             :                 .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) mskWrite,
    1679             :                 .atomCmp = (int (*)(const void *, const void *)) mskCmp,
    1680             :         },
    1681             :         [TYPE_bte] = {
    1682             :                 .name = "bte",
    1683             :                 .storage = TYPE_bte,
    1684             :                 .linear = true,
    1685             :                 .size = sizeof(bte),
    1686             :                 .atomNull = (void *) &bte_nil,
    1687             :                 .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) bteFromStr,
    1688             :                 .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) bteToStr,
    1689             :                 .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) bteRead,
    1690             :                 .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) bteWrite,
    1691             :                 .atomCmp = (int (*)(const void *, const void *)) bteCmp,
    1692             :                 .atomHash = (BUN (*)(const void *)) bteHash,
    1693             :         },
    1694             :         [TYPE_sht] = {
    1695             :                 .name = "sht",
    1696             :                 .storage = TYPE_sht,
    1697             :                 .linear = true,
    1698             :                 .size = sizeof(sht),
    1699             :                 .atomNull = (void *) &sht_nil,
    1700             :                 .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) shtFromStr,
    1701             :                 .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) shtToStr,
    1702             :                 .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) shtRead,
    1703             :                 .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) shtWrite,
    1704             :                 .atomCmp = (int (*)(const void *, const void *)) shtCmp,
    1705             :                 .atomHash = (BUN (*)(const void *)) shtHash,
    1706             :         },
    1707             :         [TYPE_int] = {
    1708             :                 .name = "int",
    1709             :                 .storage = TYPE_int,
    1710             :                 .linear = true,
    1711             :                 .size = sizeof(int),
    1712             :                 .atomNull = (void *) &int_nil,
    1713             :                 .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) intFromStr,
    1714             :                 .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) intToStr,
    1715             :                 .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) intRead,
    1716             :                 .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) intWrite,
    1717             :                 .atomCmp = (int (*)(const void *, const void *)) intCmp,
    1718             :                 .atomHash = (BUN (*)(const void *)) intHash,
    1719             :         },
    1720             :         [TYPE_oid] = {
    1721             :                 .name = "oid",
    1722             :                 .linear = true,
    1723             :                 .size = sizeof(oid),
    1724             : #if SIZEOF_OID == SIZEOF_INT
    1725             :                 .storage = TYPE_int,
    1726             :                 .atomNull = (void *) &int_nil,
    1727             :                 .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) intRead,
    1728             :                 .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) intWrite,
    1729             :                 .atomCmp = (int (*)(const void *, const void *)) intCmp,
    1730             :                 .atomHash = (BUN (*)(const void *)) intHash,
    1731             : #else
    1732             :                 .storage = TYPE_lng,
    1733             :                 .atomNull = (void *) &lng_nil,
    1734             :                 .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) lngRead,
    1735             :                 .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) lngWrite,
    1736             :                 .atomCmp = (int (*)(const void *, const void *)) lngCmp,
    1737             :                 .atomHash = (BUN (*)(const void *)) lngHash,
    1738             : #endif
    1739             :                 .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) OIDfromStr,
    1740             :                 .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) OIDtoStr,
    1741             :         },
    1742             :         [TYPE_ptr] = {
    1743             :                 .name = "ptr",
    1744             :                 .storage = TYPE_ptr,
    1745             :                 .linear = true,
    1746             :                 .size = sizeof(void *),
    1747             :                 .atomNull = (void *) &ptr_nil,
    1748             :                 .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) ptrFromStr,
    1749             :                 .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) ptrToStr,
    1750             :                 .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) ptrRead,
    1751             :                 .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) ptrWrite,
    1752             : #if SIZEOF_VOID_P == SIZEOF_INT
    1753             :                 .atomCmp = (int (*)(const void *, const void *)) intCmp,
    1754             :                 .atomHash = (BUN (*)(const void *)) intHash,
    1755             : #else /* SIZEOF_VOID_P == SIZEOF_LNG */
    1756             :                 .atomCmp = (int (*)(const void *, const void *)) lngCmp,
    1757             :                 .atomHash = (BUN (*)(const void *)) lngHash,
    1758             : #endif
    1759             :         },
    1760             :         [TYPE_flt] = {
    1761             :                 .name = "flt",
    1762             :                 .storage = TYPE_flt,
    1763             :                 .linear = true,
    1764             :                 .size = sizeof(flt),
    1765             :                 .atomNull = (void *) &flt_nil,
    1766             :                 .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) fltFromStr,
    1767             :                 .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) fltToStr,
    1768             :                 .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) fltRead,
    1769             :                 .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) fltWrite,
    1770             :                 .atomCmp = (int (*)(const void *, const void *)) fltCmp,
    1771             :                 .atomHash = (BUN (*)(const void *)) fltHash,
    1772             :         },
    1773             :         [TYPE_dbl] = {
    1774             :                 .name = "dbl",
    1775             :                 .storage = TYPE_dbl,
    1776             :                 .linear = true,
    1777             :                 .size = sizeof(dbl),
    1778             :                 .atomNull = (void *) &dbl_nil,
    1779             :                 .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) dblFromStr,
    1780             :                 .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) dblToStr,
    1781             :                 .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) dblRead,
    1782             :                 .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) dblWrite,
    1783             :                 .atomCmp = (int (*)(const void *, const void *)) dblCmp,
    1784             :                 .atomHash = (BUN (*)(const void *)) dblHash,
    1785             :         },
    1786             :         [TYPE_lng] = {
    1787             :                 .name = "lng",
    1788             :                 .storage = TYPE_lng,
    1789             :                 .linear = true,
    1790             :                 .size = sizeof(lng),
    1791             :                 .atomNull = (void *) &lng_nil,
    1792             :                 .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) lngFromStr,
    1793             :                 .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) lngToStr,
    1794             :                 .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) lngRead,
    1795             :                 .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) lngWrite,
    1796             :                 .atomCmp = (int (*)(const void *, const void *)) lngCmp,
    1797             :                 .atomHash = (BUN (*)(const void *)) lngHash,
    1798             :         },
    1799             : #ifdef HAVE_HGE
    1800             :         [TYPE_hge] = {
    1801             :                 .name = "hge",
    1802             :                 .storage = TYPE_hge,
    1803             :                 .linear = true,
    1804             :                 .size = sizeof(hge),
    1805             :                 .atomNull = (void *) &hge_nil,
    1806             :                 .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) hgeFromStr,
    1807             :                 .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) hgeToStr,
    1808             :                 .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) hgeRead,
    1809             :                 .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) hgeWrite,
    1810             :                 .atomCmp = (int (*)(const void *, const void *)) hgeCmp,
    1811             :                 .atomHash = (BUN (*)(const void *)) hgeHash,
    1812             :         },
    1813             : #endif
    1814             :         [TYPE_date] = {
    1815             :                 .name = "date",
    1816             :                 .storage = TYPE_int,
    1817             :                 .linear = true,
    1818             :                 .size = sizeof(int),
    1819             :                 .atomNull = (void *) &int_nil,
    1820             :                 .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) date_fromstr,
    1821             :                 .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) date_tostr,
    1822             :                 .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) intRead,
    1823             :                 .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) intWrite,
    1824             :                 .atomCmp = (int (*)(const void *, const void *)) intCmp,
    1825             :                 .atomHash = (BUN (*)(const void *)) intHash,
    1826             :         },
    1827             :         [TYPE_daytime] = {
    1828             :                 .name = "daytime",
    1829             :                 .storage = TYPE_lng,
    1830             :                 .linear = true,
    1831             :                 .size = sizeof(lng),
    1832             :                 .atomNull = (void *) &lng_nil,
    1833             :                 .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) daytime_tz_fromstr,
    1834             :                 .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) daytime_tostr,
    1835             :                 .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) lngRead,
    1836             :                 .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) lngWrite,
    1837             :                 .atomCmp = (int (*)(const void *, const void *)) lngCmp,
    1838             :                 .atomHash = (BUN (*)(const void *)) lngHash,
    1839             :         },
    1840             :         [TYPE_timestamp] = {
    1841             :                 .name = "timestamp",
    1842             :                 .storage = TYPE_lng,
    1843             :                 .linear = true,
    1844             :                 .size = sizeof(lng),
    1845             :                 .atomNull = (void *) &lng_nil,
    1846             :                 .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) timestamp_fromstr,
    1847             :                 .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) timestamp_tostr,
    1848             :                 .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) lngRead,
    1849             :                 .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) lngWrite,
    1850             :                 .atomCmp = (int (*)(const void *, const void *)) lngCmp,
    1851             :                 .atomHash = (BUN (*)(const void *)) lngHash,
    1852             :         },
    1853             :         [TYPE_uuid] = {
    1854             :                 .name = "uuid",
    1855             :                 .storage = TYPE_uuid,
    1856             :                 .linear = true,
    1857             :                 .size = sizeof(uuid),
    1858             :                 .atomNull = (void *) &uuid_nil,
    1859             :                 .atomFromStr = UUIDfromString,
    1860             :                 .atomToStr = UUIDtoString,
    1861             :                 .atomRead = UUIDread,
    1862             :                 .atomWrite = UUIDwrite,
    1863             :                 .atomCmp = UUIDcompare,
    1864             :                 .atomHash = UUIDhash,
    1865             :         },
    1866             :         [TYPE_str] = {
    1867             :                 .name = "str",
    1868             :                 .storage = TYPE_str,
    1869             :                 .linear = true,
    1870             :                 .size = sizeof(var_t),
    1871             :                 .atomNull = (void *) str_nil,
    1872             :                 .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) strFromStr,
    1873             :                 .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) strToStr,
    1874             :                 .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) strRead,
    1875             :                 .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) strWrite,
    1876             :                 .atomCmp = (int (*)(const void *, const void *)) strCmp,
    1877             :                 .atomHash = (BUN (*)(const void *)) strHash,
    1878             :                 .atomPut = strPut,
    1879             :                 .atomLen = (size_t (*)(const void *)) strLen,
    1880             :                 .atomHeap = strHeap,
    1881             :         },
    1882             :         [TYPE_blob] = {
    1883             :                 .name = "blob",
    1884             :                 .storage = TYPE_blob,
    1885             :                 .linear = true,
    1886             :                 .size = sizeof(var_t),
    1887             :                 .atomNull = (void *) &blob_nil,
    1888             :                 .atomFromStr = BLOBfromstr,
    1889             :                 .atomToStr = BLOBtostr,
    1890             :                 .atomRead = BLOBread,
    1891             :                 .atomWrite = BLOBwrite,
    1892             :                 .atomCmp = BLOBcmp,
    1893             :                 .atomHash = BLOBhash,
    1894             :                 .atomPut = BLOBput,
    1895             :                 .atomDel = BLOBdel,
    1896             :                 .atomLen = BLOBlength,
    1897             :                 .atomHeap = BLOBheap,
    1898             :         },
    1899             : };
    1900             : 
    1901             : int GDKatomcnt = TYPE_blob + 1;
    1902             : 
    1903             : /*
    1904             :  * Sometimes a bat descriptor is loaded before the dynamic module
    1905             :  * defining the atom is loaded. To support this an extra set of
    1906             :  * unknown atoms is kept.  These can be accessed via the ATOMunknown
    1907             :  * interface. Finding an (negative) atom index can be done via
    1908             :  * ATOMunknown_find, which simply adds the atom if it's not in the
    1909             :  * unknown set. The index can be used to find the name of an unknown
    1910             :  * ATOM via ATOMunknown_name.
    1911             :  */
    1912             : static str unknown[MAXATOMS] = { NULL };
    1913             : 
    1914             : int
    1915         241 : ATOMunknown_find(const char *nme)
    1916             : {
    1917         241 :         int i, j = 0;
    1918             : 
    1919             :         /* first try to find the atom */
    1920         241 :         MT_lock_set(&GDKatomLock);
    1921        7428 :         for (i = 1; i < MAXATOMS; i++) {
    1922        7133 :                 if (unknown[i]) {
    1923         338 :                         if (strcmp(unknown[i], nme) == 0) {
    1924         187 :                                 MT_lock_unset(&GDKatomLock);
    1925         187 :                                 return -i;
    1926             :                         }
    1927        6795 :                 } else if (j == 0)
    1928        6946 :                         j = i;
    1929             :         }
    1930          54 :         if (j == 0) {
    1931             :                 /* no space for new atom (shouldn't happen) */
    1932           0 :                 MT_lock_unset(&GDKatomLock);
    1933           0 :                 return 0;
    1934             :         }
    1935          54 :         if ((unknown[j] = GDKstrdup(nme)) == NULL) {
    1936           0 :                 MT_lock_unset(&GDKatomLock);
    1937           0 :                 return 0;
    1938             :         }
    1939          54 :         MT_lock_unset(&GDKatomLock);
    1940          54 :         return -j;
    1941             : }
    1942             : 
    1943             : const char *
    1944         297 : ATOMunknown_name(int i)
    1945             : {
    1946         297 :         assert(i < 0);
    1947         297 :         assert(-i < MAXATOMS);
    1948         297 :         assert(unknown[-i]);
    1949         297 :         return unknown[-i];
    1950             : }
    1951             : 
    1952             : void
    1953         328 : ATOMunknown_clean(void)
    1954             : {
    1955         328 :         int i;
    1956             : 
    1957         328 :         MT_lock_set(&GDKatomLock);
    1958         710 :         for (i = 1; i < MAXATOMS; i++) {
    1959         382 :                 if(unknown[i]) {
    1960          54 :                         GDKfree(unknown[i]);
    1961          54 :                         unknown[i] = NULL;
    1962             :                 } else {
    1963             :                         break;
    1964             :                 }
    1965             :         }
    1966         328 :         MT_lock_unset(&GDKatomLock);
    1967         328 : }

Generated by: LCOV version 1.14