LCOV - code coverage report
Current view: top level - gdk - gdk_atoms.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 387 515 75.1 %
Date: 2020-06-29 20:00:14 Functions: 58 72 80.6 %

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

Generated by: LCOV version 1.14