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 282 : mskCmp(const msk *l, const msk *r)
43 : {
44 282 : return (*l > *r) - (*l < *r);
45 : }
46 :
47 : static int
48 687578728 : bteCmp(const bte *l, const bte *r)
49 : {
50 687578728 : return (*l > *r) - (*l < *r);
51 : }
52 :
53 : static int
54 60826177 : shtCmp(const sht *l, const sht *r)
55 : {
56 60826177 : return (*l > *r) - (*l < *r);
57 : }
58 :
59 : static int
60 2859627619 : intCmp(const int *l, const int *r)
61 : {
62 2859627619 : return (*l > *r) - (*l < *r);
63 : }
64 :
65 : static int
66 409336770 : fltCmp(const flt *l, const flt *r)
67 : {
68 409336770 : return is_flt_nil(*l) ? -!is_flt_nil(*r) : is_flt_nil(*r) ? 1 : (*l > *r) - (*l < *r);
69 : }
70 :
71 : static int
72 5740535667 : lngCmp(const lng *l, const lng *r)
73 : {
74 5740535667 : return (*l > *r) - (*l < *r);
75 : }
76 :
77 : #ifdef HAVE_HGE
78 : static int
79 179588139 : hgeCmp(const hge *l, const hge *r)
80 : {
81 179588139 : return (*l > *r) - (*l < *r);
82 : }
83 : #endif
84 :
85 : static int
86 50061030 : dblCmp(const dbl *l, const dbl *r)
87 : {
88 50061030 : 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 1181440 : intHash(const int *v)
109 : {
110 1181440 : 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 151519 : fltHash(const flt *v)
129 : {
130 151519 : if (is_flt_nil(*v))
131 : return (BUN) mix_int(GDK_int_min);
132 151386 : if (*v == 0)
133 : return (BUN) mix_int(0);
134 147435 : return (BUN) mix_int(*(const unsigned int *) v);
135 : }
136 :
137 : static BUN
138 42117 : dblHash(const dbl *v)
139 : {
140 42117 : if (is_dbl_nil(*v))
141 : return (BUN) mix_lng(GDK_lng_min);
142 40146 : if (*v == 0)
143 : return (BUN) mix_lng(0);
144 34804 : 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 3148 : ATOMallocate(const char *id)
189 : {
190 3148 : int t;
191 :
192 3148 : if (strlen(id) >= IDLENGTH) {
193 0 : GDKerror("name too long");
194 0 : return int_nil;
195 : }
196 :
197 3148 : MT_lock_set(&GDKatomLock);
198 3148 : t = ATOMindex(id);
199 3148 : if (t < 0) {
200 3148 : t = -t;
201 3148 : if (t == GDKatomcnt) {
202 3148 : if (GDKatomcnt == MAXATOMS) {
203 0 : MT_lock_unset(&GDKatomLock);
204 0 : GDKerror("too many types");
205 0 : return int_nil;
206 : }
207 3148 : GDKatomcnt++;
208 : }
209 3148 : BATatoms[t] = (atomDesc) {
210 : .size = sizeof(int), /* default */
211 : .linear = true, /* default */
212 : .storage = t, /* default */
213 : };
214 3148 : strcpy(BATatoms[t].name, id);
215 : }
216 3148 : MT_lock_unset(&GDKatomLock);
217 3148 : return t;
218 : }
219 :
220 : int
221 69443 : ATOMindex(const char *nme)
222 : {
223 69443 : int t, j = GDKatomcnt;
224 :
225 777272 : for (t = 0; t < GDKatomcnt; t++) {
226 773514 : if (!BATatoms[t].name[0]) {
227 0 : if (j == GDKatomcnt)
228 707829 : j = t;
229 773514 : } else if (strcmp(nme, BATatoms[t].name) == 0) {
230 65685 : return t;
231 : }
232 :
233 : }
234 3758 : return -j;
235 : }
236 :
237 : const char *
238 409686 : ATOMname(int t)
239 : {
240 409686 : return t >= 0 && t < GDKatomcnt && *BATatoms[t].name ? BATatoms[t].name : "null";
241 : }
242 :
243 : bool
244 245482 : ATOMisdescendant(int tpe, int parent)
245 : {
246 245482 : int cur = -1;
247 :
248 498474 : while (cur != tpe) {
249 252992 : cur = tpe;
250 252992 : if (cur == parent)
251 : return true;
252 252992 : 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 21 : ATOMnil(int t)
284 : {
285 21 : const void *src = ATOMnilptr(t);
286 21 : size_t len = ATOMlen(ATOMtype(t), src);
287 21 : 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 7408897 : ATOMlen(int t, const void *src)
299 : {
300 7408897 : size_t (*l)(const void *) = BATatoms[t].atomLen;
301 :
302 7408897 : return l ? (*l) (src) : ATOMsize(t);
303 : }
304 :
305 : gdk_return
306 1013035 : ATOMheap(int t, Heap *hp, size_t cap)
307 : {
308 1013035 : gdk_return (*h) (Heap *, size_t) = BATatoms[t].atomHeap;
309 :
310 1013035 : if (h) {
311 1013035 : return (*h) (hp, cap);
312 : }
313 : return GDK_SUCCEED;
314 : }
315 :
316 : /*
317 : * Atom print avoids coercion to strings for built-in types.
318 : * The comparison against the NULL value is hard coded for speed.
319 : */
320 : #define LINE_LEN 60
321 :
322 : int
323 702 : ATOMprint(int t, const void *p, stream *s)
324 : {
325 702 : ssize_t (*tostr) (char **, size_t *, const void *, bool);
326 702 : ssize_t res;
327 :
328 1404 : if (p && t >= 0 && t < GDKatomcnt && (tostr = BATatoms[t].atomToStr)) {
329 702 : size_t sz;
330 :
331 702 : if (t < TYPE_date) {
332 237 : char buf[dblStrlen], *addr = buf; /* use memory from stack */
333 :
334 237 : sz = dblStrlen;
335 237 : res = (*tostr) (&addr, &sz, p, true);
336 237 : if (res > 0)
337 237 : res = mnstr_write(s, buf, (size_t) res, 1);
338 : } else {
339 465 : str buf = NULL;
340 :
341 465 : sz = 0;
342 465 : res = (*tostr) (&buf, &sz, p, true);
343 465 : if (res > 0)
344 465 : res = mnstr_write(s, buf, (size_t) res, 1);
345 465 : GDKfree(buf);
346 : }
347 : } else {
348 0 : res = mnstr_write(s, "nil", 1, 3);
349 : }
350 702 : if (res < 0)
351 0 : GDKsyserror("ATOMprint: write failure\n");
352 702 : return (int) res;
353 : }
354 :
355 :
356 : char *
357 27429 : ATOMformat(int t, const void *p)
358 : {
359 27429 : ssize_t (*tostr) (char **, size_t *, const void *, bool);
360 :
361 27429 : if (p && 0 <= t && t < GDKatomcnt && (tostr = BATatoms[t].atomToStr)) {
362 27441 : size_t sz = 0;
363 27441 : char *buf = NULL;
364 27441 : ssize_t res = (*tostr) (&buf, &sz, p, true);
365 27450 : if (res < 0 && buf) {
366 0 : GDKfree(buf);
367 0 : buf = NULL;
368 : }
369 27450 : return buf;
370 : }
371 0 : return GDKstrdup("nil");
372 : }
373 :
374 : ptr
375 115082 : ATOMdup(int t, const void *p)
376 : {
377 115082 : size_t len = ATOMlen(t, p);
378 115082 : ptr n = GDKmalloc(len);
379 :
380 115082 : if (n)
381 115082 : memcpy(n, p, len);
382 115082 : 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 15588 : bitFromStr(const char *src, size_t *len, bit **dst, bool external)
498 : {
499 15588 : const char *p = src;
500 :
501 15588 : atommem(sizeof(bit));
502 :
503 15589 : **dst = bit_nil;
504 :
505 15589 : if (strNil(src))
506 : return 1;
507 :
508 15589 : while (GDKisspace(*p))
509 0 : p++;
510 15589 : if (*p == '0') {
511 294 : **dst = FALSE;
512 294 : p++;
513 15295 : } else if (*p == '1') {
514 60 : **dst = TRUE;
515 60 : p++;
516 15235 : } else if (strncasecmp(p, "true", 4) == 0) {
517 10272 : **dst = TRUE;
518 10272 : p += 4;
519 4963 : } else if (strncasecmp(p, "false", 5) == 0) {
520 4931 : **dst = FALSE;
521 4931 : p += 5;
522 32 : } else if (external && strncasecmp(p, "nil", 3) == 0) {
523 0 : p += 3;
524 : } else {
525 : return -1;
526 : }
527 15557 : while (GDKisspace(*p))
528 0 : p++;
529 15557 : return (ssize_t) (p - src);
530 : }
531 :
532 : ssize_t
533 70766 : bitToStr(char **dst, size_t *len, const bit *src, bool external)
534 : {
535 70766 : atommem(6);
536 :
537 70766 : 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 70741 : if (*src) {
546 25325 : strcpy(*dst, "true");
547 25325 : return 4;
548 : }
549 45416 : strcpy(*dst, "false");
550 45416 : 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 234187511 : numFromStr(const char *src, size_t *len, void **dst, int tp, bool external)
700 : {
701 234187511 : const char *p = src;
702 234187511 : size_t sz = ATOMsize(tp);
703 : #ifdef HAVE_HGE
704 234187511 : hge base = 0;
705 : #else
706 : lng base = 0;
707 : #endif
708 234187511 : 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 234187511 : atommem(sz);
719 :
720 234187511 : if (strNil(src)) {
721 0 : memcpy(*dst, ATOMnilptr(tp), sz);
722 0 : return 1;
723 : }
724 :
725 234187609 : while (GDKisspace(*p))
726 98 : p++;
727 234187511 : if (!GDKisdigit(*p)) {
728 11691 : 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 11496 : case '-':
740 11496 : sign = -1;
741 11496 : p++;
742 11496 : break;
743 1 : case '+':
744 1 : p++;
745 1 : break;
746 : }
747 11686 : if (!GDKisdigit(*p)) {
748 195 : GDKerror("not a number");
749 195 : goto bailout;
750 : }
751 : }
752 568019006 : do {
753 568019006 : int dig = base10(*p);
754 568019006 : if (base > maxdiv[1].maxval ||
755 1 : (base == maxdiv[1].maxval && dig > maxmod10)) {
756 : /* overflow */
757 0 : goto overflow;
758 : }
759 568019006 : base = 10 * base + dig;
760 568019006 : p++;
761 568019006 : } while (GDKisdigit(*p));
762 234187311 : 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 234187311 : base *= sign;
788 234187311 : switch (sz) {
789 54663 : case 1: {
790 54663 : bte **dstbte = (bte **) dst;
791 54663 : if (base < GDK_bte_min || base > GDK_bte_max) {
792 0 : goto overflow;
793 : }
794 54663 : **dstbte = (bte) base;
795 54663 : break;
796 : }
797 329687 : case 2: {
798 329687 : sht **dstsht = (sht **) dst;
799 329687 : if (base < GDK_sht_min || base > GDK_sht_max) {
800 3 : goto overflow;
801 : }
802 329684 : **dstsht = (sht) base;
803 329684 : break;
804 : }
805 230169135 : case 4: {
806 230169135 : int **dstint = (int **) dst;
807 230169135 : if (base < GDK_int_min || base > GDK_int_max) {
808 2 : goto overflow;
809 : }
810 230169133 : **dstint = (int) base;
811 230169133 : break;
812 : }
813 1911885 : case 8: {
814 1911885 : lng **dstlng = (lng **) dst;
815 : #ifdef HAVE_HGE
816 1911885 : if (base < GDK_lng_min || base > GDK_lng_max) {
817 4 : goto overflow;
818 : }
819 : #endif
820 1911881 : **dstlng = (lng) base;
821 1911881 : if (p[0] == 'L' && p[1] == 'L')
822 0 : p += 2;
823 : break;
824 : }
825 : #ifdef HAVE_HGE
826 1721941 : case 16: {
827 1721941 : hge **dsthge = (hge **) dst;
828 1721941 : **dsthge = (hge) base;
829 1721941 : if (p[0] == 'L' && p[1] == 'L')
830 0 : p += 2;
831 : break;
832 : }
833 : #endif
834 : }
835 234187418 : while (GDKisspace(*p))
836 116 : p++;
837 234187302 : 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 209 : bailout:
845 209 : memcpy(*dst, ATOMnilptr(tp), sz);
846 209 : return -1;
847 : }
848 :
849 : ssize_t
850 54276 : bteFromStr(const char *src, size_t *len, bte **dst, bool external)
851 : {
852 54276 : return numFromStr(src, len, (void **) dst, TYPE_bte, external);
853 : }
854 :
855 : ssize_t
856 325299 : shtFromStr(const char *src, size_t *len, sht **dst, bool external)
857 : {
858 325299 : return numFromStr(src, len, (void **) dst, TYPE_sht, external);
859 : }
860 :
861 : ssize_t
862 221978359 : intFromStr(const char *src, size_t *len, int **dst, bool external)
863 : {
864 221978359 : return numFromStr(src, len, (void **) dst, TYPE_int, external);
865 : }
866 :
867 : ssize_t
868 1911857 : lngFromStr(const char *src, size_t *len, lng **dst, bool external)
869 : {
870 1911857 : return numFromStr(src, len, (void **) dst, TYPE_lng, external);
871 : }
872 :
873 : #ifdef HAVE_HGE
874 : ssize_t
875 1721568 : hgeFromStr(const char *src, size_t *len, hge **dst, bool external)
876 : {
877 1721568 : 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 125350 : mskWrite(const msk *a, stream *s, size_t cnt)
908 : {
909 125350 : if (cnt == 0)
910 : return GDK_SUCCEED;
911 125350 : if (cnt == 1)
912 125350 : return mnstr_writeBte(s, (int8_t) *a) ? GDK_SUCCEED : GDK_FAIL;
913 : return GDK_FAIL;
914 : }
915 :
916 : static void *
917 124192 : mskRead(msk *A, size_t *dstlen, stream *s, size_t cnt)
918 : {
919 124192 : int8_t v;
920 124192 : msk *a = A;
921 124192 : if (cnt != 1)
922 : return NULL;
923 124192 : if (a == NULL || *dstlen == 0) {
924 0 : if ((a = GDKrealloc(a, 1)) == NULL)
925 : return NULL;
926 0 : *dstlen = 1;
927 : }
928 124192 : if (mnstr_readBte(s, &v) != 1) {
929 0 : if (a != A)
930 0 : GDKfree(a);
931 0 : return NULL;
932 : }
933 124192 : *a = v != 0;
934 124192 : return a;
935 : }
936 :
937 7283 : atom_io(bit, Bte, bte)
938 :
939 43720 : atomtostr(bte, "%hhd", )
940 256226 : atom_io(bte, Bte, bte)
941 :
942 1073017 : atomtostr(sht, "%hd", )
943 8423 : atom_io(sht, Sht, sht)
944 :
945 15496624 : atomtostr(int, "%d", )
946 220454 : atom_io(int, Int, int)
947 :
948 165880 : atomtostr(lng, LLFMT, )
949 5951 : 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 3301 : hgeToStr(char **dst, size_t *len, const hge *src, bool external)
957 : {
958 3301 : atommem(hgeStrlen);
959 3301 : 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 3300 : if ((hge) GDK_lng_min <= *src && *src <= (hge) GDK_lng_max) {
970 3183 : lng s = (lng) *src;
971 3183 : 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 267809 : dblFromStr(const char *src, size_t *len, dbl **dst, bool external)
1039 : {
1040 267809 : const char *p = src;
1041 267809 : ssize_t n = 0;
1042 267809 : double d;
1043 :
1044 : /* alloc memory */
1045 267809 : atommem(sizeof(dbl));
1046 :
1047 267809 : if (strNil(src)) {
1048 0 : **dst = dbl_nil;
1049 0 : return 1;
1050 : }
1051 :
1052 267928 : while (GDKisspace(*p))
1053 119 : p++;
1054 267809 : 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 267809 : char *pe;
1065 267809 : errno = 0;
1066 267809 : d = strtod(p, &pe);
1067 282204 : if (p == pe)
1068 : p = src; /* nothing converted */
1069 : else
1070 282170 : p = pe;
1071 282204 : n = (ssize_t) (p - src);
1072 282204 : if (n == 0 || (errno == ERANGE && (d < -1 || d > 1))
1073 282162 : || !isfinite(d) /* no NaN or Infinite */
1074 : ) {
1075 104 : GDKerror("overflow or not a number\n");
1076 104 : return -1;
1077 : } else {
1078 282150 : while (src[n] && GDKisspace(src[n]))
1079 50 : n++;
1080 282100 : **dst = (dbl) d;
1081 : }
1082 : }
1083 : return n;
1084 : }
1085 :
1086 : ssize_t
1087 14050 : dblToStr(char **dst, size_t *len, const dbl *src, bool external)
1088 : {
1089 14050 : int l = 0;
1090 :
1091 14050 : atommem(dblStrlen);
1092 14050 : 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 14043 : if (*src <= (dbl) 999999999999999 &&
1101 13896 : *src >= (dbl) -999999999999999 &&
1102 13896 : (dbl) (int) *src == *src) {
1103 8604 : l = snprintf(*dst, *len, "%.0f", *src);
1104 8604 : if (strtod(*dst, NULL) == *src)
1105 8603 : return (ssize_t) l;
1106 : }
1107 39238 : for (int i = 4; i < 18; i++) {
1108 39238 : l = snprintf(*dst, *len, "%.*g", i, *src);
1109 39238 : if (strtod(*dst, NULL) == *src)
1110 : break;
1111 : }
1112 5438 : return (ssize_t) l;
1113 : }
1114 :
1115 768 : atom_io(dbl, Lng, lng)
1116 :
1117 : ssize_t
1118 1828040 : fltFromStr(const char *src, size_t *len, flt **dst, bool external)
1119 : {
1120 1828040 : const char *p = src;
1121 1828040 : ssize_t n = 0;
1122 1828040 : float f;
1123 :
1124 : /* alloc memory */
1125 1828040 : atommem(sizeof(flt));
1126 :
1127 1828040 : if (strNil(src)) {
1128 0 : **dst = flt_nil;
1129 0 : return 1;
1130 : }
1131 :
1132 1828105 : while (GDKisspace(*p))
1133 65 : p++;
1134 1828040 : 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 1828040 : char *pe;
1145 1828040 : errno = 0;
1146 1828040 : f = strtof(p, &pe);
1147 1834310 : if (p == pe)
1148 : p = src; /* nothing converted */
1149 : else
1150 1834302 : p = pe;
1151 1834310 : n = (ssize_t) (p - src);
1152 1834310 : if (n == 0 || (errno == ERANGE && (f < -1 || f > 1))
1153 1834294 : || !isfinite(f) /* no NaN or infinite */) {
1154 58 : GDKerror("overflow or not a number\n");
1155 58 : return -1;
1156 : } else {
1157 1834291 : while (src[n] && GDKisspace(src[n]))
1158 39 : n++;
1159 1834252 : if (f == -0)
1160 6550 : f = 0;
1161 1834252 : **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 217 : atom_io(flt, Int, int)
1197 :
1198 :
1199 : /*
1200 : * String conversion routines.
1201 : */
1202 : ssize_t
1203 26 : 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 26 : lng ui = 0, *uip = &ui;
1209 : #endif
1210 26 : size_t l = sizeof(ui);
1211 26 : ssize_t pos = 0;
1212 26 : const char *p = src;
1213 :
1214 26 : atommem(sizeof(oid));
1215 :
1216 26 : **dst = oid_nil;
1217 26 : if (strNil(src))
1218 : return 1;
1219 :
1220 26 : while (GDKisspace(*p))
1221 0 : p++;
1222 :
1223 26 : if (external && strncmp(p, "nil", 3) == 0)
1224 0 : return (ssize_t) (p - src) + 3;
1225 :
1226 26 : if (*p >= '0' && *p <= '9') {
1227 : #if SIZEOF_OID == SIZEOF_INT
1228 : pos = intFromStr(p, &l, &uip, external);
1229 : #else
1230 25 : pos = lngFromStr(p, &l, &uip, external);
1231 : #endif
1232 25 : if (pos < 0)
1233 : return pos;
1234 25 : if (p[pos] == '@') {
1235 7 : pos++;
1236 14 : while (p[pos] >= '0' && p[pos] <= '9')
1237 7 : pos++;
1238 : }
1239 25 : if (ui >= 0) {
1240 25 : **dst = ui;
1241 : }
1242 25 : p += pos;
1243 : } else {
1244 1 : GDKerror("not an OID\n");
1245 1 : return -1;
1246 : }
1247 25 : while (GDKisspace(*p))
1248 0 : p++;
1249 25 : return (ssize_t) (p - src);
1250 : }
1251 :
1252 : ssize_t
1253 4210 : OIDtoStr(char **dst, size_t *len, const oid *src, bool external)
1254 : {
1255 4210 : atommem(oidStrlen);
1256 :
1257 4210 : 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 4194 : return snprintf(*dst, *len, OIDFMT "@0", *src);
1266 : }
1267 :
1268 : static int
1269 4144016 : UUIDcompare(const void *L, const void *R)
1270 : {
1271 4144016 : const uuid *l = L, *r = R;
1272 4144016 : if (is_uuid_nil(*r))
1273 441040 : return !is_uuid_nil(*l);
1274 3702976 : if (is_uuid_nil(*l))
1275 : return -1;
1276 401253 : 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 1599 : u.u[i] = *s - '0';
1311 1577 : else if ('a' <= *s && *s <= 'f')
1312 1143 : 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 1497 : u.u[i] |= *s - '0';
1322 1647 : else if ('a' <= *s && *s <= 'f')
1323 1277 : 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 22 : UUIDread(void *U, size_t *dstlen, stream *s, size_t cnt)
1351 : {
1352 22 : uuid *u = U;
1353 22 : 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 22 : 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 23 : UUIDwrite(const void *u, stream *s, size_t cnt)
1368 : {
1369 23 : return mnstr_write(s, u, UUID_SIZE, cnt) ? GDK_SUCCEED : GDK_FAIL;
1370 : }
1371 :
1372 : static ssize_t
1373 1764853 : UUIDtoString(str *retval, size_t *len, const void *VALUE, bool external)
1374 : {
1375 1764853 : const uuid *value = VALUE;
1376 1764853 : 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 1764130 : 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 1764130 : snprintf(*retval, *len,
1394 : "%02x%02x%02x%02x-%02x%02x-%02x%02x"
1395 : "-%02x%02x-%02x%02x%02x%02x%02x%02x",
1396 1764130 : value->u[0], value->u[1], value->u[2], value->u[3],
1397 1764130 : value->u[4], value->u[5], value->u[6], value->u[7],
1398 1764130 : value->u[8], value->u[9], value->u[10], value->u[11],
1399 1764130 : value->u[12], value->u[13], value->u[14], value->u[15]);
1400 1764130 : 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 14806110 : blobsize(size_t nitems)
1410 : {
1411 14806110 : if (nitems == ~(size_t) 0)
1412 5334273 : nitems = 0;
1413 14806110 : assert(offsetof(blob, data) + nitems <= VAR_MAX);
1414 14806110 : return (size_t) (offsetof(blob, data) + nitems);
1415 : }
1416 :
1417 : static int
1418 14342226 : BLOBcmp(const void *L, const void *R)
1419 : {
1420 14342226 : const blob *l = L, *r = R;
1421 14342226 : int c;
1422 14342226 : if (is_blob_nil(r))
1423 10407001 : return !is_blob_nil(l);
1424 3935225 : if (is_blob_nil(l))
1425 : return -1;
1426 6670 : if (l->nitems < r->nitems) {
1427 2571 : c = memcmp(l->data, r->data, l->nitems);
1428 2571 : if (c == 0)
1429 2273 : return -1;
1430 : } else {
1431 4099 : c = memcmp(l->data, r->data, r->nitems);
1432 4099 : if (c == 0)
1433 3559 : 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 11280 : BLOBhash(const void *B)
1446 : {
1447 11280 : const blob *b = B;
1448 11280 : return (BUN) b->nitems;
1449 : }
1450 :
1451 : static void *
1452 65 : BLOBread(void *A, size_t *dstlen, stream *s, size_t cnt)
1453 : {
1454 65 : blob *a = A;
1455 65 : int len;
1456 :
1457 65 : (void) cnt;
1458 65 : assert(cnt == 1);
1459 65 : if (mnstr_readInt(s, &len) != 1 || len < 0)
1460 : return NULL;
1461 65 : 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 65 : 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 65 : BLOBwrite(const void *A, stream *s, size_t cnt)
1475 : {
1476 65 : const blob *a = A;
1477 65 : size_t len = blobsize(a->nitems);
1478 :
1479 65 : (void) cnt;
1480 65 : assert(cnt == 1);
1481 130 : if (!mnstr_writeInt(s, (int) len) /* 64bit: check for overflow */ ||
1482 65 : mnstr_write(s, a, len, 1) < 0)
1483 0 : return GDK_FAIL;
1484 : return GDK_SUCCEED;
1485 : }
1486 :
1487 : static size_t
1488 1471 : BLOBlength(const void *P)
1489 : {
1490 1471 : const blob *p = P;
1491 1471 : size_t l = blobsize(p->nitems); /* 64bit: check for overflow */
1492 1471 : assert(l <= (size_t) GDK_int_max);
1493 1471 : return l;
1494 : }
1495 :
1496 : static gdk_return
1497 921 : BLOBheap(Heap *heap, size_t capacity)
1498 : {
1499 921 : return HEAP_initialize(heap, capacity, 0, (int) sizeof(var_t));
1500 : }
1501 :
1502 : static var_t
1503 7401090 : BLOBput(BAT *b, var_t *bun, const void *VAL)
1504 : {
1505 7401090 : const blob *val = VAL;
1506 7401090 : char *base = NULL;
1507 :
1508 7401090 : *bun = HEAP_malloc(b, blobsize(val->nitems));
1509 7401089 : base = b->tvheap->base;
1510 7401089 : if (*bun != (var_t) -1) {
1511 7401089 : memcpy(&base[*bun], val, blobsize(val->nitems));
1512 7401089 : b->tvheap->dirty = true;
1513 : }
1514 7401089 : 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 : *s++ = hexit[(p->data[i] >> 4) & 15];
1550 25857199 : *s++ = hexit[p->data[i] & 15];
1551 : }
1552 397 : *s = '\0';
1553 397 : return (ssize_t) (s - *tostr);
1554 : }
1555 :
1556 : static ssize_t
1557 2393 : BLOBfromstr(const char *instr, size_t *l, void **VAL, bool external)
1558 : {
1559 2393 : blob **val = (blob **) VAL;
1560 2393 : size_t i;
1561 2393 : size_t nitems;
1562 2393 : size_t nbytes;
1563 2393 : blob *result;
1564 2393 : const char *s = instr;
1565 :
1566 4786 : if (strNil(instr) || (external && strncmp(instr, "nil", 3) == 0)) {
1567 0 : nbytes = blobsize(0);
1568 0 : if (*l < nbytes || *val == NULL) {
1569 0 : GDKfree(*val);
1570 0 : if ((*val = GDKmalloc(nbytes)) == NULL)
1571 : return -1;
1572 : }
1573 0 : **val = blob_nil;
1574 0 : return strNil(instr) ? 1 : 3;
1575 : }
1576 :
1577 : /* count hexits and check for hexits/space */
1578 21957765 : for (i = nitems = 0; instr[i]; i++) {
1579 21955375 : if (GDKisxdigit(instr[i]))
1580 21955372 : nitems++;
1581 3 : else if (!GDKisspace(instr[i])) {
1582 3 : GDKerror("Illegal char in blob\n");
1583 3 : return -1;
1584 : }
1585 : }
1586 2390 : if (nitems % 2 != 0) {
1587 0 : GDKerror("Illegal blob length '%zu' (should be even)\n", nitems);
1588 0 : return -1;
1589 : }
1590 2390 : nitems /= 2;
1591 2390 : nbytes = blobsize(nitems);
1592 :
1593 2390 : if (*l < nbytes || *val == NULL) {
1594 2292 : GDKfree(*val);
1595 2292 : *val = GDKmalloc(nbytes);
1596 2292 : if( *val == NULL)
1597 : return -1;
1598 2292 : *l = nbytes;
1599 : }
1600 2390 : result = *val;
1601 2390 : result->nitems = nitems;
1602 :
1603 : /*
1604 : // Read the values of the blob.
1605 : */
1606 10980076 : for (i = 0; i < nitems; ++i) {
1607 10977686 : int res = 0;
1608 :
1609 10977686 : for (;;) {
1610 10977686 : if (*s >= '0' && *s <= '9') {
1611 5900546 : res = *s - '0';
1612 5077140 : } else if (*s >= 'A' && *s <= 'F') {
1613 2651908 : res = 10 + *s - 'A';
1614 2425232 : } else if (*s >= 'a' && *s <= 'f') {
1615 2425232 : res = 10 + *s - 'a';
1616 : } else {
1617 0 : assert(GDKisspace(*s));
1618 0 : s++;
1619 0 : continue;
1620 : }
1621 10977686 : break;
1622 : }
1623 10977686 : s++;
1624 10977686 : res <<= 4;
1625 10977686 : for (;;) {
1626 10977686 : if (*s >= '0' && *s <= '9') {
1627 5899417 : res += *s - '0';
1628 5078269 : } else if (*s >= 'A' && *s <= 'F') {
1629 2654281 : res += 10 + *s - 'A';
1630 2423988 : } else if (*s >= 'a' && *s <= 'f') {
1631 2423988 : res += 10 + *s - 'a';
1632 : } else {
1633 0 : assert(GDKisspace(*s));
1634 0 : s++;
1635 0 : continue;
1636 : }
1637 10977686 : break;
1638 : }
1639 10977686 : s++;
1640 :
1641 10977686 : result->data[i] = (uint8_t) res;
1642 : }
1643 2390 : while (GDKisspace(*s))
1644 0 : s++;
1645 :
1646 2390 : return (ssize_t) (s - instr);
1647 : }
1648 :
1649 : atomDesc BATatoms[MAXATOMS] = {
1650 : [TYPE_void] = {
1651 : .name = "void",
1652 : .storage = TYPE_void,
1653 : .linear = true,
1654 : #if SIZEOF_OID == SIZEOF_INT
1655 : .atomNull = (void *) &int_nil,
1656 : .atomCmp = (int (*)(const void *, const void *)) intCmp,
1657 : .atomHash = (BUN (*)(const void *)) intHash,
1658 : #else
1659 : .atomNull = (void *) &lng_nil,
1660 : .atomCmp = (int (*)(const void *, const void *)) lngCmp,
1661 : .atomHash = (BUN (*)(const void *)) lngHash,
1662 : #endif
1663 : .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) OIDfromStr,
1664 : .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) OIDtoStr,
1665 : .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) voidRead,
1666 : .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) voidWrite,
1667 : },
1668 : [TYPE_bit] = {
1669 : .name = "bit",
1670 : .storage = TYPE_bte,
1671 : .linear = true,
1672 : .size = sizeof(bit),
1673 : .atomNull = (void *) &bte_nil,
1674 : .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) bitFromStr,
1675 : .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) bitToStr,
1676 : .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) bitRead,
1677 : .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) bitWrite,
1678 : .atomCmp = (int (*)(const void *, const void *)) bteCmp,
1679 : .atomHash = (BUN (*)(const void *)) bteHash,
1680 : },
1681 : [TYPE_msk] = {
1682 : .name = "msk",
1683 : .storage = TYPE_msk,
1684 : .linear = false,
1685 : .size = 1, /* really 1/8 */
1686 : .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) mskFromStr,
1687 : .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) mskToStr,
1688 : .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) mskRead,
1689 : .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) mskWrite,
1690 : .atomCmp = (int (*)(const void *, const void *)) mskCmp,
1691 : },
1692 : [TYPE_bte] = {
1693 : .name = "bte",
1694 : .storage = TYPE_bte,
1695 : .linear = true,
1696 : .size = sizeof(bte),
1697 : .atomNull = (void *) &bte_nil,
1698 : .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) bteFromStr,
1699 : .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) bteToStr,
1700 : .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) bteRead,
1701 : .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) bteWrite,
1702 : .atomCmp = (int (*)(const void *, const void *)) bteCmp,
1703 : .atomHash = (BUN (*)(const void *)) bteHash,
1704 : },
1705 : [TYPE_sht] = {
1706 : .name = "sht",
1707 : .storage = TYPE_sht,
1708 : .linear = true,
1709 : .size = sizeof(sht),
1710 : .atomNull = (void *) &sht_nil,
1711 : .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) shtFromStr,
1712 : .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) shtToStr,
1713 : .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) shtRead,
1714 : .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) shtWrite,
1715 : .atomCmp = (int (*)(const void *, const void *)) shtCmp,
1716 : .atomHash = (BUN (*)(const void *)) shtHash,
1717 : },
1718 : [TYPE_int] = {
1719 : .name = "int",
1720 : .storage = TYPE_int,
1721 : .linear = true,
1722 : .size = sizeof(int),
1723 : .atomNull = (void *) &int_nil,
1724 : .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) intFromStr,
1725 : .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) intToStr,
1726 : .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) intRead,
1727 : .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) intWrite,
1728 : .atomCmp = (int (*)(const void *, const void *)) intCmp,
1729 : .atomHash = (BUN (*)(const void *)) intHash,
1730 : },
1731 : [TYPE_oid] = {
1732 : .name = "oid",
1733 : .linear = true,
1734 : .size = sizeof(oid),
1735 : #if SIZEOF_OID == SIZEOF_INT
1736 : .storage = TYPE_int,
1737 : .atomNull = (void *) &int_nil,
1738 : .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) intRead,
1739 : .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) intWrite,
1740 : .atomCmp = (int (*)(const void *, const void *)) intCmp,
1741 : .atomHash = (BUN (*)(const void *)) intHash,
1742 : #else
1743 : .storage = TYPE_lng,
1744 : .atomNull = (void *) &lng_nil,
1745 : .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) lngRead,
1746 : .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) lngWrite,
1747 : .atomCmp = (int (*)(const void *, const void *)) lngCmp,
1748 : .atomHash = (BUN (*)(const void *)) lngHash,
1749 : #endif
1750 : .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) OIDfromStr,
1751 : .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) OIDtoStr,
1752 : },
1753 : [TYPE_ptr] = {
1754 : .name = "ptr",
1755 : .storage = TYPE_ptr,
1756 : .linear = true,
1757 : .size = sizeof(void *),
1758 : .atomNull = (void *) &ptr_nil,
1759 : .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) ptrFromStr,
1760 : .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) ptrToStr,
1761 : .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) ptrRead,
1762 : .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) ptrWrite,
1763 : #if SIZEOF_VOID_P == SIZEOF_INT
1764 : .atomCmp = (int (*)(const void *, const void *)) intCmp,
1765 : .atomHash = (BUN (*)(const void *)) intHash,
1766 : #else /* SIZEOF_VOID_P == SIZEOF_LNG */
1767 : .atomCmp = (int (*)(const void *, const void *)) lngCmp,
1768 : .atomHash = (BUN (*)(const void *)) lngHash,
1769 : #endif
1770 : },
1771 : [TYPE_flt] = {
1772 : .name = "flt",
1773 : .storage = TYPE_flt,
1774 : .linear = true,
1775 : .size = sizeof(flt),
1776 : .atomNull = (void *) &flt_nil,
1777 : .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) fltFromStr,
1778 : .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) fltToStr,
1779 : .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) fltRead,
1780 : .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) fltWrite,
1781 : .atomCmp = (int (*)(const void *, const void *)) fltCmp,
1782 : .atomHash = (BUN (*)(const void *)) fltHash,
1783 : },
1784 : [TYPE_dbl] = {
1785 : .name = "dbl",
1786 : .storage = TYPE_dbl,
1787 : .linear = true,
1788 : .size = sizeof(dbl),
1789 : .atomNull = (void *) &dbl_nil,
1790 : .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) dblFromStr,
1791 : .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) dblToStr,
1792 : .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) dblRead,
1793 : .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) dblWrite,
1794 : .atomCmp = (int (*)(const void *, const void *)) dblCmp,
1795 : .atomHash = (BUN (*)(const void *)) dblHash,
1796 : },
1797 : [TYPE_lng] = {
1798 : .name = "lng",
1799 : .storage = TYPE_lng,
1800 : .linear = true,
1801 : .size = sizeof(lng),
1802 : .atomNull = (void *) &lng_nil,
1803 : .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) lngFromStr,
1804 : .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) lngToStr,
1805 : .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) lngRead,
1806 : .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) lngWrite,
1807 : .atomCmp = (int (*)(const void *, const void *)) lngCmp,
1808 : .atomHash = (BUN (*)(const void *)) lngHash,
1809 : },
1810 : #ifdef HAVE_HGE
1811 : [TYPE_hge] = {
1812 : .name = "hge",
1813 : .storage = TYPE_hge,
1814 : .linear = true,
1815 : .size = sizeof(hge),
1816 : .atomNull = (void *) &hge_nil,
1817 : .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) hgeFromStr,
1818 : .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) hgeToStr,
1819 : .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) hgeRead,
1820 : .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) hgeWrite,
1821 : .atomCmp = (int (*)(const void *, const void *)) hgeCmp,
1822 : .atomHash = (BUN (*)(const void *)) hgeHash,
1823 : },
1824 : #endif
1825 : [TYPE_date] = {
1826 : .name = "date",
1827 : .storage = TYPE_int,
1828 : .linear = true,
1829 : .size = sizeof(int),
1830 : .atomNull = (void *) &int_nil,
1831 : .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) date_fromstr,
1832 : .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) date_tostr,
1833 : .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) intRead,
1834 : .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) intWrite,
1835 : .atomCmp = (int (*)(const void *, const void *)) intCmp,
1836 : .atomHash = (BUN (*)(const void *)) intHash,
1837 : },
1838 : [TYPE_daytime] = {
1839 : .name = "daytime",
1840 : .storage = TYPE_lng,
1841 : .linear = true,
1842 : .size = sizeof(lng),
1843 : .atomNull = (void *) &lng_nil,
1844 : .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) daytime_tz_fromstr,
1845 : .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) daytime_tostr,
1846 : .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) lngRead,
1847 : .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) lngWrite,
1848 : .atomCmp = (int (*)(const void *, const void *)) lngCmp,
1849 : .atomHash = (BUN (*)(const void *)) lngHash,
1850 : },
1851 : [TYPE_timestamp] = {
1852 : .name = "timestamp",
1853 : .storage = TYPE_lng,
1854 : .linear = true,
1855 : .size = sizeof(lng),
1856 : .atomNull = (void *) &lng_nil,
1857 : .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) timestamp_fromstr,
1858 : .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) timestamp_tostr,
1859 : .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) lngRead,
1860 : .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) lngWrite,
1861 : .atomCmp = (int (*)(const void *, const void *)) lngCmp,
1862 : .atomHash = (BUN (*)(const void *)) lngHash,
1863 : },
1864 : [TYPE_uuid] = {
1865 : .name = "uuid",
1866 : .storage = TYPE_uuid,
1867 : .linear = true,
1868 : .size = sizeof(uuid),
1869 : .atomNull = (void *) &uuid_nil,
1870 : .atomFromStr = UUIDfromString,
1871 : .atomToStr = UUIDtoString,
1872 : .atomRead = UUIDread,
1873 : .atomWrite = UUIDwrite,
1874 : .atomCmp = UUIDcompare,
1875 : .atomHash = UUIDhash,
1876 : },
1877 : [TYPE_str] = {
1878 : .name = "str",
1879 : .storage = TYPE_str,
1880 : .linear = true,
1881 : .size = sizeof(var_t),
1882 : .atomNull = (void *) str_nil,
1883 : .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) strFromStr,
1884 : .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) strToStr,
1885 : .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) strRead,
1886 : .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) strWrite,
1887 : .atomCmp = (int (*)(const void *, const void *)) strCmp,
1888 : .atomHash = (BUN (*)(const void *)) strHash,
1889 : .atomPut = strPut,
1890 : .atomLen = (size_t (*)(const void *)) strLen,
1891 : .atomHeap = strHeap,
1892 : },
1893 : [TYPE_blob] = {
1894 : .name = "blob",
1895 : .storage = TYPE_blob,
1896 : .linear = true,
1897 : .size = sizeof(var_t),
1898 : .atomNull = (void *) &blob_nil,
1899 : .atomFromStr = BLOBfromstr,
1900 : .atomToStr = BLOBtostr,
1901 : .atomRead = BLOBread,
1902 : .atomWrite = BLOBwrite,
1903 : .atomCmp = BLOBcmp,
1904 : .atomHash = BLOBhash,
1905 : .atomPut = BLOBput,
1906 : .atomDel = BLOBdel,
1907 : .atomLen = BLOBlength,
1908 : .atomHeap = BLOBheap,
1909 : },
1910 : };
1911 :
1912 : int GDKatomcnt = TYPE_blob + 1;
1913 :
1914 : /*
1915 : * Sometimes a bat descriptor is loaded before the dynamic module
1916 : * defining the atom is loaded. To support this an extra set of
1917 : * unknown atoms is kept. These can be accessed via the ATOMunknown
1918 : * interface. Finding an (negative) atom index can be done via
1919 : * ATOMunknown_find, which simply adds the atom if it's not in the
1920 : * unknown set. The index can be used to find the name of an unknown
1921 : * ATOM via ATOMunknown_name.
1922 : */
1923 : static str unknown[MAXATOMS] = { NULL };
1924 :
1925 : int
1926 241 : ATOMunknown_find(const char *nme)
1927 : {
1928 241 : int i, j = 0;
1929 :
1930 : /* first try to find the atom */
1931 241 : MT_lock_set(&GDKatomLock);
1932 7428 : for (i = 1; i < MAXATOMS; i++) {
1933 7133 : if (unknown[i]) {
1934 338 : if (strcmp(unknown[i], nme) == 0) {
1935 187 : MT_lock_unset(&GDKatomLock);
1936 187 : return -i;
1937 : }
1938 6795 : } else if (j == 0)
1939 6946 : j = i;
1940 : }
1941 54 : if (j == 0) {
1942 : /* no space for new atom (shouldn't happen) */
1943 0 : MT_lock_unset(&GDKatomLock);
1944 0 : return 0;
1945 : }
1946 54 : if ((unknown[j] = GDKstrdup(nme)) == NULL) {
1947 0 : MT_lock_unset(&GDKatomLock);
1948 0 : return 0;
1949 : }
1950 54 : MT_lock_unset(&GDKatomLock);
1951 54 : return -j;
1952 : }
1953 :
1954 : const char *
1955 297 : ATOMunknown_name(int i)
1956 : {
1957 297 : assert(i < 0);
1958 297 : assert(-i < MAXATOMS);
1959 297 : assert(unknown[-i]);
1960 297 : return unknown[-i];
1961 : }
1962 :
1963 : void
1964 350 : ATOMunknown_clean(void)
1965 : {
1966 350 : int i;
1967 :
1968 350 : MT_lock_set(&GDKatomLock);
1969 754 : for (i = 1; i < MAXATOMS; i++) {
1970 404 : if(unknown[i]) {
1971 54 : GDKfree(unknown[i]);
1972 54 : unknown[i] = NULL;
1973 : } else {
1974 : break;
1975 : }
1976 : }
1977 350 : MT_lock_unset(&GDKatomLock);
1978 350 : }
|