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, 2025 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 714386432 : bteCmp(const bte *l, const bte *r)
49 : {
50 714386432 : return (*l > *r) - (*l < *r);
51 : }
52 :
53 : static int
54 60900877 : shtCmp(const sht *l, const sht *r)
55 : {
56 60900877 : return (*l > *r) - (*l < *r);
57 : }
58 :
59 : static int
60 2880197119 : intCmp(const int *l, const int *r)
61 : {
62 2880197119 : return (*l > *r) - (*l < *r);
63 : }
64 :
65 : static int
66 409742296 : fltCmp(const flt *l, const flt *r)
67 : {
68 409742296 : return is_flt_nil(*l) ? -!is_flt_nil(*r) : is_flt_nil(*r) ? 1 : (*l > *r) - (*l < *r);
69 : }
70 :
71 : static int
72 5744963081 : lngCmp(const lng *l, const lng *r)
73 : {
74 5744963081 : return (*l > *r) - (*l < *r);
75 : }
76 :
77 : #ifdef HAVE_HGE
78 : static int
79 180202342 : hgeCmp(const hge *l, const hge *r)
80 : {
81 180202342 : return (*l > *r) - (*l < *r);
82 : }
83 : #endif
84 :
85 : static int
86 45982942 : dblCmp(const dbl *l, const dbl *r)
87 : {
88 45982942 : 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 1196708 : intHash(const int *v)
109 : {
110 1196708 : 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 151585 : fltHash(const flt *v)
129 : {
130 151585 : if (is_flt_nil(*v))
131 : return (BUN) mix_int(GDK_int_min);
132 151449 : if (*v == 0)
133 : return (BUN) mix_int(0);
134 147477 : return (BUN) mix_int(*(const unsigned int *) v);
135 : }
136 :
137 : static BUN
138 42062 : dblHash(const dbl *v)
139 : {
140 42062 : if (is_dbl_nil(*v))
141 : return (BUN) mix_lng(GDK_lng_min);
142 40104 : if (*v == 0)
143 : return (BUN) mix_lng(0);
144 34761 : 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 3202 : ATOMallocate(const char *id)
189 : {
190 3202 : int t;
191 :
192 3202 : if (strlen(id) >= IDLENGTH) {
193 0 : GDKerror("name too long");
194 0 : return int_nil;
195 : }
196 :
197 3202 : MT_lock_set(&GDKatomLock);
198 3202 : t = ATOMindex(id);
199 3202 : if (t < 0) {
200 3202 : t = -t;
201 3202 : if (t == GDKatomcnt) {
202 3202 : if (GDKatomcnt == MAXATOMS) {
203 0 : MT_lock_unset(&GDKatomLock);
204 0 : GDKerror("too many types");
205 0 : return int_nil;
206 : }
207 3202 : GDKatomcnt++;
208 : }
209 3202 : BATatoms[t] = (atomDesc) {
210 : .size = sizeof(int), /* default */
211 : .linear = true, /* default */
212 : .storage = t, /* default */
213 : };
214 3202 : strcpy(BATatoms[t].name, id);
215 : }
216 3202 : MT_lock_unset(&GDKatomLock);
217 3202 : return t;
218 : }
219 :
220 : int
221 71235 : ATOMindex(const char *nme)
222 : {
223 71235 : int t, j = GDKatomcnt;
224 :
225 804570 : for (t = 0; t < GDKatomcnt; t++) {
226 800752 : if (!BATatoms[t].name[0]) {
227 0 : if (j == GDKatomcnt)
228 733335 : j = t;
229 800752 : } else if (strcmp(nme, BATatoms[t].name) == 0) {
230 67417 : return t;
231 : }
232 :
233 : }
234 3818 : return -j;
235 : }
236 :
237 : const char *
238 415081 : ATOMname(int t)
239 : {
240 415081 : return t >= 0 && t < GDKatomcnt && *BATatoms[t].name ? BATatoms[t].name : "null";
241 : }
242 :
243 : bool
244 248673 : ATOMisdescendant(int tpe, int parent)
245 : {
246 248673 : int cur = -1;
247 :
248 505270 : while (cur != tpe) {
249 256597 : cur = tpe;
250 256597 : if (cur == parent)
251 : return true;
252 256597 : tpe = ATOMstorage(tpe);
253 : }
254 : return false;
255 : }
256 :
257 :
258 : const bte bte_nil = GDK_bte_min-1;
259 : const sht sht_nil = GDK_sht_min-1;
260 : const int int_nil = GDK_int_min-1;
261 : #ifdef NAN_CANNOT_BE_USED_AS_INITIALIZER
262 : /* Definition of NAN is seriously broken on Intel compiler (at least
263 : * in some versions), so we work around it. */
264 : const union _flt_nil_t _flt_nil_ = {
265 : .l = UINT32_C(0x7FC00000)
266 : };
267 : const union _dbl_nil_t _dbl_nil_ = {
268 : .l = UINT64_C(0x7FF8000000000000)
269 : };
270 : #else
271 : const flt flt_nil = NAN;
272 : const dbl dbl_nil = NAN;
273 : #endif
274 : const lng lng_nil = GDK_lng_min-1;
275 : #ifdef HAVE_HGE
276 : const hge hge_nil = GDK_hge_min-1;
277 : #endif
278 : const oid oid_nil = (oid) 1 << (sizeof(oid) * 8 - 1);
279 : const ptr ptr_nil = NULL;
280 : const uuid uuid_nil = {0};
281 :
282 : ptr
283 22 : ATOMnil(int t)
284 : {
285 22 : const void *src = ATOMnilptr(t);
286 22 : size_t len = ATOMlen(ATOMtype(t), src);
287 23 : ptr dst = GDKmalloc(len);
288 :
289 23 : if (dst)
290 23 : memcpy(dst, src, len);
291 23 : return dst;
292 : }
293 :
294 : /*
295 : * @- Atomic ADT functions
296 : */
297 : size_t
298 7543746 : ATOMlen(int t, const void *src)
299 : {
300 7543746 : size_t (*l)(const void *) = BATatoms[t].atomLen;
301 :
302 7543746 : return l ? (*l) (src) : ATOMsize(t);
303 : }
304 :
305 : gdk_return
306 1026970 : ATOMheap(int t, Heap *hp, size_t cap)
307 : {
308 1026970 : gdk_return (*h) (Heap *, size_t) = BATatoms[t].atomHeap;
309 :
310 1026970 : if (h) {
311 1026970 : 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 27578 : ATOMformat(int t, const void *p)
358 : {
359 27578 : ssize_t (*tostr) (char **, size_t *, const void *, bool);
360 :
361 27578 : if (p && 0 <= t && t < GDKatomcnt && (tostr = BATatoms[t].atomToStr)) {
362 27589 : size_t sz = 0;
363 27589 : char *buf = NULL;
364 27589 : ssize_t res = (*tostr) (&buf, &sz, p, true);
365 27591 : if (res < 0 && buf) {
366 0 : GDKfree(buf);
367 0 : buf = NULL;
368 : }
369 27591 : return buf;
370 : }
371 0 : return GDKstrdup("nil");
372 : }
373 :
374 : ptr
375 115554 : ATOMdup(int t, const void *p)
376 : {
377 115554 : size_t len = ATOMlen(t, p);
378 115554 : ptr n = GDKmalloc(len);
379 :
380 115554 : if (n)
381 115554 : memcpy(n, p, len);
382 115554 : 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 15589 : bitFromStr(const char *src, size_t *len, bit **dst, bool external)
498 : {
499 15589 : const char *p = src;
500 :
501 15589 : 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 10271 : **dst = TRUE;
518 10271 : 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 15557 : while (GDKisspace(*p))
528 0 : p++;
529 15557 : return (ssize_t) (p - src);
530 : }
531 :
532 : ssize_t
533 70961 : bitToStr(char **dst, size_t *len, const bit *src, bool external)
534 : {
535 70961 : atommem(6);
536 :
537 70961 : 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 70936 : if (*src) {
546 25395 : strcpy(*dst, "true");
547 25395 : return 4;
548 : }
549 45541 : strcpy(*dst, "false");
550 45541 : return 5;
551 : }
552 :
553 :
554 : /*
555 : * numFromStr parses the head of the string for a number, accepting an
556 : * optional sign. The code has been prepared to continue parsing by
557 : * returning the number of characters read. Both overflow and
558 : * incorrect syntax (not a number) result in the function returning 0
559 : * and setting the destination to nil.
560 : */
561 : struct maxdiv {
562 : /* if we want to multiply a value with scale, the value must
563 : * be no larger than maxval for there to not be overflow */
564 : #ifdef HAVE_HGE
565 : hge scale, maxval;
566 : #else
567 : lng scale, maxval;
568 : #endif
569 : };
570 : static const struct maxdiv maxdiv[] = {
571 : #ifdef HAVE_HGE
572 : /* maximum hge value: 170141183460469231731687303715884105727 (2**127-1)
573 : * GCC doesn't currently support integer constants that don't
574 : * fit in 8 bytes, so we split large values up*/
575 : {(hge) LL_CONSTANT(1), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(10000000000000000000U)+ (hge) LL_CONSTANT(1687303715884105727)},
576 : {(hge) LL_CONSTANT(10), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(1000000000000000000) + (hge) LL_CONSTANT(168730371588410572)},
577 : {(hge) LL_CONSTANT(100), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(100000000000000000) + (hge) LL_CONSTANT(16873037158841057)},
578 : {(hge) LL_CONSTANT(1000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(10000000000000000) + (hge) LL_CONSTANT(1687303715884105)},
579 : {(hge) LL_CONSTANT(10000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(1000000000000000) + (hge) LL_CONSTANT(168730371588410)},
580 : {(hge) LL_CONSTANT(100000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(100000000000000) + (hge) LL_CONSTANT(16873037158841)},
581 : {(hge) LL_CONSTANT(1000000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(10000000000000) + (hge) LL_CONSTANT(1687303715884)},
582 : {(hge) LL_CONSTANT(10000000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(1000000000000) + (hge) LL_CONSTANT(168730371588)},
583 : {(hge) LL_CONSTANT(100000000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(100000000000) + (hge) LL_CONSTANT(16873037158)},
584 : {(hge) LL_CONSTANT(1000000000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(10000000000) + (hge) LL_CONSTANT(1687303715)},
585 : {(hge) LL_CONSTANT(10000000000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(1000000000) + (hge) LL_CONSTANT(168730371)},
586 : {(hge) LL_CONSTANT(100000000000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(100000000) + (hge) LL_CONSTANT(16873037)},
587 : {(hge) LL_CONSTANT(1000000000000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(10000000) + (hge) LL_CONSTANT(1687303)},
588 : {(hge) LL_CONSTANT(10000000000000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(1000000) + (hge) LL_CONSTANT(168730)},
589 : {(hge) LL_CONSTANT(100000000000000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(100000) + (hge) LL_CONSTANT(16873)},
590 : {(hge) LL_CONSTANT(1000000000000000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(10000) + (hge) LL_CONSTANT(1687)},
591 : {(hge) LL_CONSTANT(10000000000000000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(1000) + (hge) LL_CONSTANT(168)},
592 : {(hge) LL_CONSTANT(100000000000000000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(100) + (hge) LL_CONSTANT(16)},
593 : {(hge) LL_CONSTANT(1000000000000000000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(10) + (hge) LL_CONSTANT(1)},
594 : {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(1), (hge) LL_CONSTANT(17014118346046923173U)},
595 : {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(10), (hge) LL_CONSTANT(1701411834604692317)},
596 : {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(100), (hge) LL_CONSTANT(170141183460469231)},
597 : {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(1000), (hge) LL_CONSTANT(17014118346046923)},
598 : {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(10000), (hge) LL_CONSTANT(1701411834604692)},
599 : {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(100000), (hge) LL_CONSTANT(170141183460469)},
600 : {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(1000000), (hge) LL_CONSTANT(17014118346046)},
601 : {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(10000000), (hge) LL_CONSTANT(1701411834604)},
602 : {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(100000000), (hge) LL_CONSTANT(170141183460)},
603 : {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(1000000000), (hge) LL_CONSTANT(17014118346)},
604 : {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(10000000000), (hge) LL_CONSTANT(1701411834)},
605 : {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(100000000000), (hge) LL_CONSTANT(170141183)},
606 : {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(1000000000000), (hge) LL_CONSTANT(17014118)},
607 : {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(10000000000000), (hge) LL_CONSTANT(1701411)},
608 : {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(100000000000000), (hge) LL_CONSTANT(170141)},
609 : {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(1000000000000000), (hge) LL_CONSTANT(17014)},
610 : {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(10000000000000000), (hge) LL_CONSTANT(1701)},
611 : {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(100000000000000000), (hge) LL_CONSTANT(170)},
612 : {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(1000000000000000000), (hge) LL_CONSTANT(17)},
613 : {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(10000000000000000000U),(hge) LL_CONSTANT(1)},
614 : #else
615 : /* maximum lng value: 9223372036854775807 (2**63-1) */
616 : {LL_CONSTANT(1), LL_CONSTANT(9223372036854775807)},
617 : {LL_CONSTANT(10), LL_CONSTANT(922337203685477580)},
618 : {LL_CONSTANT(100), LL_CONSTANT(92233720368547758)},
619 : {LL_CONSTANT(1000), LL_CONSTANT(9223372036854775)},
620 : {LL_CONSTANT(10000), LL_CONSTANT(922337203685477)},
621 : {LL_CONSTANT(100000), LL_CONSTANT(92233720368547)},
622 : {LL_CONSTANT(1000000), LL_CONSTANT(9223372036854)},
623 : {LL_CONSTANT(10000000), LL_CONSTANT(922337203685)},
624 : {LL_CONSTANT(100000000), LL_CONSTANT(92233720368)},
625 : {LL_CONSTANT(1000000000), LL_CONSTANT(9223372036)},
626 : {LL_CONSTANT(10000000000), LL_CONSTANT(922337203)},
627 : {LL_CONSTANT(100000000000), LL_CONSTANT(92233720)},
628 : {LL_CONSTANT(1000000000000), LL_CONSTANT(9223372)},
629 : {LL_CONSTANT(10000000000000), LL_CONSTANT(922337)},
630 : {LL_CONSTANT(100000000000000), LL_CONSTANT(92233)},
631 : {LL_CONSTANT(1000000000000000), LL_CONSTANT(9223)},
632 : {LL_CONSTANT(10000000000000000), LL_CONSTANT(922)},
633 : {LL_CONSTANT(100000000000000000), LL_CONSTANT(92)},
634 : {LL_CONSTANT(1000000000000000000), LL_CONSTANT(9)},
635 : #endif
636 : };
637 : static const int maxmod10 = 7; /* (int) (maxdiv[0].maxval % 10) */
638 :
639 : static ssize_t
640 234656739 : numFromStr(const char *src, size_t *len, void **dst, int tp, bool external)
641 : {
642 234656739 : const char *p = src;
643 234656739 : size_t sz = ATOMsize(tp);
644 : #ifdef HAVE_HGE
645 234656739 : hge base = 0;
646 : #else
647 : lng base = 0;
648 : #endif
649 234656739 : int sign = 1;
650 :
651 : /* a valid number has the following syntax:
652 : * [-+]?[0-9]+([eE][0-9]+)?(LL)? -- PCRE syntax, or in other words
653 : * optional sign, one or more digits, optional exponent, optional LL
654 : * the exponent has the following syntax:
655 : * lower or upper case letter E, one or more digits
656 : * embedded spaces are not allowed
657 : * the optional LL at the end are only allowed for lng and hge
658 : * values */
659 234656739 : atommem(sz);
660 :
661 234656740 : if (strNil(src)) {
662 0 : memcpy(*dst, ATOMnilptr(tp), sz);
663 0 : return 1;
664 : }
665 :
666 234656838 : while (GDKisspace(*p))
667 98 : p++;
668 234656740 : if (!GDKisdigit(*p)) {
669 11698 : switch (*p) {
670 5 : case 'n':
671 5 : if (external) {
672 0 : memcpy(*dst, ATOMnilptr(tp), sz);
673 0 : if (p[1] == 'i' && p[2] == 'l') {
674 0 : p += 3;
675 0 : return (ssize_t) (p - src);
676 : }
677 : }
678 5 : GDKerror("not a number");
679 5 : goto bailout;
680 11503 : case '-':
681 11503 : sign = -1;
682 11503 : p++;
683 11503 : break;
684 1 : case '+':
685 1 : p++;
686 1 : break;
687 : }
688 11693 : if (!GDKisdigit(*p)) {
689 195 : GDKerror("not a number");
690 195 : goto bailout;
691 : }
692 : }
693 580891681 : do {
694 580891681 : int dig = base10(*p);
695 580891681 : if (base > maxdiv[1].maxval ||
696 7 : (base == maxdiv[1].maxval && dig > maxmod10)) {
697 : /* overflow */
698 0 : goto overflow;
699 : }
700 580891681 : base = 10 * base + dig;
701 580891681 : p++;
702 580891681 : } while (GDKisdigit(*p));
703 234656540 : if ((*p == 'e' || *p == 'E') && GDKisdigit(p[1])) {
704 7 : p++;
705 7 : if (base == 0) {
706 : /* if base is 0, any exponent will do, the
707 : * result is still 0 */
708 0 : while (GDKisdigit(*p))
709 0 : p++;
710 : } else {
711 : int exp = 0;
712 11 : do {
713 : /* this calculation cannot overflow */
714 11 : exp = exp * 10 + base10(*p);
715 11 : if (exp >= (int) (sizeof(maxdiv) / sizeof(maxdiv[0]))) {
716 : /* overflow */
717 0 : goto overflow;
718 : }
719 11 : p++;
720 11 : } while (GDKisdigit(*p));
721 7 : if (base > maxdiv[exp].maxval) {
722 : /* overflow */
723 0 : goto overflow;
724 : }
725 7 : base *= maxdiv[exp].scale;
726 : }
727 : }
728 234656540 : base *= sign;
729 234656540 : switch (sz) {
730 53842 : case 1: {
731 53842 : bte **dstbte = (bte **) dst;
732 53842 : if (base < GDK_bte_min || base > GDK_bte_max) {
733 0 : goto overflow;
734 : }
735 53842 : **dstbte = (bte) base;
736 53842 : break;
737 : }
738 386062 : case 2: {
739 386062 : sht **dstsht = (sht **) dst;
740 386062 : if (base < GDK_sht_min || base > GDK_sht_max) {
741 3 : goto overflow;
742 : }
743 386059 : **dstsht = (sht) base;
744 386059 : break;
745 : }
746 230509119 : case 4: {
747 230509119 : int **dstint = (int **) dst;
748 230509119 : if (base < GDK_int_min || base > GDK_int_max) {
749 2 : goto overflow;
750 : }
751 230509117 : **dstint = (int) base;
752 230509117 : break;
753 : }
754 1912009 : case 8: {
755 1912009 : lng **dstlng = (lng **) dst;
756 : #ifdef HAVE_HGE
757 1912009 : if (base < GDK_lng_min || base > GDK_lng_max) {
758 4 : goto overflow;
759 : }
760 : #endif
761 1912005 : **dstlng = (lng) base;
762 1912005 : if (p[0] == 'L' && p[1] == 'L')
763 0 : p += 2;
764 : break;
765 : }
766 : #ifdef HAVE_HGE
767 1795508 : case 16: {
768 1795508 : hge **dsthge = (hge **) dst;
769 1795508 : **dsthge = (hge) base;
770 1795508 : if (p[0] == 'L' && p[1] == 'L')
771 0 : p += 2;
772 : break;
773 : }
774 : #endif
775 : }
776 234656647 : while (GDKisspace(*p))
777 116 : p++;
778 234656531 : return (ssize_t) (p - src);
779 :
780 : overflow:
781 9 : while (GDKisdigit(*p))
782 0 : p++;
783 9 : GDKerror("overflow: \"%.*s\" does not fit in %s\n",
784 : (int) (p - src), src, ATOMname(tp));
785 209 : bailout:
786 209 : memcpy(*dst, ATOMnilptr(tp), sz);
787 209 : return -1;
788 : }
789 :
790 : ssize_t
791 53497 : bteFromStr(const char *src, size_t *len, bte **dst, bool external)
792 : {
793 53497 : return numFromStr(src, len, (void **) dst, TYPE_bte, external);
794 : }
795 :
796 : ssize_t
797 378547 : shtFromStr(const char *src, size_t *len, sht **dst, bool external)
798 : {
799 378547 : return numFromStr(src, len, (void **) dst, TYPE_sht, external);
800 : }
801 :
802 : ssize_t
803 225143265 : intFromStr(const char *src, size_t *len, int **dst, bool external)
804 : {
805 225143265 : return numFromStr(src, len, (void **) dst, TYPE_int, external);
806 : }
807 :
808 : ssize_t
809 1912016 : lngFromStr(const char *src, size_t *len, lng **dst, bool external)
810 : {
811 1912016 : return numFromStr(src, len, (void **) dst, TYPE_lng, external);
812 : }
813 :
814 : #ifdef HAVE_HGE
815 : ssize_t
816 1795462 : hgeFromStr(const char *src, size_t *len, hge **dst, bool external)
817 : {
818 1795462 : return numFromStr(src, len, (void **) dst, TYPE_hge, external);
819 : }
820 : #endif
821 :
822 : #define atom_io(TYPE, NAME, CAST) \
823 : static TYPE * \
824 : TYPE##Read(TYPE *A, size_t *dstlen, stream *s, size_t cnt) \
825 : { \
826 : TYPE *a = A; \
827 : if (a == NULL || *dstlen < cnt * sizeof(TYPE)) { \
828 : if ((a = GDKrealloc(a, cnt * sizeof(TYPE))) == NULL) \
829 : return NULL; \
830 : *dstlen = cnt * sizeof(TYPE); \
831 : } \
832 : if (mnstr_read##NAME##Array(s, (CAST *) a, cnt) == 0 || \
833 : mnstr_errnr(s) != MNSTR_NO__ERROR) { \
834 : if (a != A) \
835 : GDKfree(a); \
836 : return NULL; \
837 : } \
838 : return a; \
839 : } \
840 : static gdk_return \
841 : TYPE##Write(const TYPE *a, stream *s, size_t cnt) \
842 : { \
843 : return mnstr_write##NAME##Array(s, (const CAST *) a, cnt) ? \
844 : GDK_SUCCEED : GDK_FAIL; \
845 : }
846 :
847 : static gdk_return
848 125264 : mskWrite(const msk *a, stream *s, size_t cnt)
849 : {
850 125264 : if (cnt == 0)
851 : return GDK_SUCCEED;
852 125264 : if (cnt == 1)
853 125264 : return mnstr_writeBte(s, (int8_t) *a) ? GDK_SUCCEED : GDK_FAIL;
854 : return GDK_FAIL;
855 : }
856 :
857 : static void *
858 124102 : mskRead(msk *A, size_t *dstlen, stream *s, size_t cnt)
859 : {
860 124102 : int8_t v;
861 124102 : msk *a = A;
862 124102 : if (cnt != 1)
863 : return NULL;
864 124102 : if (a == NULL || *dstlen == 0) {
865 0 : if ((a = GDKrealloc(a, 1)) == NULL)
866 : return NULL;
867 0 : *dstlen = 1;
868 : }
869 124102 : if (mnstr_readBte(s, &v) != 1) {
870 0 : if (a != A)
871 0 : GDKfree(a);
872 0 : return NULL;
873 : }
874 124102 : *a = v != 0;
875 124102 : return a;
876 : }
877 :
878 7289 : atom_io(bit, Bte, bte)
879 :
880 47067 : atomtostr(bte, "%hhd", )
881 260296 : atom_io(bte, Bte, bte)
882 :
883 1073922 : atomtostr(sht, "%hd", )
884 8420 : atom_io(sht, Sht, sht)
885 :
886 15326300 : atomtostr(int, "%d", )
887 224825 : atom_io(int, Int, int)
888 :
889 165936 : atomtostr(lng, LLFMT, )
890 5893 : atom_io(lng, Lng, lng)
891 :
892 : #ifdef HAVE_HGE
893 : #define HGE_LL018FMT "%018" PRId64
894 : #define HGE_LL18DIGITS LL_CONSTANT(1000000000000000000)
895 : #define HGE_ABS(a) (((a) < 0) ? -(a) : (a))
896 : ssize_t
897 3333 : hgeToStr(char **dst, size_t *len, const hge *src, bool external)
898 : {
899 3333 : atommem(hgeStrlen);
900 3333 : if (is_hge_nil(*src)) {
901 1 : if (external) {
902 1 : assert(*len >= strlen("nil") + 1);
903 1 : strcpy(*dst, "nil");
904 1 : return 3;
905 : }
906 0 : assert(*len >= strlen(str_nil) + 1);
907 0 : strcpy(*dst, str_nil);
908 0 : return 1;
909 : }
910 3332 : if ((hge) GDK_lng_min <= *src && *src <= (hge) GDK_lng_max) {
911 3199 : lng s = (lng) *src;
912 3199 : return lngToStr(dst, len, &s, external);
913 : } else {
914 133 : hge s = *src / HGE_LL18DIGITS;
915 133 : ssize_t llen = hgeToStr(dst, len, &s, external);
916 133 : if (llen < 0)
917 : return llen;
918 133 : snprintf(*dst + llen, *len - llen, HGE_LL018FMT,
919 133 : (lng) HGE_ABS(*src % HGE_LL18DIGITS));
920 133 : return strlen(*dst);
921 : }
922 : }
923 954 : atom_io(hge, Hge, hge)
924 : #endif
925 :
926 : ssize_t
927 0 : ptrFromStr(const char *src, size_t *len, ptr **dst, bool external)
928 : {
929 0 : size_t base = 0;
930 0 : const char *p = src;
931 :
932 0 : atommem(sizeof(ptr));
933 :
934 0 : **dst = ptr_nil;
935 0 : if (strNil(src))
936 : return 1;
937 :
938 0 : while (GDKisspace(*p))
939 0 : p++;
940 0 : if (external && strncmp(p, "nil", 3) == 0) {
941 0 : p += 3;
942 : } else {
943 0 : if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) {
944 0 : p += 2;
945 : }
946 0 : if (!GDKisxdigit(*p)) {
947 0 : GDKerror("not a number\n");
948 0 : return -1;
949 : }
950 0 : while (GDKisxdigit(*p)) {
951 0 : if (base >= ((size_t) 1 << (8 * sizeof(size_t) - 4))) {
952 0 : GDKerror("overflow\n");
953 0 : return -1;
954 : }
955 0 : base = mult16(base) + base16(*p);
956 0 : p++;
957 : }
958 0 : **dst = (ptr) base;
959 : }
960 0 : while (GDKisspace(*p))
961 0 : p++;
962 0 : return (ssize_t) (p - src);
963 : }
964 :
965 : #ifdef _MSC_VER
966 : /* Windows doesn't put 0x in front whereas Linux does, so we do it ourselves */
967 : atomtostr(ptr, "0x%p", )
968 : #else
969 1 : atomtostr(ptr, "%p", )
970 : #endif
971 :
972 : #if SIZEOF_VOID_P == SIZEOF_INT
973 : atom_io(ptr, Int, int)
974 : #else /* SIZEOF_VOID_P == SIZEOF_LNG */
975 0 : atom_io(ptr, Lng, lng)
976 : #endif
977 :
978 : ssize_t
979 274101 : dblFromStr(const char *src, size_t *len, dbl **dst, bool external)
980 : {
981 274101 : const char *p = src;
982 274101 : ssize_t n = 0;
983 274101 : double d;
984 :
985 : /* alloc memory */
986 274101 : atommem(sizeof(dbl));
987 :
988 274101 : if (strNil(src)) {
989 0 : **dst = dbl_nil;
990 0 : return 1;
991 : }
992 :
993 274220 : while (GDKisspace(*p))
994 119 : p++;
995 274101 : if (external && strncmp(p, "nil", 3) == 0) {
996 0 : **dst = dbl_nil;
997 0 : p += 3;
998 0 : n = (ssize_t) (p - src);
999 : } else {
1000 : /* on overflow, strtod returns HUGE_VAL and sets
1001 : * errno to ERANGE; on underflow, it returns a value
1002 : * whose magnitude is no greater than the smallest
1003 : * normalized double, and may or may not set errno to
1004 : * ERANGE. We accept underflow, but not overflow. */
1005 274101 : char *pe;
1006 274101 : errno = 0;
1007 274101 : d = strtod(p, &pe);
1008 294029 : if (p == pe)
1009 : p = src; /* nothing converted */
1010 : else
1011 293995 : p = pe;
1012 294029 : n = (ssize_t) (p - src);
1013 294029 : if (n == 0 || (errno == ERANGE && (d < -1 || d > 1))
1014 293987 : || !isfinite(d) /* no NaN or Infinite */
1015 : ) {
1016 104 : GDKerror("overflow or not a number\n");
1017 104 : return -1;
1018 : } else {
1019 293975 : while (src[n] && GDKisspace(src[n]))
1020 50 : n++;
1021 293925 : **dst = (dbl) d;
1022 : }
1023 : }
1024 : return n;
1025 : }
1026 :
1027 : ssize_t
1028 14396 : dblToStr(char **dst, size_t *len, const dbl *src, bool external)
1029 : {
1030 14396 : int l = 0;
1031 :
1032 14396 : atommem(dblStrlen);
1033 14396 : if (is_dbl_nil(*src)) {
1034 7 : if (external) {
1035 7 : strcpy(*dst, "nil");
1036 7 : return 3;
1037 : }
1038 0 : strcpy(*dst, str_nil);
1039 0 : return 1;
1040 : }
1041 14389 : if (*src <= (dbl) 999999999999999 &&
1042 14243 : *src >= (dbl) -999999999999999 &&
1043 14243 : (dbl) (int) *src == *src) {
1044 8634 : l = snprintf(*dst, *len, "%.0f", *src);
1045 8634 : if (strtod(*dst, NULL) == *src)
1046 8634 : return (ssize_t) l;
1047 : }
1048 39621 : for (int i = 4; i < 18; i++) {
1049 39621 : l = snprintf(*dst, *len, "%.*g", i, *src);
1050 39621 : if (strtod(*dst, NULL) == *src)
1051 : break;
1052 : }
1053 5753 : return (ssize_t) l;
1054 : }
1055 :
1056 764 : atom_io(dbl, Lng, lng)
1057 :
1058 : ssize_t
1059 1831440 : fltFromStr(const char *src, size_t *len, flt **dst, bool external)
1060 : {
1061 1831440 : const char *p = src;
1062 1831440 : ssize_t n = 0;
1063 1831440 : float f;
1064 :
1065 : /* alloc memory */
1066 1831440 : atommem(sizeof(flt));
1067 :
1068 1831440 : if (strNil(src)) {
1069 0 : **dst = flt_nil;
1070 0 : return 1;
1071 : }
1072 :
1073 1831505 : while (GDKisspace(*p))
1074 65 : p++;
1075 1831440 : if (external && strncmp(p, "nil", 3) == 0) {
1076 0 : **dst = flt_nil;
1077 0 : p += 3;
1078 0 : n = (ssize_t) (p - src);
1079 : } else {
1080 : /* on overflow, strtof returns HUGE_VALF and sets
1081 : * errno to ERANGE; on underflow, it returns a value
1082 : * whose magnitude is no greater than the smallest
1083 : * normalized float, and may or may not set errno to
1084 : * ERANGE. We accept underflow, but not overflow. */
1085 1831440 : char *pe;
1086 1831440 : errno = 0;
1087 1831440 : f = strtof(p, &pe);
1088 1834810 : if (p == pe)
1089 : p = src; /* nothing converted */
1090 : else
1091 1834802 : p = pe;
1092 1834810 : n = (ssize_t) (p - src);
1093 1834810 : if (n == 0 || (errno == ERANGE && (f < -1 || f > 1))
1094 1834794 : || !isfinite(f) /* no NaN or infinite */) {
1095 58 : GDKerror("overflow or not a number\n");
1096 58 : return -1;
1097 : } else {
1098 1834791 : while (src[n] && GDKisspace(src[n]))
1099 39 : n++;
1100 1834752 : if (f == -0)
1101 6566 : f = 0;
1102 1834752 : **dst = (flt) f;
1103 : }
1104 : }
1105 : return n;
1106 : }
1107 :
1108 : ssize_t
1109 1922 : fltToStr(char **dst, size_t *len, const flt *src, bool external)
1110 : {
1111 1922 : int l = 0;
1112 :
1113 1922 : atommem(fltStrlen);
1114 1922 : if (is_flt_nil(*src)) {
1115 5 : if (external) {
1116 5 : strcpy(*dst, "nil");
1117 5 : return 3;
1118 : }
1119 0 : strcpy(*dst, str_nil);
1120 0 : return 1;
1121 : }
1122 1917 : if (*src <= (flt) 9999999 &&
1123 1663 : *src >= (flt) -9999999 &&
1124 1663 : (flt) (int) *src == *src) {
1125 1244 : l = snprintf(*dst, *len, "%.0f", *src);
1126 1244 : if (strtof(*dst, NULL) == *src)
1127 1244 : return (ssize_t) l;
1128 : }
1129 2011 : for (int i = 4; i < 10; i++) {
1130 2011 : l = snprintf(*dst, *len, "%.*g", i, *src);
1131 2011 : if (strtof(*dst, NULL) == *src)
1132 : break;
1133 : }
1134 673 : return (ssize_t) l;
1135 : }
1136 :
1137 211 : atom_io(flt, Int, int)
1138 :
1139 :
1140 : /*
1141 : * String conversion routines.
1142 : */
1143 : ssize_t
1144 26 : OIDfromStr(const char *src, size_t *len, oid **dst, bool external)
1145 : {
1146 : #if SIZEOF_OID == SIZEOF_INT
1147 : int ui = 0, *uip = &ui;
1148 : #else
1149 26 : lng ui = 0, *uip = &ui;
1150 : #endif
1151 26 : size_t l = sizeof(ui);
1152 26 : ssize_t pos = 0;
1153 26 : const char *p = src;
1154 :
1155 26 : atommem(sizeof(oid));
1156 :
1157 26 : **dst = oid_nil;
1158 26 : if (strNil(src))
1159 : return 1;
1160 :
1161 26 : while (GDKisspace(*p))
1162 0 : p++;
1163 :
1164 26 : if (external && strncmp(p, "nil", 3) == 0)
1165 0 : return (ssize_t) (p - src) + 3;
1166 :
1167 26 : if (*p >= '0' && *p <= '9') {
1168 : #if SIZEOF_OID == SIZEOF_INT
1169 : pos = intFromStr(p, &l, &uip, external);
1170 : #else
1171 25 : pos = lngFromStr(p, &l, &uip, external);
1172 : #endif
1173 25 : if (pos < 0)
1174 : return pos;
1175 25 : if (p[pos] == '@') {
1176 7 : pos++;
1177 14 : while (p[pos] >= '0' && p[pos] <= '9')
1178 7 : pos++;
1179 : }
1180 25 : if (ui >= 0) {
1181 25 : **dst = ui;
1182 : }
1183 25 : p += pos;
1184 : } else {
1185 1 : GDKerror("not an OID\n");
1186 1 : return -1;
1187 : }
1188 25 : while (GDKisspace(*p))
1189 0 : p++;
1190 25 : return (ssize_t) (p - src);
1191 : }
1192 :
1193 : ssize_t
1194 4212 : OIDtoStr(char **dst, size_t *len, const oid *src, bool external)
1195 : {
1196 4212 : atommem(oidStrlen);
1197 :
1198 4211 : if (is_oid_nil(*src)) {
1199 16 : if (external) {
1200 16 : strcpy(*dst, "nil");
1201 16 : return 3;
1202 : }
1203 0 : strcpy(*dst, str_nil);
1204 0 : return 1;
1205 : }
1206 4195 : return snprintf(*dst, *len, OIDFMT "@0", *src);
1207 : }
1208 :
1209 : static int
1210 4219726 : UUIDcompare(const void *L, const void *R)
1211 : {
1212 4219726 : const uuid *l = L, *r = R;
1213 4219726 : if (is_uuid_nil(*r))
1214 441631 : return !is_uuid_nil(*l);
1215 3778095 : if (is_uuid_nil(*l))
1216 : return -1;
1217 401260 : return memcmp(l->u, r->u, UUID_SIZE);
1218 : }
1219 :
1220 : static ssize_t
1221 287 : UUIDfromString(const char *svalue, size_t *len, void **RETVAL, bool external)
1222 : {
1223 287 : uuid **retval = (uuid **) RETVAL;
1224 287 : const char *s = svalue;
1225 :
1226 287 : if (*len < UUID_SIZE || *retval == NULL) {
1227 54 : GDKfree(*retval);
1228 54 : if ((*retval = GDKmalloc(UUID_SIZE)) == NULL)
1229 : return -1;
1230 54 : *len = UUID_SIZE;
1231 : }
1232 287 : if (external && strcmp(svalue, "nil") == 0) {
1233 0 : **retval = uuid_nil;
1234 0 : return 3;
1235 : }
1236 287 : if (strNil(svalue)) {
1237 33 : **retval = uuid_nil;
1238 33 : return 1;
1239 : }
1240 256 : while (GDKisspace(*s))
1241 2 : s++;
1242 : /* we don't use uuid_parse since we accept UUIDs without hyphens */
1243 : uuid u;
1244 3513 : for (int i = 0, j = 0; i < UUID_SIZE; i++) {
1245 : /* on select locations we allow a '-' in the source string */
1246 3310 : if (j == 8 || j == 12 || j == 16 || j == 20) {
1247 814 : if (*s == '-')
1248 760 : s++;
1249 : }
1250 3310 : if (*s >= '0' && *s <= '9')
1251 1681 : u.u[i] = *s - '0';
1252 1629 : else if ('a' <= *s && *s <= 'f')
1253 1194 : u.u[i] = *s - 'a' + 10;
1254 435 : else if ('A' <= *s && *s <= 'F')
1255 402 : u.u[i] = *s - 'A' + 10;
1256 : else
1257 33 : goto bailout;
1258 3277 : s++;
1259 3277 : j++;
1260 3277 : u.u[i] <<= 4;
1261 3277 : if (*s >= '0' && *s <= '9')
1262 1575 : u.u[i] |= *s - '0';
1263 1702 : else if ('a' <= *s && *s <= 'f')
1264 1332 : u.u[i] |= *s - 'a' + 10;
1265 370 : else if ('A' <= *s && *s <= 'F')
1266 352 : u.u[i] |= *s - 'A' + 10;
1267 : else
1268 18 : goto bailout;
1269 3259 : s++;
1270 3259 : j++;
1271 : }
1272 209 : while (GDKisspace(*s))
1273 6 : s++;
1274 203 : if (*s != 0)
1275 12 : goto bailout;
1276 191 : **retval = u;
1277 191 : return (ssize_t) (s - svalue);
1278 :
1279 63 : bailout:
1280 63 : **retval = uuid_nil;
1281 63 : return -1;
1282 : }
1283 :
1284 : static BUN
1285 0 : UUIDhash(const void *v)
1286 : {
1287 0 : return mix_uuid((const uuid *) v);
1288 : }
1289 :
1290 : static void *
1291 21 : UUIDread(void *U, size_t *dstlen, stream *s, size_t cnt)
1292 : {
1293 21 : uuid *u = U;
1294 21 : if (u == NULL || *dstlen < cnt * sizeof(uuid)) {
1295 0 : if ((u = GDKrealloc(u, cnt * sizeof(uuid))) == NULL)
1296 : return NULL;
1297 0 : *dstlen = cnt * sizeof(uuid);
1298 : }
1299 21 : if (mnstr_read(s, u, UUID_SIZE, cnt) < (ssize_t) cnt) {
1300 0 : if (u != U)
1301 0 : GDKfree(u);
1302 0 : return NULL;
1303 : }
1304 : return u;
1305 : }
1306 :
1307 : static gdk_return
1308 22 : UUIDwrite(const void *u, stream *s, size_t cnt)
1309 : {
1310 22 : return mnstr_write(s, u, UUID_SIZE, cnt) ? GDK_SUCCEED : GDK_FAIL;
1311 : }
1312 :
1313 : static ssize_t
1314 1772806 : UUIDtoString(str *retval, size_t *len, const void *VALUE, bool external)
1315 : {
1316 1772806 : const uuid *value = VALUE;
1317 1772806 : if (*len <= UUID_STRLEN || *retval == NULL) {
1318 105 : if (*retval)
1319 0 : GDKfree(*retval);
1320 105 : if ((*retval = GDKmalloc(UUID_STRLEN + 1)) == NULL)
1321 : return -1;
1322 0 : *len = UUID_STRLEN + 1;
1323 : }
1324 1770550 : if (is_uuid_nil(*value)) {
1325 0 : if (external) {
1326 0 : assert(*len >= strlen("nil") + 1);
1327 0 : strcpy(*retval, "nil");
1328 0 : return 3;
1329 : }
1330 0 : assert(*len >= strlen(str_nil) + 1);
1331 0 : strcpy(*retval, str_nil);
1332 0 : return 1;
1333 : }
1334 1770550 : snprintf(*retval, *len,
1335 : "%02x%02x%02x%02x-%02x%02x-%02x%02x"
1336 : "-%02x%02x-%02x%02x%02x%02x%02x%02x",
1337 1770550 : value->u[0], value->u[1], value->u[2], value->u[3],
1338 1770550 : value->u[4], value->u[5], value->u[6], value->u[7],
1339 1770550 : value->u[8], value->u[9], value->u[10], value->u[11],
1340 1770550 : value->u[12], value->u[13], value->u[14], value->u[15]);
1341 1770550 : assert(strlen(*retval) == UUID_STRLEN);
1342 : return UUID_STRLEN;
1343 : }
1344 :
1345 : static const blob blob_nil = {
1346 : ~(size_t) 0
1347 : };
1348 :
1349 : size_t
1350 14806177 : blobsize(size_t nitems)
1351 : {
1352 14806177 : if (nitems == ~(size_t) 0)
1353 5334293 : nitems = 0;
1354 14806177 : assert(offsetof(blob, data) + nitems <= VAR_MAX);
1355 14806177 : return (size_t) (offsetof(blob, data) + nitems);
1356 : }
1357 :
1358 : static int
1359 14845381 : BLOBcmp(const void *L, const void *R)
1360 : {
1361 14845381 : const blob *l = L, *r = R;
1362 14845381 : int c;
1363 14845381 : if (is_blob_nil(r))
1364 10739790 : return !is_blob_nil(l);
1365 4105591 : if (is_blob_nil(l))
1366 : return -1;
1367 6705 : if (l->nitems < r->nitems) {
1368 2570 : c = memcmp(l->data, r->data, l->nitems);
1369 2570 : if (c == 0)
1370 2273 : return -1;
1371 : } else {
1372 4135 : c = memcmp(l->data, r->data, r->nitems);
1373 4135 : if (c == 0)
1374 3592 : return l->nitems > r->nitems;
1375 : }
1376 : return c;
1377 : }
1378 :
1379 : static void
1380 35 : BLOBdel(Heap *h, var_t *idx)
1381 : {
1382 35 : HEAP_free(h, *idx);
1383 35 : }
1384 :
1385 : static BUN
1386 11284 : BLOBhash(const void *B)
1387 : {
1388 11284 : const blob *b = B;
1389 11284 : return (BUN) b->nitems;
1390 : }
1391 :
1392 : static void *
1393 64 : BLOBread(void *A, size_t *dstlen, stream *s, size_t cnt)
1394 : {
1395 64 : blob *a = A;
1396 64 : int len;
1397 :
1398 64 : (void) cnt;
1399 64 : assert(cnt == 1);
1400 64 : if (mnstr_readInt(s, &len) != 1 || len < 0)
1401 : return NULL;
1402 64 : if (a == NULL || *dstlen < (size_t) len) {
1403 0 : if ((a = GDKrealloc(a, (size_t) len)) == NULL)
1404 : return NULL;
1405 0 : *dstlen = (size_t) len;
1406 : }
1407 64 : if (mnstr_read(s, (char *) a, (size_t) len, 1) != 1) {
1408 0 : GDKfree(a);
1409 0 : return NULL;
1410 : }
1411 : return a;
1412 : }
1413 :
1414 : static gdk_return
1415 64 : BLOBwrite(const void *A, stream *s, size_t cnt)
1416 : {
1417 64 : const blob *a = A;
1418 64 : size_t len = blobsize(a->nitems);
1419 :
1420 64 : (void) cnt;
1421 64 : assert(cnt == 1);
1422 128 : if (!mnstr_writeInt(s, (int) len) /* 64bit: check for overflow */ ||
1423 64 : mnstr_write(s, a, len, 1) < 0)
1424 0 : return GDK_FAIL;
1425 : return GDK_SUCCEED;
1426 : }
1427 :
1428 : static size_t
1429 1505 : BLOBlength(const void *P)
1430 : {
1431 1505 : const blob *p = P;
1432 1505 : size_t l = blobsize(p->nitems); /* 64bit: check for overflow */
1433 1505 : assert(l <= (size_t) GDK_int_max);
1434 1505 : return l;
1435 : }
1436 :
1437 : static gdk_return
1438 941 : BLOBheap(Heap *heap, size_t capacity)
1439 : {
1440 941 : return HEAP_initialize(heap, capacity, 0, (int) sizeof(var_t));
1441 : }
1442 :
1443 : static var_t
1444 7401102 : BLOBput(BAT *b, var_t *bun, const void *VAL)
1445 : {
1446 7401102 : const blob *val = VAL;
1447 7401102 : char *base = NULL;
1448 :
1449 7401102 : *bun = HEAP_malloc(b, blobsize(val->nitems));
1450 7401101 : base = b->tvheap->base;
1451 7401101 : if (*bun != (var_t) -1) {
1452 7401100 : memcpy(&base[*bun], val, blobsize(val->nitems));
1453 7401100 : b->tvheap->dirty = true;
1454 : }
1455 7401101 : return *bun;
1456 : }
1457 :
1458 : static ssize_t
1459 409 : BLOBtostr(str *tostr, size_t *l, const void *P, bool external)
1460 : {
1461 409 : static const char hexit[] = "0123456789ABCDEF";
1462 409 : const blob *p = P;
1463 409 : char *s;
1464 409 : size_t i;
1465 409 : size_t expectedlen;
1466 :
1467 409 : if (is_blob_nil(p))
1468 3 : expectedlen = external ? 4 : 2;
1469 : else
1470 406 : expectedlen = p->nitems * 2 + 1;
1471 409 : if (*l < expectedlen || *tostr == NULL) {
1472 55 : GDKfree(*tostr);
1473 55 : *tostr = GDKmalloc(expectedlen);
1474 55 : if (*tostr == NULL)
1475 : return -1;
1476 55 : *l = expectedlen;
1477 : }
1478 409 : if (is_blob_nil(p)) {
1479 3 : if (external) {
1480 3 : strcpy(*tostr, "nil");
1481 3 : return 3;
1482 : }
1483 0 : strcpy(*tostr, str_nil);
1484 0 : return 1;
1485 : }
1486 :
1487 406 : s = *tostr;
1488 :
1489 25857775 : for (i = 0; i < p->nitems; i++) {
1490 25857369 : *s++ = hexit[(p->data[i] >> 4) & 15];
1491 25857369 : *s++ = hexit[p->data[i] & 15];
1492 : }
1493 406 : *s = '\0';
1494 406 : return (ssize_t) (s - *tostr);
1495 : }
1496 :
1497 : static ssize_t
1498 2399 : BLOBfromstr(const char *instr, size_t *l, void **VAL, bool external)
1499 : {
1500 2399 : blob **val = (blob **) VAL;
1501 2399 : size_t i;
1502 2399 : size_t nitems;
1503 2399 : size_t nbytes;
1504 2399 : blob *result;
1505 2399 : const char *s = instr;
1506 :
1507 4798 : if (strNil(instr) || (external && strncmp(instr, "nil", 3) == 0)) {
1508 0 : nbytes = blobsize(0);
1509 0 : if (*l < nbytes || *val == NULL) {
1510 0 : GDKfree(*val);
1511 0 : if ((*val = GDKmalloc(nbytes)) == NULL)
1512 : return -1;
1513 : }
1514 0 : **val = blob_nil;
1515 0 : return strNil(instr) ? 1 : 3;
1516 : }
1517 :
1518 : /* count hexits and check for hexits/space */
1519 21958025 : for (i = nitems = 0; instr[i]; i++) {
1520 21955629 : if (GDKisxdigit(instr[i]))
1521 21955626 : nitems++;
1522 3 : else if (!GDKisspace(instr[i])) {
1523 3 : GDKerror("Illegal char in blob\n");
1524 3 : return -1;
1525 : }
1526 : }
1527 2396 : if (nitems % 2 != 0) {
1528 0 : GDKerror("Illegal blob length '%zu' (should be even)\n", nitems);
1529 0 : return -1;
1530 : }
1531 2396 : nitems /= 2;
1532 2396 : nbytes = blobsize(nitems);
1533 :
1534 2396 : if (*l < nbytes || *val == NULL) {
1535 2298 : GDKfree(*val);
1536 2298 : *val = GDKmalloc(nbytes);
1537 2299 : if( *val == NULL)
1538 : return -1;
1539 2299 : *l = nbytes;
1540 : }
1541 2397 : result = *val;
1542 2397 : result->nitems = nitems;
1543 :
1544 : /*
1545 : // Read the values of the blob.
1546 : */
1547 10980210 : for (i = 0; i < nitems; ++i) {
1548 10977813 : int res = 0;
1549 :
1550 10977813 : for (;;) {
1551 10977813 : if (*s >= '0' && *s <= '9') {
1552 5900618 : res = *s - '0';
1553 5077195 : } else if (*s >= 'A' && *s <= 'F') {
1554 2651918 : res = 10 + *s - 'A';
1555 2425277 : } else if (*s >= 'a' && *s <= 'f') {
1556 2425277 : res = 10 + *s - 'a';
1557 : } else {
1558 0 : assert(GDKisspace(*s));
1559 0 : s++;
1560 0 : continue;
1561 : }
1562 10977813 : break;
1563 : }
1564 10977813 : s++;
1565 10977813 : res <<= 4;
1566 10977813 : for (;;) {
1567 10977813 : if (*s >= '0' && *s <= '9') {
1568 5899482 : res += *s - '0';
1569 5078331 : } else if (*s >= 'A' && *s <= 'F') {
1570 2654295 : res += 10 + *s - 'A';
1571 2424036 : } else if (*s >= 'a' && *s <= 'f') {
1572 2424036 : res += 10 + *s - 'a';
1573 : } else {
1574 0 : assert(GDKisspace(*s));
1575 0 : s++;
1576 0 : continue;
1577 : }
1578 10977813 : break;
1579 : }
1580 10977813 : s++;
1581 :
1582 10977813 : result->data[i] = (uint8_t) res;
1583 : }
1584 2397 : while (GDKisspace(*s))
1585 0 : s++;
1586 :
1587 2397 : return (ssize_t) (s - instr);
1588 : }
1589 :
1590 : atomDesc BATatoms[MAXATOMS] = {
1591 : [TYPE_void] = {
1592 : .name = "void",
1593 : .storage = TYPE_void,
1594 : .linear = true,
1595 : #if SIZEOF_OID == SIZEOF_INT
1596 : .atomNull = (void *) &int_nil,
1597 : .atomCmp = (int (*)(const void *, const void *)) intCmp,
1598 : .atomHash = (BUN (*)(const void *)) intHash,
1599 : #else
1600 : .atomNull = (void *) &lng_nil,
1601 : .atomCmp = (int (*)(const void *, const void *)) lngCmp,
1602 : .atomHash = (BUN (*)(const void *)) lngHash,
1603 : #endif
1604 : .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) OIDfromStr,
1605 : .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) OIDtoStr,
1606 : .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) voidRead,
1607 : .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) voidWrite,
1608 : },
1609 : [TYPE_bit] = {
1610 : .name = "bit",
1611 : .storage = TYPE_bte,
1612 : .linear = true,
1613 : .size = sizeof(bit),
1614 : .atomNull = (void *) &bte_nil,
1615 : .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) bitFromStr,
1616 : .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) bitToStr,
1617 : .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) bitRead,
1618 : .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) bitWrite,
1619 : .atomCmp = (int (*)(const void *, const void *)) bteCmp,
1620 : .atomHash = (BUN (*)(const void *)) bteHash,
1621 : },
1622 : [TYPE_msk] = {
1623 : .name = "msk",
1624 : .storage = TYPE_msk,
1625 : .linear = false,
1626 : .size = 1, /* really 1/8 */
1627 : .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) mskFromStr,
1628 : .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) mskToStr,
1629 : .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) mskRead,
1630 : .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) mskWrite,
1631 : .atomCmp = (int (*)(const void *, const void *)) mskCmp,
1632 : },
1633 : [TYPE_bte] = {
1634 : .name = "bte",
1635 : .storage = TYPE_bte,
1636 : .linear = true,
1637 : .size = sizeof(bte),
1638 : .atomNull = (void *) &bte_nil,
1639 : .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) bteFromStr,
1640 : .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) bteToStr,
1641 : .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) bteRead,
1642 : .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) bteWrite,
1643 : .atomCmp = (int (*)(const void *, const void *)) bteCmp,
1644 : .atomHash = (BUN (*)(const void *)) bteHash,
1645 : },
1646 : [TYPE_sht] = {
1647 : .name = "sht",
1648 : .storage = TYPE_sht,
1649 : .linear = true,
1650 : .size = sizeof(sht),
1651 : .atomNull = (void *) &sht_nil,
1652 : .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) shtFromStr,
1653 : .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) shtToStr,
1654 : .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) shtRead,
1655 : .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) shtWrite,
1656 : .atomCmp = (int (*)(const void *, const void *)) shtCmp,
1657 : .atomHash = (BUN (*)(const void *)) shtHash,
1658 : },
1659 : [TYPE_int] = {
1660 : .name = "int",
1661 : .storage = TYPE_int,
1662 : .linear = true,
1663 : .size = sizeof(int),
1664 : .atomNull = (void *) &int_nil,
1665 : .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) intFromStr,
1666 : .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) intToStr,
1667 : .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) intRead,
1668 : .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) intWrite,
1669 : .atomCmp = (int (*)(const void *, const void *)) intCmp,
1670 : .atomHash = (BUN (*)(const void *)) intHash,
1671 : },
1672 : [TYPE_oid] = {
1673 : .name = "oid",
1674 : .linear = true,
1675 : .size = sizeof(oid),
1676 : #if SIZEOF_OID == SIZEOF_INT
1677 : .storage = TYPE_int,
1678 : .atomNull = (void *) &int_nil,
1679 : .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) intRead,
1680 : .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) intWrite,
1681 : .atomCmp = (int (*)(const void *, const void *)) intCmp,
1682 : .atomHash = (BUN (*)(const void *)) intHash,
1683 : #else
1684 : .storage = TYPE_lng,
1685 : .atomNull = (void *) &lng_nil,
1686 : .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) lngRead,
1687 : .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) lngWrite,
1688 : .atomCmp = (int (*)(const void *, const void *)) lngCmp,
1689 : .atomHash = (BUN (*)(const void *)) lngHash,
1690 : #endif
1691 : .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) OIDfromStr,
1692 : .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) OIDtoStr,
1693 : },
1694 : [TYPE_ptr] = {
1695 : .name = "ptr",
1696 : .storage = TYPE_ptr,
1697 : .linear = true,
1698 : .size = sizeof(void *),
1699 : .atomNull = (void *) &ptr_nil,
1700 : .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) ptrFromStr,
1701 : .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) ptrToStr,
1702 : .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) ptrRead,
1703 : .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) ptrWrite,
1704 : #if SIZEOF_VOID_P == SIZEOF_INT
1705 : .atomCmp = (int (*)(const void *, const void *)) intCmp,
1706 : .atomHash = (BUN (*)(const void *)) intHash,
1707 : #else /* SIZEOF_VOID_P == SIZEOF_LNG */
1708 : .atomCmp = (int (*)(const void *, const void *)) lngCmp,
1709 : .atomHash = (BUN (*)(const void *)) lngHash,
1710 : #endif
1711 : },
1712 : [TYPE_flt] = {
1713 : .name = "flt",
1714 : .storage = TYPE_flt,
1715 : .linear = true,
1716 : .size = sizeof(flt),
1717 : .atomNull = (void *) &flt_nil,
1718 : .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) fltFromStr,
1719 : .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) fltToStr,
1720 : .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) fltRead,
1721 : .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) fltWrite,
1722 : .atomCmp = (int (*)(const void *, const void *)) fltCmp,
1723 : .atomHash = (BUN (*)(const void *)) fltHash,
1724 : },
1725 : [TYPE_dbl] = {
1726 : .name = "dbl",
1727 : .storage = TYPE_dbl,
1728 : .linear = true,
1729 : .size = sizeof(dbl),
1730 : .atomNull = (void *) &dbl_nil,
1731 : .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) dblFromStr,
1732 : .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) dblToStr,
1733 : .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) dblRead,
1734 : .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) dblWrite,
1735 : .atomCmp = (int (*)(const void *, const void *)) dblCmp,
1736 : .atomHash = (BUN (*)(const void *)) dblHash,
1737 : },
1738 : [TYPE_lng] = {
1739 : .name = "lng",
1740 : .storage = TYPE_lng,
1741 : .linear = true,
1742 : .size = sizeof(lng),
1743 : .atomNull = (void *) &lng_nil,
1744 : .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) lngFromStr,
1745 : .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) lngToStr,
1746 : .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) lngRead,
1747 : .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) lngWrite,
1748 : .atomCmp = (int (*)(const void *, const void *)) lngCmp,
1749 : .atomHash = (BUN (*)(const void *)) lngHash,
1750 : },
1751 : #ifdef HAVE_HGE
1752 : [TYPE_hge] = {
1753 : .name = "hge",
1754 : .storage = TYPE_hge,
1755 : .linear = true,
1756 : .size = sizeof(hge),
1757 : .atomNull = (void *) &hge_nil,
1758 : .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) hgeFromStr,
1759 : .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) hgeToStr,
1760 : .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) hgeRead,
1761 : .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) hgeWrite,
1762 : .atomCmp = (int (*)(const void *, const void *)) hgeCmp,
1763 : .atomHash = (BUN (*)(const void *)) hgeHash,
1764 : },
1765 : #endif
1766 : [TYPE_date] = {
1767 : .name = "date",
1768 : .storage = TYPE_int,
1769 : .linear = true,
1770 : .size = sizeof(int),
1771 : .atomNull = (void *) &int_nil,
1772 : .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) date_fromstr,
1773 : .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) date_tostr,
1774 : .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) intRead,
1775 : .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) intWrite,
1776 : .atomCmp = (int (*)(const void *, const void *)) intCmp,
1777 : .atomHash = (BUN (*)(const void *)) intHash,
1778 : },
1779 : [TYPE_daytime] = {
1780 : .name = "daytime",
1781 : .storage = TYPE_lng,
1782 : .linear = true,
1783 : .size = sizeof(lng),
1784 : .atomNull = (void *) &lng_nil,
1785 : .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) daytime_tz_fromstr,
1786 : .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) daytime_tostr,
1787 : .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) lngRead,
1788 : .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) lngWrite,
1789 : .atomCmp = (int (*)(const void *, const void *)) lngCmp,
1790 : .atomHash = (BUN (*)(const void *)) lngHash,
1791 : },
1792 : [TYPE_timestamp] = {
1793 : .name = "timestamp",
1794 : .storage = TYPE_lng,
1795 : .linear = true,
1796 : .size = sizeof(lng),
1797 : .atomNull = (void *) &lng_nil,
1798 : .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) timestamp_fromstr,
1799 : .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) timestamp_tostr,
1800 : .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) lngRead,
1801 : .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) lngWrite,
1802 : .atomCmp = (int (*)(const void *, const void *)) lngCmp,
1803 : .atomHash = (BUN (*)(const void *)) lngHash,
1804 : },
1805 : [TYPE_uuid] = {
1806 : .name = "uuid",
1807 : .storage = TYPE_uuid,
1808 : .linear = true,
1809 : .size = sizeof(uuid),
1810 : .atomNull = (void *) &uuid_nil,
1811 : .atomFromStr = UUIDfromString,
1812 : .atomToStr = UUIDtoString,
1813 : .atomRead = UUIDread,
1814 : .atomWrite = UUIDwrite,
1815 : .atomCmp = UUIDcompare,
1816 : .atomHash = UUIDhash,
1817 : },
1818 : [TYPE_str] = {
1819 : .name = "str",
1820 : .storage = TYPE_str,
1821 : .linear = true,
1822 : .size = sizeof(var_t),
1823 : .atomNull = (void *) str_nil,
1824 : .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) strFromStr,
1825 : .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) strToStr,
1826 : .atomRead = (void *(*)(void *, size_t *, stream *, size_t)) strRead,
1827 : .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) strWrite,
1828 : .atomCmp = (int (*)(const void *, const void *)) strCmp,
1829 : .atomHash = (BUN (*)(const void *)) strHash,
1830 : .atomPut = strPut,
1831 : .atomLen = (size_t (*)(const void *)) strLen,
1832 : .atomHeap = strHeap,
1833 : },
1834 : [TYPE_blob] = {
1835 : .name = "blob",
1836 : .storage = TYPE_blob,
1837 : .linear = true,
1838 : .size = sizeof(var_t),
1839 : .atomNull = (void *) &blob_nil,
1840 : .atomFromStr = BLOBfromstr,
1841 : .atomToStr = BLOBtostr,
1842 : .atomRead = BLOBread,
1843 : .atomWrite = BLOBwrite,
1844 : .atomCmp = BLOBcmp,
1845 : .atomHash = BLOBhash,
1846 : .atomPut = BLOBput,
1847 : .atomDel = BLOBdel,
1848 : .atomLen = BLOBlength,
1849 : .atomHeap = BLOBheap,
1850 : },
1851 : };
1852 :
1853 : int GDKatomcnt = TYPE_blob + 1;
1854 :
1855 : /*
1856 : * Sometimes a bat descriptor is loaded before the dynamic module
1857 : * defining the atom is loaded. To support this an extra set of
1858 : * unknown atoms is kept. These can be accessed via the ATOMunknown
1859 : * interface. Finding an (negative) atom index can be done via
1860 : * ATOMunknown_find, which simply adds the atom if it's not in the
1861 : * unknown set. The index can be used to find the name of an unknown
1862 : * ATOM via ATOMunknown_name.
1863 : */
1864 : static str unknown[MAXATOMS] = { NULL };
1865 :
1866 : int
1867 241 : ATOMunknown_find(const char *nme)
1868 : {
1869 241 : int i, j = 0;
1870 :
1871 : /* first try to find the atom */
1872 241 : MT_lock_set(&GDKatomLock);
1873 7428 : for (i = 1; i < MAXATOMS; i++) {
1874 7133 : if (unknown[i]) {
1875 338 : if (strcmp(unknown[i], nme) == 0) {
1876 187 : MT_lock_unset(&GDKatomLock);
1877 187 : return -i;
1878 : }
1879 6795 : } else if (j == 0)
1880 6946 : j = i;
1881 : }
1882 54 : if (j == 0) {
1883 : /* no space for new atom (shouldn't happen) */
1884 0 : MT_lock_unset(&GDKatomLock);
1885 0 : return 0;
1886 : }
1887 54 : if ((unknown[j] = GDKstrdup(nme)) == NULL) {
1888 0 : MT_lock_unset(&GDKatomLock);
1889 0 : return 0;
1890 : }
1891 54 : MT_lock_unset(&GDKatomLock);
1892 54 : return -j;
1893 : }
1894 :
1895 : const char *
1896 297 : ATOMunknown_name(int i)
1897 : {
1898 297 : assert(i < 0);
1899 297 : assert(-i < MAXATOMS);
1900 297 : assert(unknown[-i]);
1901 297 : return unknown[-i];
1902 : }
1903 :
1904 : void
1905 356 : ATOMunknown_clean(void)
1906 : {
1907 356 : int i;
1908 :
1909 356 : MT_lock_set(&GDKatomLock);
1910 766 : for (i = 1; i < MAXATOMS; i++) {
1911 410 : if(unknown[i]) {
1912 54 : GDKfree(unknown[i]);
1913 54 : unknown[i] = NULL;
1914 : } else {
1915 : break;
1916 : }
1917 : }
1918 356 : MT_lock_unset(&GDKatomLock);
1919 356 : }
|