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