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

Generated by: LCOV version 1.14