LCOV - code coverage report
Current view: top level - gdk - gdk_atoms.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 602 767 78.5 %
Date: 2025-03-25 21:27:32 Functions: 79 90 87.8 %

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

Generated by: LCOV version 1.14