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 220 : mskCmp(const msk *l, const msk *r)
43 : {
44 220 : return (*l > *r) - (*l < *r);
45 : }
46 :
47 : static int
48 451058811 : bteCmp(const bte *l, const bte *r)
49 : {
50 451058811 : return (*l > *r) - (*l < *r);
51 : }
52 :
53 : static int
54 63803535 : shtCmp(const sht *l, const sht *r)
55 : {
56 63803535 : return (*l > *r) - (*l < *r);
57 : }
58 :
59 : static int
60 1611110351 : intCmp(const int *l, const int *r)
61 : {
62 1611110351 : return (*l > *r) - (*l < *r);
63 : }
64 :
65 : static int
66 408960080 : fltCmp(const flt *l, const flt *r)
67 : {
68 408960080 : return is_flt_nil(*l) ? -!is_flt_nil(*r) : is_flt_nil(*r) ? 1 : (*l > *r) - (*l < *r);
69 : }
70 :
71 : static int
72 2068904210 : lngCmp(const lng *l, const lng *r)
73 : {
74 2068904210 : return (*l > *r) - (*l < *r);
75 : }
76 :
77 : #ifdef HAVE_HGE
78 : static int
79 143308522 : hgeCmp(const hge *l, const hge *r)
80 : {
81 143308522 : return (*l > *r) - (*l < *r);
82 : }
83 : #endif
84 :
85 : static int
86 43277419 : dblCmp(const dbl *l, const dbl *r)
87 : {
88 43277419 : 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 1136323 : intHash(const int *v)
109 : {
110 1136323 : return (BUN) mix_int(*(const unsigned int *) v);
111 : }
112 :
113 : static BUN
114 867 : lngHash(const lng *v)
115 : {
116 867 : 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 151947 : fltHash(const flt *v)
129 : {
130 151947 : if (is_flt_nil(*v))
131 : return (BUN) mix_int(GDK_int_min);
132 151812 : if (*v == 0)
133 : return (BUN) mix_int(0);
134 147834 : return (BUN) mix_int(*(const unsigned int *) v);
135 : }
136 :
137 : static BUN
138 40756 : dblHash(const dbl *v)
139 : {
140 40756 : if (is_dbl_nil(*v))
141 : return (BUN) mix_lng(GDK_lng_min);
142 38862 : if (*v == 0)
143 : return (BUN) mix_lng(0);
144 33520 : 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 3928 : ATOMallocate(const char *id)
189 : {
190 3928 : int t;
191 :
192 3928 : if (strlen(id) >= IDLENGTH) {
193 0 : GDKerror("name too long");
194 0 : return int_nil;
195 : }
196 :
197 3928 : MT_lock_set(&GDKatomLock);
198 3928 : t = ATOMindex(id);
199 3928 : if (t < 0) {
200 3928 : t = -t;
201 3928 : if (t == GDKatomcnt) {
202 3928 : if (GDKatomcnt == MAXATOMS) {
203 0 : MT_lock_unset(&GDKatomLock);
204 0 : GDKerror("too many types");
205 0 : return int_nil;
206 : }
207 3928 : GDKatomcnt++;
208 : }
209 3928 : BATatoms[t] = (atomDesc) {
210 : .size = sizeof(int), /* default */
211 : .linear = true, /* default */
212 : .storage = t, /* default */
213 : };
214 3928 : strcpy(BATatoms[t].name, id);
215 : }
216 3928 : MT_lock_unset(&GDKatomLock);
217 3928 : return t;
218 : }
219 :
220 : int
221 65022 : ATOMindex(const char *nme)
222 : {
223 65022 : int t, j = GDKatomcnt;
224 :
225 774879 : for (t = 0; t < GDKatomcnt; t++) {
226 770363 : if (!BATatoms[t].name[0]) {
227 0 : if (j == GDKatomcnt)
228 709857 : j = t;
229 770363 : } else if (strcmp(nme, BATatoms[t].name) == 0) {
230 60506 : return t;
231 : }
232 :
233 : }
234 4516 : return -j;
235 : }
236 :
237 : const char *
238 405798 : ATOMname(int t)
239 : {
240 405798 : return t >= 0 && t < GDKatomcnt && *BATatoms[t].name ? BATatoms[t].name : "null";
241 : }
242 :
243 : bool
244 244055 : ATOMisdescendant(int tpe, int parent)
245 : {
246 244055 : int cur = -1;
247 :
248 495465 : while (cur != tpe) {
249 251410 : cur = tpe;
250 251410 : if (cur == parent)
251 : return true;
252 251410 : 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 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 7266958 : ATOMlen(int t, const void *src)
299 : {
300 7266958 : size_t (*l)(const void *) = BATatoms[t].atomLen;
301 :
302 7266958 : return l ? (*l) (src) : ATOMsize(t);
303 : }
304 :
305 : gdk_return
306 856525 : ATOMheap(int t, Heap *hp, size_t cap)
307 : {
308 856525 : gdk_return (*h) (Heap *, size_t) = BATatoms[t].atomHeap;
309 :
310 856525 : if (h) {
311 856525 : 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 717 : ATOMprint(int t, const void *p, stream *s)
324 : {
325 717 : ssize_t (*tostr) (char **, size_t *, const void *, bool);
326 717 : ssize_t res;
327 :
328 1434 : if (p && t >= 0 && t < GDKatomcnt && (tostr = BATatoms[t].atomToStr)) {
329 717 : size_t sz;
330 :
331 717 : if (t < TYPE_date) {
332 247 : char buf[dblStrlen], *addr = buf; /* use memory from stack */
333 :
334 247 : sz = dblStrlen;
335 247 : res = (*tostr) (&addr, &sz, p, true);
336 247 : if (res > 0)
337 247 : 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 717 : if (res < 0)
351 0 : GDKsyserror("ATOMprint: write failure\n");
352 717 : return (int) res;
353 : }
354 :
355 :
356 : char *
357 27907 : ATOMformat(int t, const void *p)
358 : {
359 27907 : ssize_t (*tostr) (char **, size_t *, const void *, bool);
360 :
361 27907 : if (p && 0 <= t && t < GDKatomcnt && (tostr = BATatoms[t].atomToStr)) {
362 27917 : size_t sz = 0;
363 27917 : char *buf = NULL;
364 27917 : ssize_t res = (*tostr) (&buf, &sz, p, true);
365 27925 : if (res < 0 && buf) {
366 0 : GDKfree(buf);
367 0 : buf = NULL;
368 : }
369 27925 : return buf;
370 : }
371 0 : return GDKstrdup("nil");
372 : }
373 :
374 : ptr
375 56296 : ATOMdup(int t, const void *p)
376 : {
377 56296 : size_t len = ATOMlen(t, p);
378 56296 : ptr n = GDKmalloc(len);
379 :
380 56296 : if (n)
381 56296 : memcpy(n, p, len);
382 56296 : 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 70343 : bitToStr(char **dst, size_t *len, const bit *src, bool external)
534 : {
535 70343 : atommem(6);
536 :
537 70341 : 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 70316 : if (*src) {
546 24936 : strcpy(*dst, "true");
547 24936 : return 4;
548 : }
549 45380 : strcpy(*dst, "false");
550 45380 : 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 242772764 : numFromStr(const char *src, size_t *len, void **dst, int tp, bool external)
700 : {
701 242772764 : const char *p = src;
702 242772764 : size_t sz = ATOMsize(tp);
703 : #ifdef HAVE_HGE
704 242772764 : hge base = 0;
705 : #else
706 : lng base = 0;
707 : #endif
708 242772764 : 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 242772764 : atommem(sz);
719 :
720 242772763 : if (strNil(src)) {
721 0 : memcpy(*dst, ATOMnilptr(tp), sz);
722 0 : return 1;
723 : }
724 :
725 242772861 : while (GDKisspace(*p))
726 98 : p++;
727 242772763 : if (!GDKisdigit(*p)) {
728 11602 : 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 11525 : case '-':
740 11525 : sign = -1;
741 11525 : p++;
742 11525 : break;
743 1 : case '+':
744 1 : p++;
745 1 : break;
746 : }
747 11597 : if (!GDKisdigit(*p)) {
748 77 : GDKerror("not a number");
749 77 : goto bailout;
750 : }
751 : }
752 592823400 : do {
753 592823400 : int dig = base10(*p);
754 592823400 : if (base > maxdiv[1].maxval ||
755 1 : (base == maxdiv[1].maxval && dig > maxmod10)) {
756 : /* overflow */
757 0 : goto overflow;
758 : }
759 592823400 : base = 10 * base + dig;
760 592823400 : p++;
761 592823400 : } while (GDKisdigit(*p));
762 242772681 : 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 242772681 : base *= sign;
788 242772681 : switch (sz) {
789 54413 : case 1: {
790 54413 : bte **dstbte = (bte **) dst;
791 54413 : if (base < GDK_bte_min || base > GDK_bte_max) {
792 0 : goto overflow;
793 : }
794 54413 : **dstbte = (bte) base;
795 54413 : break;
796 : }
797 392351 : case 2: {
798 392351 : sht **dstsht = (sht **) dst;
799 392351 : if (base < GDK_sht_min || base > GDK_sht_max) {
800 3 : goto overflow;
801 : }
802 392348 : **dstsht = (sht) base;
803 392348 : break;
804 : }
805 238711096 : case 4: {
806 238711096 : int **dstint = (int **) dst;
807 238711096 : if (base < GDK_int_min || base > GDK_int_max) {
808 2 : goto overflow;
809 : }
810 238711094 : **dstint = (int) base;
811 238711094 : break;
812 : }
813 1912190 : case 8: {
814 1912190 : lng **dstlng = (lng **) dst;
815 : #ifdef HAVE_HGE
816 1912190 : if (base < GDK_lng_min || base > GDK_lng_max) {
817 4 : goto overflow;
818 : }
819 : #endif
820 1912186 : **dstlng = (lng) base;
821 1912186 : if (p[0] == 'L' && p[1] == 'L')
822 0 : p += 2;
823 : break;
824 : }
825 : #ifdef HAVE_HGE
826 1702631 : case 16: {
827 1702631 : hge **dsthge = (hge **) dst;
828 1702631 : **dsthge = (hge) base;
829 1702631 : if (p[0] == 'L' && p[1] == 'L')
830 0 : p += 2;
831 : break;
832 : }
833 : #endif
834 : }
835 242772788 : while (GDKisspace(*p))
836 116 : p++;
837 242772672 : 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 91 : bailout:
845 91 : memcpy(*dst, ATOMnilptr(tp), sz);
846 91 : return -1;
847 : }
848 :
849 : ssize_t
850 54053 : bteFromStr(const char *src, size_t *len, bte **dst, bool external)
851 : {
852 54053 : return numFromStr(src, len, (void **) dst, TYPE_bte, external);
853 : }
854 :
855 : ssize_t
856 385798 : shtFromStr(const char *src, size_t *len, sht **dst, bool external)
857 : {
858 385798 : return numFromStr(src, len, (void **) dst, TYPE_sht, external);
859 : }
860 :
861 : ssize_t
862 227665246 : intFromStr(const char *src, size_t *len, int **dst, bool external)
863 : {
864 227665246 : return numFromStr(src, len, (void **) dst, TYPE_int, external);
865 : }
866 :
867 : ssize_t
868 1912322 : lngFromStr(const char *src, size_t *len, lng **dst, bool external)
869 : {
870 1912322 : return numFromStr(src, len, (void **) dst, TYPE_lng, external);
871 : }
872 :
873 : #ifdef HAVE_HGE
874 : ssize_t
875 1701997 : hgeFromStr(const char *src, size_t *len, hge **dst, bool external)
876 : {
877 1701997 : 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 125519 : mskWrite(const msk *a, stream *s, size_t cnt)
908 : {
909 125519 : if (cnt == 0)
910 : return GDK_SUCCEED;
911 125519 : if (cnt == 1)
912 125519 : return mnstr_writeBte(s, (int8_t) *a) ? GDK_SUCCEED : GDK_FAIL;
913 : return GDK_FAIL;
914 : }
915 :
916 : static void *
917 123036 : mskRead(msk *A, size_t *dstlen, stream *s, size_t cnt)
918 : {
919 123036 : int8_t v;
920 123036 : msk *a = A;
921 123036 : if (cnt != 1)
922 : return NULL;
923 123036 : if (a == NULL || *dstlen == 0) {
924 0 : if ((a = GDKrealloc(a, 1)) == NULL)
925 : return NULL;
926 0 : *dstlen = 1;
927 : }
928 123036 : if (mnstr_readBte(s, &v) != 1) {
929 0 : if (a != A)
930 0 : GDKfree(a);
931 0 : return NULL;
932 : }
933 123036 : *a = v != 0;
934 123036 : return a;
935 : }
936 :
937 7093 : atom_io(bit, Bte, bte)
938 :
939 42944 : atomtostr(bte, "%hhd", )
940 255968 : atom_io(bte, Bte, bte)
941 :
942 1072916 : atomtostr(sht, "%hd", )
943 8263 : atom_io(sht, Sht, sht)
944 :
945 15249425 : atomtostr(int, "%d", )
946 222488 : atom_io(int, Int, int)
947 :
948 163411 : atomtostr(lng, LLFMT, )
949 18806 : 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 3279 : hgeToStr(char **dst, size_t *len, const hge *src, bool external)
957 : {
958 3279 : atommem(hgeStrlen);
959 3279 : 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 3278 : if ((hge) GDK_lng_min <= *src && *src <= (hge) GDK_lng_max) {
970 3161 : lng s = (lng) *src;
971 3161 : 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 257200 : dblFromStr(const char *src, size_t *len, dbl **dst, bool external)
1039 : {
1040 257200 : const char *p = src;
1041 257200 : ssize_t n = 0;
1042 257200 : double d;
1043 :
1044 : /* alloc memory */
1045 257200 : atommem(sizeof(dbl));
1046 :
1047 257200 : if (strNil(src)) {
1048 0 : **dst = dbl_nil;
1049 0 : return 1;
1050 : }
1051 :
1052 257319 : while (GDKisspace(*p))
1053 119 : p++;
1054 257200 : 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 257200 : char *pe;
1065 257200 : errno = 0;
1066 257200 : d = strtod(p, &pe);
1067 283142 : if (p == pe)
1068 : p = src; /* nothing converted */
1069 : else
1070 283108 : p = pe;
1071 283142 : n = (ssize_t) (p - src);
1072 283142 : if (n == 0 || (errno == ERANGE && (d < -1 || d > 1))
1073 283100 : || !isfinite(d) /* no NaN or Infinite */
1074 : ) {
1075 104 : GDKerror("overflow or not a number\n");
1076 104 : return -1;
1077 : } else {
1078 283088 : while (src[n] && GDKisspace(src[n]))
1079 50 : n++;
1080 283038 : **dst = (dbl) d;
1081 : }
1082 : }
1083 : return n;
1084 : }
1085 :
1086 : ssize_t
1087 13941 : dblToStr(char **dst, size_t *len, const dbl *src, bool external)
1088 : {
1089 13941 : int i;
1090 :
1091 13941 : atommem(dblStrlen);
1092 13941 : 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 50318 : for (i = 4; i < 18; i++) {
1101 50317 : snprintf(*dst, *len, "%.*g", i, *src);
1102 50317 : if (strtod(*dst, NULL) == *src)
1103 : break;
1104 : }
1105 13932 : return (ssize_t) strlen(*dst);
1106 : }
1107 :
1108 767 : atom_io(dbl, Lng, lng)
1109 :
1110 : ssize_t
1111 1829051 : fltFromStr(const char *src, size_t *len, flt **dst, bool external)
1112 : {
1113 1829051 : const char *p = src;
1114 1829051 : ssize_t n = 0;
1115 1829051 : float f;
1116 :
1117 : /* alloc memory */
1118 1829051 : atommem(sizeof(flt));
1119 :
1120 1829051 : if (strNil(src)) {
1121 0 : **dst = flt_nil;
1122 0 : return 1;
1123 : }
1124 :
1125 1829116 : while (GDKisspace(*p))
1126 65 : p++;
1127 1829051 : if (external && strncmp(p, "nil", 3) == 0) {
1128 0 : **dst = flt_nil;
1129 0 : p += 3;
1130 0 : n = (ssize_t) (p - src);
1131 : } else {
1132 : /* on overflow, strtof returns HUGE_VALF and sets
1133 : * errno to ERANGE; on underflow, it returns a value
1134 : * whose magnitude is no greater than the smallest
1135 : * normalized float, and may or may not set errno to
1136 : * ERANGE. We accept underflow, but not overflow. */
1137 1829051 : char *pe;
1138 1829051 : errno = 0;
1139 1829051 : f = strtof(p, &pe);
1140 1834550 : if (p == pe)
1141 : p = src; /* nothing converted */
1142 : else
1143 1834542 : p = pe;
1144 1834550 : n = (ssize_t) (p - src);
1145 1834550 : if (n == 0 || (errno == ERANGE && (f < -1 || f > 1))
1146 1834534 : || !isfinite(f) /* no NaN or infinite */) {
1147 58 : GDKerror("overflow or not a number\n");
1148 58 : return -1;
1149 : } else {
1150 1834531 : while (src[n] && GDKisspace(src[n]))
1151 39 : n++;
1152 1834492 : if (f == -0)
1153 6552 : f = 0;
1154 1834492 : **dst = (flt) f;
1155 : }
1156 : }
1157 : return n;
1158 : }
1159 :
1160 : ssize_t
1161 1864 : fltToStr(char **dst, size_t *len, const flt *src, bool external)
1162 : {
1163 1864 : int i;
1164 :
1165 1864 : atommem(fltStrlen);
1166 1864 : if (is_flt_nil(*src)) {
1167 5 : if (external) {
1168 5 : strcpy(*dst, "nil");
1169 5 : return 3;
1170 : }
1171 0 : strcpy(*dst, str_nil);
1172 0 : return 1;
1173 : }
1174 3332 : for (i = 4; i < 10; i++) {
1175 3332 : snprintf(*dst, *len, "%.*g", i, *src);
1176 3332 : if (strtof(*dst, NULL) == *src)
1177 : break;
1178 : }
1179 1859 : return (ssize_t) strlen(*dst);
1180 : }
1181 :
1182 217 : atom_io(flt, Int, int)
1183 :
1184 :
1185 : /*
1186 : * String conversion routines.
1187 : */
1188 : ssize_t
1189 26 : OIDfromStr(const char *src, size_t *len, oid **dst, bool external)
1190 : {
1191 : #if SIZEOF_OID == SIZEOF_INT
1192 : int ui = 0, *uip = &ui;
1193 : #else
1194 26 : lng ui = 0, *uip = &ui;
1195 : #endif
1196 26 : size_t l = sizeof(ui);
1197 26 : ssize_t pos = 0;
1198 26 : const char *p = src;
1199 :
1200 26 : atommem(sizeof(oid));
1201 :
1202 26 : **dst = oid_nil;
1203 26 : if (strNil(src))
1204 : return 1;
1205 :
1206 26 : while (GDKisspace(*p))
1207 0 : p++;
1208 :
1209 26 : if (external && strncmp(p, "nil", 3) == 0)
1210 0 : return (ssize_t) (p - src) + 3;
1211 :
1212 26 : if (*p >= '0' && *p <= '9') {
1213 : #if SIZEOF_OID == SIZEOF_INT
1214 : pos = intFromStr(p, &l, &uip, external);
1215 : #else
1216 25 : pos = lngFromStr(p, &l, &uip, external);
1217 : #endif
1218 25 : if (pos < 0)
1219 : return pos;
1220 25 : if (p[pos] == '@') {
1221 7 : pos++;
1222 14 : while (p[pos] >= '0' && p[pos] <= '9')
1223 7 : pos++;
1224 : }
1225 25 : if (ui >= 0) {
1226 25 : **dst = ui;
1227 : }
1228 25 : p += pos;
1229 : } else {
1230 1 : GDKerror("not an OID\n");
1231 1 : return -1;
1232 : }
1233 25 : while (GDKisspace(*p))
1234 0 : p++;
1235 25 : return (ssize_t) (p - src);
1236 : }
1237 :
1238 : ssize_t
1239 4216 : OIDtoStr(char **dst, size_t *len, const oid *src, bool external)
1240 : {
1241 4216 : atommem(oidStrlen);
1242 :
1243 4216 : if (is_oid_nil(*src)) {
1244 16 : if (external) {
1245 16 : strcpy(*dst, "nil");
1246 16 : return 3;
1247 : }
1248 0 : strcpy(*dst, str_nil);
1249 0 : return 1;
1250 : }
1251 4200 : return snprintf(*dst, *len, OIDFMT "@0", *src);
1252 : }
1253 :
1254 : static int
1255 4186138 : UUIDcompare(const void *L, const void *R)
1256 : {
1257 4186138 : const uuid *l = L, *r = R;
1258 4186138 : if (is_uuid_nil(*r))
1259 441685 : return !is_uuid_nil(*l);
1260 3744453 : if (is_uuid_nil(*l))
1261 : return -1;
1262 401257 : return memcmp(l->u, r->u, UUID_SIZE);
1263 : }
1264 :
1265 : static ssize_t
1266 278 : UUIDfromString(const char *svalue, size_t *len, void **RETVAL, bool external)
1267 : {
1268 278 : uuid **retval = (uuid **) RETVAL;
1269 278 : const char *s = svalue;
1270 :
1271 278 : if (*len < UUID_SIZE || *retval == NULL) {
1272 54 : GDKfree(*retval);
1273 54 : if ((*retval = GDKmalloc(UUID_SIZE)) == NULL)
1274 : return -1;
1275 54 : *len = UUID_SIZE;
1276 : }
1277 278 : if (external && strcmp(svalue, "nil") == 0) {
1278 0 : **retval = uuid_nil;
1279 0 : return 3;
1280 : }
1281 278 : if (strNil(svalue)) {
1282 33 : **retval = uuid_nil;
1283 33 : return 1;
1284 : }
1285 247 : while (GDKisspace(*s))
1286 2 : s++;
1287 : /* we don't use uuid_parse since we accept UUIDs without hyphens */
1288 : uuid u;
1289 3371 : for (int i = 0, j = 0; i < UUID_SIZE; i++) {
1290 : /* on select locations we allow a '-' in the source string */
1291 3176 : if (j == 8 || j == 12 || j == 16 || j == 20) {
1292 781 : if (*s == '-')
1293 728 : s++;
1294 : }
1295 3176 : if (*s >= '0' && *s <= '9')
1296 1607 : u.u[i] = *s - '0';
1297 1569 : else if ('a' <= *s && *s <= 'f')
1298 1135 : u.u[i] = *s - 'a' + 10;
1299 434 : else if ('A' <= *s && *s <= 'F')
1300 402 : u.u[i] = *s - 'A' + 10;
1301 : else
1302 32 : goto bailout;
1303 3144 : s++;
1304 3144 : j++;
1305 3144 : u.u[i] <<= 4;
1306 3144 : if (*s >= '0' && *s <= '9')
1307 1514 : u.u[i] |= *s - '0';
1308 1630 : else if ('a' <= *s && *s <= 'f')
1309 1260 : u.u[i] |= *s - 'a' + 10;
1310 370 : else if ('A' <= *s && *s <= 'F')
1311 352 : u.u[i] |= *s - 'A' + 10;
1312 : else
1313 18 : goto bailout;
1314 3126 : s++;
1315 3126 : j++;
1316 : }
1317 201 : while (GDKisspace(*s))
1318 6 : s++;
1319 195 : if (*s != 0)
1320 12 : goto bailout;
1321 183 : **retval = u;
1322 183 : return (ssize_t) (s - svalue);
1323 :
1324 62 : bailout:
1325 62 : **retval = uuid_nil;
1326 62 : return -1;
1327 : }
1328 :
1329 : static BUN
1330 0 : UUIDhash(const void *v)
1331 : {
1332 0 : return mix_uuid((const uuid *) v);
1333 : }
1334 :
1335 : static void *
1336 22 : UUIDread(void *U, size_t *dstlen, stream *s, size_t cnt)
1337 : {
1338 22 : uuid *u = U;
1339 22 : if (u == NULL || *dstlen < cnt * sizeof(uuid)) {
1340 0 : if ((u = GDKrealloc(u, cnt * sizeof(uuid))) == NULL)
1341 : return NULL;
1342 0 : *dstlen = cnt * sizeof(uuid);
1343 : }
1344 22 : if (mnstr_read(s, u, UUID_SIZE, cnt) < (ssize_t) cnt) {
1345 0 : if (u != U)
1346 0 : GDKfree(u);
1347 0 : return NULL;
1348 : }
1349 : return u;
1350 : }
1351 :
1352 : static gdk_return
1353 23 : UUIDwrite(const void *u, stream *s, size_t cnt)
1354 : {
1355 23 : return mnstr_write(s, u, UUID_SIZE, cnt) ? GDK_SUCCEED : GDK_FAIL;
1356 : }
1357 :
1358 : static ssize_t
1359 1740861 : UUIDtoString(str *retval, size_t *len, const void *VALUE, bool external)
1360 : {
1361 1740861 : const uuid *value = VALUE;
1362 1740861 : if (*len <= UUID_STRLEN || *retval == NULL) {
1363 105 : if (*retval)
1364 0 : GDKfree(*retval);
1365 105 : if ((*retval = GDKmalloc(UUID_STRLEN + 1)) == NULL)
1366 : return -1;
1367 0 : *len = UUID_STRLEN + 1;
1368 : }
1369 1739483 : if (is_uuid_nil(*value)) {
1370 0 : if (external) {
1371 0 : assert(*len >= strlen("nil") + 1);
1372 0 : strcpy(*retval, "nil");
1373 0 : return 3;
1374 : }
1375 0 : assert(*len >= strlen(str_nil) + 1);
1376 0 : strcpy(*retval, str_nil);
1377 0 : return 1;
1378 : }
1379 1739483 : snprintf(*retval, *len,
1380 : "%02x%02x%02x%02x-%02x%02x-%02x%02x"
1381 : "-%02x%02x-%02x%02x%02x%02x%02x%02x",
1382 1739483 : value->u[0], value->u[1], value->u[2], value->u[3],
1383 1739483 : value->u[4], value->u[5], value->u[6], value->u[7],
1384 1739483 : value->u[8], value->u[9], value->u[10], value->u[11],
1385 1739483 : value->u[12], value->u[13], value->u[14], value->u[15]);
1386 1739483 : assert(strlen(*retval) == UUID_STRLEN);
1387 : return UUID_STRLEN;
1388 : }
1389 :
1390 : static const blob blob_nil = {
1391 : ~(size_t) 0
1392 : };
1393 :
1394 : size_t
1395 14806097 : blobsize(size_t nitems)
1396 : {
1397 14806097 : if (nitems == ~(size_t) 0)
1398 5334264 : nitems = 0;
1399 14806097 : assert(offsetof(blob, data) + nitems <= VAR_MAX);
1400 14806097 : return (size_t) (offsetof(blob, data) + nitems);
1401 : }
1402 :
1403 : static int
1404 15153248 : BLOBcmp(const void *L, const void *R)
1405 : {
1406 15153248 : const blob *l = L, *r = R;
1407 15153248 : int c;
1408 15153248 : if (is_blob_nil(r))
1409 11036561 : return !is_blob_nil(l);
1410 4116687 : if (is_blob_nil(l))
1411 : return -1;
1412 6620 : if (l->nitems < r->nitems) {
1413 2569 : c = memcmp(l->data, r->data, l->nitems);
1414 2569 : if (c == 0)
1415 2273 : return -1;
1416 : } else {
1417 4051 : c = memcmp(l->data, r->data, r->nitems);
1418 4051 : if (c == 0)
1419 3518 : return l->nitems > r->nitems;
1420 : }
1421 : return c;
1422 : }
1423 :
1424 : static void
1425 35 : BLOBdel(Heap *h, var_t *idx)
1426 : {
1427 35 : HEAP_free(h, *idx);
1428 35 : }
1429 :
1430 : static BUN
1431 11280 : BLOBhash(const void *B)
1432 : {
1433 11280 : const blob *b = B;
1434 11280 : return (BUN) b->nitems;
1435 : }
1436 :
1437 : static void *
1438 65 : BLOBread(void *A, size_t *dstlen, stream *s, size_t cnt)
1439 : {
1440 65 : blob *a = A;
1441 65 : int len;
1442 :
1443 65 : (void) cnt;
1444 65 : assert(cnt == 1);
1445 65 : if (mnstr_readInt(s, &len) != 1 || len < 0)
1446 : return NULL;
1447 65 : if (a == NULL || *dstlen < (size_t) len) {
1448 0 : if ((a = GDKrealloc(a, (size_t) len)) == NULL)
1449 : return NULL;
1450 0 : *dstlen = (size_t) len;
1451 : }
1452 65 : if (mnstr_read(s, (char *) a, (size_t) len, 1) != 1) {
1453 0 : GDKfree(a);
1454 0 : return NULL;
1455 : }
1456 : return a;
1457 : }
1458 :
1459 : static gdk_return
1460 65 : BLOBwrite(const void *A, stream *s, size_t cnt)
1461 : {
1462 65 : const blob *a = A;
1463 65 : size_t len = blobsize(a->nitems);
1464 :
1465 65 : (void) cnt;
1466 65 : assert(cnt == 1);
1467 130 : if (!mnstr_writeInt(s, (int) len) /* 64bit: check for overflow */ ||
1468 65 : mnstr_write(s, a, len, 1) < 0)
1469 0 : return GDK_FAIL;
1470 : return GDK_SUCCEED;
1471 : }
1472 :
1473 : static size_t
1474 1468 : BLOBlength(const void *P)
1475 : {
1476 1468 : const blob *p = P;
1477 1468 : size_t l = blobsize(p->nitems); /* 64bit: check for overflow */
1478 1468 : assert(l <= (size_t) GDK_int_max);
1479 1468 : return l;
1480 : }
1481 :
1482 : static gdk_return
1483 891 : BLOBheap(Heap *heap, size_t capacity)
1484 : {
1485 891 : return HEAP_initialize(heap, capacity, 0, (int) sizeof(var_t));
1486 : }
1487 :
1488 : static var_t
1489 7401085 : BLOBput(BAT *b, var_t *bun, const void *VAL)
1490 : {
1491 7401085 : const blob *val = VAL;
1492 7401085 : char *base = NULL;
1493 :
1494 7401085 : *bun = HEAP_malloc(b, blobsize(val->nitems));
1495 7401085 : base = b->tvheap->base;
1496 7401085 : if (*bun != (var_t) -1) {
1497 7401084 : memcpy(&base[*bun], val, blobsize(val->nitems));
1498 7401084 : b->tvheap->dirty = true;
1499 : }
1500 7401085 : return *bun;
1501 : }
1502 :
1503 : static ssize_t
1504 400 : BLOBtostr(str *tostr, size_t *l, const void *P, bool external)
1505 : {
1506 400 : static const char hexit[] = "0123456789ABCDEF";
1507 400 : const blob *p = P;
1508 400 : char *s;
1509 400 : size_t i;
1510 400 : size_t expectedlen;
1511 :
1512 400 : if (is_blob_nil(p))
1513 3 : expectedlen = external ? 4 : 2;
1514 : else
1515 397 : expectedlen = p->nitems * 2 + 1;
1516 400 : if (*l < expectedlen || *tostr == NULL) {
1517 55 : GDKfree(*tostr);
1518 55 : *tostr = GDKmalloc(expectedlen);
1519 55 : if (*tostr == NULL)
1520 : return -1;
1521 55 : *l = expectedlen;
1522 : }
1523 400 : if (is_blob_nil(p)) {
1524 3 : if (external) {
1525 3 : strcpy(*tostr, "nil");
1526 3 : return 3;
1527 : }
1528 0 : strcpy(*tostr, str_nil);
1529 0 : return 1;
1530 : }
1531 :
1532 397 : s = *tostr;
1533 :
1534 25857594 : for (i = 0; i < p->nitems; i++) {
1535 25857197 : int val = (p->data[i] >> 4) & 15;
1536 :
1537 25857197 : *s++ = hexit[val];
1538 25857197 : val = p->data[i] & 15;
1539 25857197 : *s++ = hexit[val];
1540 : }
1541 397 : *s = '\0';
1542 397 : return (ssize_t) (s - *tostr);
1543 : }
1544 :
1545 : static ssize_t
1546 2391 : BLOBfromstr(const char *instr, size_t *l, void **VAL, bool external)
1547 : {
1548 2391 : blob **val = (blob **) VAL;
1549 2391 : size_t i;
1550 2391 : size_t nitems;
1551 2391 : size_t nbytes;
1552 2391 : blob *result;
1553 2391 : const char *s = instr;
1554 :
1555 4782 : if (strNil(instr) || (external && strncmp(instr, "nil", 3) == 0)) {
1556 0 : nbytes = blobsize(0);
1557 0 : if (*l < nbytes || *val == NULL) {
1558 0 : GDKfree(*val);
1559 0 : if ((*val = GDKmalloc(nbytes)) == NULL)
1560 : return -1;
1561 : }
1562 0 : **val = blob_nil;
1563 0 : return strNil(instr) ? 1 : 3;
1564 : }
1565 :
1566 : /* count hexits and check for hexits/space */
1567 21957755 : for (i = nitems = 0; instr[i]; i++) {
1568 21955367 : if (GDKisxdigit(instr[i]))
1569 21955364 : nitems++;
1570 3 : else if (!GDKisspace(instr[i])) {
1571 3 : GDKerror("Illegal char in blob\n");
1572 3 : return -1;
1573 : }
1574 : }
1575 2388 : if (nitems % 2 != 0) {
1576 0 : GDKerror("Illegal blob length '%zu' (should be even)\n", nitems);
1577 0 : return -1;
1578 : }
1579 2388 : nitems /= 2;
1580 2388 : nbytes = blobsize(nitems);
1581 :
1582 2388 : if (*l < nbytes || *val == NULL) {
1583 2290 : GDKfree(*val);
1584 2290 : *val = GDKmalloc(nbytes);
1585 2292 : if( *val == NULL)
1586 : return -1;
1587 2292 : *l = nbytes;
1588 : }
1589 2390 : result = *val;
1590 2390 : result->nitems = nitems;
1591 :
1592 : /*
1593 : // Read the values of the blob.
1594 : */
1595 10980074 : for (i = 0; i < nitems; ++i) {
1596 10977684 : char res = 0;
1597 :
1598 10977684 : for (;;) {
1599 10977684 : if (*s >= '0' && *s <= '9') {
1600 5900548 : res = *s - '0';
1601 5077136 : } else if (*s >= 'A' && *s <= 'F') {
1602 2651904 : res = 10 + *s - 'A';
1603 2425232 : } else if (*s >= 'a' && *s <= 'f') {
1604 2425232 : res = 10 + *s - 'a';
1605 : } else {
1606 0 : assert(GDKisspace(*s));
1607 0 : s++;
1608 0 : continue;
1609 : }
1610 10977684 : break;
1611 : }
1612 10977684 : s++;
1613 10977684 : res <<= 4;
1614 10977684 : for (;;) {
1615 10977684 : if (*s >= '0' && *s <= '9') {
1616 5899417 : res += *s - '0';
1617 5078267 : } else if (*s >= 'A' && *s <= 'F') {
1618 2654279 : res += 10 + *s - 'A';
1619 2423988 : } else if (*s >= 'a' && *s <= 'f') {
1620 2423988 : res += 10 + *s - 'a';
1621 : } else {
1622 0 : assert(GDKisspace(*s));
1623 0 : s++;
1624 0 : continue;
1625 : }
1626 10977684 : break;
1627 : }
1628 10977684 : s++;
1629 :
1630 10977684 : result->data[i] = res;
1631 : }
1632 2390 : while (GDKisspace(*s))
1633 0 : s++;
1634 :
1635 2390 : return (ssize_t) (s - instr);
1636 : }
1637 :
1638 : atomDesc BATatoms[MAXATOMS] = {
1639 : [TYPE_void] = {
1640 : .name = "void",
1641 : .storage = TYPE_void,
1642 : .linear = true,
1643 : #if SIZEOF_OID == SIZEOF_INT
1644 : .atomNull = (void *) &int_nil,
1645 : .atomCmp = (int (*)(const void *, const void *)) intCmp,
1646 : .atomHash = (BUN (*)(const void *)) intHash,
1647 : #else
1648 : .atomNull = (void *) &lng_nil,
1649 : .atomCmp = (int (*)(const void *, const void *)) lngCmp,
1650 : .atomHash = (BUN (*)(const void *)) lngHash,
1651 : #endif
1652 : .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) OIDfromStr,
1653 : .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) OIDtoStr,
1654 : .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) voidRead,
1655 : .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) voidWrite,
1656 : },
1657 : [TYPE_bit] = {
1658 : .name = "bit",
1659 : .storage = TYPE_bte,
1660 : .linear = true,
1661 : .size = sizeof(bit),
1662 : .atomNull = (void *) &bte_nil,
1663 : .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) bitFromStr,
1664 : .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) bitToStr,
1665 : .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) bitRead,
1666 : .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) bitWrite,
1667 : .atomCmp = (int (*)(const void *, const void *)) bteCmp,
1668 : .atomHash = (BUN (*)(const void *)) bteHash,
1669 : },
1670 : [TYPE_msk] = {
1671 : .name = "msk",
1672 : .storage = TYPE_msk,
1673 : .linear = false,
1674 : .size = 1, /* really 1/8 */
1675 : .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) mskFromStr,
1676 : .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) mskToStr,
1677 : .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) mskRead,
1678 : .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) mskWrite,
1679 : .atomCmp = (int (*)(const void *, const void *)) mskCmp,
1680 : },
1681 : [TYPE_bte] = {
1682 : .name = "bte",
1683 : .storage = TYPE_bte,
1684 : .linear = true,
1685 : .size = sizeof(bte),
1686 : .atomNull = (void *) &bte_nil,
1687 : .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) bteFromStr,
1688 : .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) bteToStr,
1689 : .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) bteRead,
1690 : .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) bteWrite,
1691 : .atomCmp = (int (*)(const void *, const void *)) bteCmp,
1692 : .atomHash = (BUN (*)(const void *)) bteHash,
1693 : },
1694 : [TYPE_sht] = {
1695 : .name = "sht",
1696 : .storage = TYPE_sht,
1697 : .linear = true,
1698 : .size = sizeof(sht),
1699 : .atomNull = (void *) &sht_nil,
1700 : .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) shtFromStr,
1701 : .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) shtToStr,
1702 : .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) shtRead,
1703 : .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) shtWrite,
1704 : .atomCmp = (int (*)(const void *, const void *)) shtCmp,
1705 : .atomHash = (BUN (*)(const void *)) shtHash,
1706 : },
1707 : [TYPE_int] = {
1708 : .name = "int",
1709 : .storage = TYPE_int,
1710 : .linear = true,
1711 : .size = sizeof(int),
1712 : .atomNull = (void *) &int_nil,
1713 : .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) intFromStr,
1714 : .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) intToStr,
1715 : .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) intRead,
1716 : .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) intWrite,
1717 : .atomCmp = (int (*)(const void *, const void *)) intCmp,
1718 : .atomHash = (BUN (*)(const void *)) intHash,
1719 : },
1720 : [TYPE_oid] = {
1721 : .name = "oid",
1722 : .linear = true,
1723 : .size = sizeof(oid),
1724 : #if SIZEOF_OID == SIZEOF_INT
1725 : .storage = TYPE_int,
1726 : .atomNull = (void *) &int_nil,
1727 : .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) intRead,
1728 : .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) intWrite,
1729 : .atomCmp = (int (*)(const void *, const void *)) intCmp,
1730 : .atomHash = (BUN (*)(const void *)) intHash,
1731 : #else
1732 : .storage = TYPE_lng,
1733 : .atomNull = (void *) &lng_nil,
1734 : .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) lngRead,
1735 : .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) lngWrite,
1736 : .atomCmp = (int (*)(const void *, const void *)) lngCmp,
1737 : .atomHash = (BUN (*)(const void *)) lngHash,
1738 : #endif
1739 : .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) OIDfromStr,
1740 : .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) OIDtoStr,
1741 : },
1742 : [TYPE_ptr] = {
1743 : .name = "ptr",
1744 : .storage = TYPE_ptr,
1745 : .linear = true,
1746 : .size = sizeof(void *),
1747 : .atomNull = (void *) &ptr_nil,
1748 : .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) ptrFromStr,
1749 : .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) ptrToStr,
1750 : .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) ptrRead,
1751 : .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) ptrWrite,
1752 : #if SIZEOF_VOID_P == SIZEOF_INT
1753 : .atomCmp = (int (*)(const void *, const void *)) intCmp,
1754 : .atomHash = (BUN (*)(const void *)) intHash,
1755 : #else /* SIZEOF_VOID_P == SIZEOF_LNG */
1756 : .atomCmp = (int (*)(const void *, const void *)) lngCmp,
1757 : .atomHash = (BUN (*)(const void *)) lngHash,
1758 : #endif
1759 : },
1760 : [TYPE_flt] = {
1761 : .name = "flt",
1762 : .storage = TYPE_flt,
1763 : .linear = true,
1764 : .size = sizeof(flt),
1765 : .atomNull = (void *) &flt_nil,
1766 : .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) fltFromStr,
1767 : .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) fltToStr,
1768 : .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) fltRead,
1769 : .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) fltWrite,
1770 : .atomCmp = (int (*)(const void *, const void *)) fltCmp,
1771 : .atomHash = (BUN (*)(const void *)) fltHash,
1772 : },
1773 : [TYPE_dbl] = {
1774 : .name = "dbl",
1775 : .storage = TYPE_dbl,
1776 : .linear = true,
1777 : .size = sizeof(dbl),
1778 : .atomNull = (void *) &dbl_nil,
1779 : .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) dblFromStr,
1780 : .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) dblToStr,
1781 : .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) dblRead,
1782 : .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) dblWrite,
1783 : .atomCmp = (int (*)(const void *, const void *)) dblCmp,
1784 : .atomHash = (BUN (*)(const void *)) dblHash,
1785 : },
1786 : [TYPE_lng] = {
1787 : .name = "lng",
1788 : .storage = TYPE_lng,
1789 : .linear = true,
1790 : .size = sizeof(lng),
1791 : .atomNull = (void *) &lng_nil,
1792 : .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) lngFromStr,
1793 : .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) lngToStr,
1794 : .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) lngRead,
1795 : .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) lngWrite,
1796 : .atomCmp = (int (*)(const void *, const void *)) lngCmp,
1797 : .atomHash = (BUN (*)(const void *)) lngHash,
1798 : },
1799 : #ifdef HAVE_HGE
1800 : [TYPE_hge] = {
1801 : .name = "hge",
1802 : .storage = TYPE_hge,
1803 : .linear = true,
1804 : .size = sizeof(hge),
1805 : .atomNull = (void *) &hge_nil,
1806 : .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) hgeFromStr,
1807 : .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) hgeToStr,
1808 : .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) hgeRead,
1809 : .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) hgeWrite,
1810 : .atomCmp = (int (*)(const void *, const void *)) hgeCmp,
1811 : .atomHash = (BUN (*)(const void *)) hgeHash,
1812 : },
1813 : #endif
1814 : [TYPE_date] = {
1815 : .name = "date",
1816 : .storage = TYPE_int,
1817 : .linear = true,
1818 : .size = sizeof(int),
1819 : .atomNull = (void *) &int_nil,
1820 : .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) date_fromstr,
1821 : .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) date_tostr,
1822 : .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) intRead,
1823 : .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) intWrite,
1824 : .atomCmp = (int (*)(const void *, const void *)) intCmp,
1825 : .atomHash = (BUN (*)(const void *)) intHash,
1826 : },
1827 : [TYPE_daytime] = {
1828 : .name = "daytime",
1829 : .storage = TYPE_lng,
1830 : .linear = true,
1831 : .size = sizeof(lng),
1832 : .atomNull = (void *) &lng_nil,
1833 : .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) daytime_tz_fromstr,
1834 : .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) daytime_tostr,
1835 : .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) lngRead,
1836 : .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) lngWrite,
1837 : .atomCmp = (int (*)(const void *, const void *)) lngCmp,
1838 : .atomHash = (BUN (*)(const void *)) lngHash,
1839 : },
1840 : [TYPE_timestamp] = {
1841 : .name = "timestamp",
1842 : .storage = TYPE_lng,
1843 : .linear = true,
1844 : .size = sizeof(lng),
1845 : .atomNull = (void *) &lng_nil,
1846 : .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) timestamp_fromstr,
1847 : .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) timestamp_tostr,
1848 : .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) lngRead,
1849 : .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) lngWrite,
1850 : .atomCmp = (int (*)(const void *, const void *)) lngCmp,
1851 : .atomHash = (BUN (*)(const void *)) lngHash,
1852 : },
1853 : [TYPE_uuid] = {
1854 : .name = "uuid",
1855 : .storage = TYPE_uuid,
1856 : .linear = true,
1857 : .size = sizeof(uuid),
1858 : .atomNull = (void *) &uuid_nil,
1859 : .atomFromStr = UUIDfromString,
1860 : .atomToStr = UUIDtoString,
1861 : .atomRead = UUIDread,
1862 : .atomWrite = UUIDwrite,
1863 : .atomCmp = UUIDcompare,
1864 : .atomHash = UUIDhash,
1865 : },
1866 : [TYPE_str] = {
1867 : .name = "str",
1868 : .storage = TYPE_str,
1869 : .linear = true,
1870 : .size = sizeof(var_t),
1871 : .atomNull = (void *) str_nil,
1872 : .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) strFromStr,
1873 : .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) strToStr,
1874 : .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) strRead,
1875 : .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) strWrite,
1876 : .atomCmp = (int (*)(const void *, const void *)) strCmp,
1877 : .atomHash = (BUN (*)(const void *)) strHash,
1878 : .atomPut = strPut,
1879 : .atomLen = (size_t (*)(const void *)) strLen,
1880 : .atomHeap = strHeap,
1881 : },
1882 : [TYPE_blob] = {
1883 : .name = "blob",
1884 : .storage = TYPE_blob,
1885 : .linear = true,
1886 : .size = sizeof(var_t),
1887 : .atomNull = (void *) &blob_nil,
1888 : .atomFromStr = BLOBfromstr,
1889 : .atomToStr = BLOBtostr,
1890 : .atomRead = BLOBread,
1891 : .atomWrite = BLOBwrite,
1892 : .atomCmp = BLOBcmp,
1893 : .atomHash = BLOBhash,
1894 : .atomPut = BLOBput,
1895 : .atomDel = BLOBdel,
1896 : .atomLen = BLOBlength,
1897 : .atomHeap = BLOBheap,
1898 : },
1899 : };
1900 :
1901 : int GDKatomcnt = TYPE_blob + 1;
1902 :
1903 : /*
1904 : * Sometimes a bat descriptor is loaded before the dynamic module
1905 : * defining the atom is loaded. To support this an extra set of
1906 : * unknown atoms is kept. These can be accessed via the ATOMunknown
1907 : * interface. Finding an (negative) atom index can be done via
1908 : * ATOMunknown_find, which simply adds the atom if it's not in the
1909 : * unknown set. The index can be used to find the name of an unknown
1910 : * ATOM via ATOMunknown_name.
1911 : */
1912 : static str unknown[MAXATOMS] = { NULL };
1913 :
1914 : int
1915 241 : ATOMunknown_find(const char *nme)
1916 : {
1917 241 : int i, j = 0;
1918 :
1919 : /* first try to find the atom */
1920 241 : MT_lock_set(&GDKatomLock);
1921 7428 : for (i = 1; i < MAXATOMS; i++) {
1922 7133 : if (unknown[i]) {
1923 338 : if (strcmp(unknown[i], nme) == 0) {
1924 187 : MT_lock_unset(&GDKatomLock);
1925 187 : return -i;
1926 : }
1927 6795 : } else if (j == 0)
1928 6946 : j = i;
1929 : }
1930 54 : if (j == 0) {
1931 : /* no space for new atom (shouldn't happen) */
1932 0 : MT_lock_unset(&GDKatomLock);
1933 0 : return 0;
1934 : }
1935 54 : if ((unknown[j] = GDKstrdup(nme)) == NULL) {
1936 0 : MT_lock_unset(&GDKatomLock);
1937 0 : return 0;
1938 : }
1939 54 : MT_lock_unset(&GDKatomLock);
1940 54 : return -j;
1941 : }
1942 :
1943 : const char *
1944 297 : ATOMunknown_name(int i)
1945 : {
1946 297 : assert(i < 0);
1947 297 : assert(-i < MAXATOMS);
1948 297 : assert(unknown[-i]);
1949 297 : return unknown[-i];
1950 : }
1951 :
1952 : void
1953 328 : ATOMunknown_clean(void)
1954 : {
1955 328 : int i;
1956 :
1957 328 : MT_lock_set(&GDKatomLock);
1958 710 : for (i = 1; i < MAXATOMS; i++) {
1959 382 : if(unknown[i]) {
1960 54 : GDKfree(unknown[i]);
1961 54 : unknown[i] = NULL;
1962 : } else {
1963 : break;
1964 : }
1965 : }
1966 328 : MT_lock_unset(&GDKatomLock);
1967 328 : }
|