LCOV - code coverage report
Current view: top level - gdk - gdk_atoms.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 410 574 71.4 %
Date: 2021-09-14 19:48:19 Functions: 68 83 81.9 %

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

Generated by: LCOV version 1.14