LCOV - code coverage report
Current view: top level - gdk - gdk_atoms.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 606 806 75.2 %
Date: 2024-04-25 20:03:45 Functions: 81 96 84.4 %

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

Generated by: LCOV version 1.14