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