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