1 | /* |
2 | * This Source Code Form is subject to the terms of the Mozilla Public |
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
5 | * |
6 | * Copyright 1997 - July 2008 CWI, August 2008 - 2019 MonetDB B.V. |
7 | */ |
8 | |
9 | /* |
10 | * @a M. L. Kersten, P. Boncz |
11 | * @* Atomic types |
12 | * The Binary Association Table library assumes efficient |
13 | * implementation of the atoms making up the binary association. This |
14 | * section describes the preliminaries for handling both built-in and |
15 | * user-defined atomic types. |
16 | * New types, such as point and polygons, can be readily added to this |
17 | * collection. |
18 | */ |
19 | /* |
20 | * @- inline comparison routines |
21 | * Return 0 on l==r, < 0 iff l < r, >0 iff l > r |
22 | */ |
23 | #include "monetdb_config.h" |
24 | #include "gdk.h" |
25 | #include "gdk_private.h" |
26 | #include <math.h> |
27 | |
28 | /* the *Cmp functions return a value less than zero if the first |
29 | * argument is less than the second; they return zero if the two |
30 | * values are equal; and they return a value greater than zero if the |
31 | * first argument is greater than the second. Remember that in all |
32 | * cases, nil is considered smaller than any other value and nil is |
33 | * equal to itself (this has repercussions for the floating point |
34 | * implementation if and when its NIL value is the floating point |
35 | * NaN). */ |
36 | |
37 | static int |
38 | bteCmp(const bte *l, const bte *r) |
39 | { |
40 | return (*l > *r) - (*l < *r); |
41 | } |
42 | |
43 | static int |
44 | shtCmp(const sht *l, const sht *r) |
45 | { |
46 | return (*l > *r) - (*l < *r); |
47 | } |
48 | |
49 | static int |
50 | intCmp(const int *l, const int *r) |
51 | { |
52 | return (*l > *r) - (*l < *r); |
53 | } |
54 | |
55 | static int |
56 | fltCmp(const flt *l, const flt *r) |
57 | { |
58 | return is_flt_nil(*l) ? -!is_flt_nil(*r) : is_flt_nil(*r) ? 1 : (*l > *r) - (*l < *r); |
59 | } |
60 | |
61 | static int |
62 | lngCmp(const lng *l, const lng *r) |
63 | { |
64 | return (*l > *r) - (*l < *r); |
65 | } |
66 | |
67 | #ifdef HAVE_HGE |
68 | static int |
69 | hgeCmp(const hge *l, const hge *r) |
70 | { |
71 | return (*l > *r) - (*l < *r); |
72 | } |
73 | #endif |
74 | |
75 | static int |
76 | dblCmp(const dbl *l, const dbl *r) |
77 | { |
78 | return is_dbl_nil(*l) ? -!is_dbl_nil(*r) : is_dbl_nil(*r) ? 1 : (*l > *r) - (*l < *r); |
79 | } |
80 | |
81 | /* |
82 | * @- inline hash routines |
83 | * Return some positive integer derived from one atom value. |
84 | */ |
85 | static BUN |
86 | bteHash(const bte *v) |
87 | { |
88 | return (BUN) mix_bte(*(const unsigned char *) v); |
89 | } |
90 | |
91 | static BUN |
92 | shtHash(const sht *v) |
93 | { |
94 | return (BUN) mix_sht(*(const unsigned short *) v); |
95 | } |
96 | |
97 | static BUN |
98 | intHash(const int *v) |
99 | { |
100 | return (BUN) mix_int(*(const unsigned int *) v); |
101 | } |
102 | |
103 | static BUN |
104 | lngHash(const lng *v) |
105 | { |
106 | return (BUN) mix_lng(*(const ulng *) v); |
107 | } |
108 | |
109 | #ifdef HAVE_HGE |
110 | static BUN |
111 | hgeHash(const hge *v) |
112 | { |
113 | return (BUN) mix_hge(*(const uhge *) v); |
114 | } |
115 | #endif |
116 | |
117 | /* |
118 | * @+ Standard Atoms |
119 | */ |
120 | static int |
121 | batFix(const bat *b) |
122 | { |
123 | return BBPretain(*b); |
124 | } |
125 | |
126 | static int |
127 | batUnfix(const bat *b) |
128 | { |
129 | return BBPrelease(*b); |
130 | } |
131 | |
132 | /* |
133 | * @+ Atomic Type Interface |
134 | * The collection of built-in types supported for BATs can be extended |
135 | * easily. In essence, the user should specify conversion routines |
136 | * from values stored anywhere in memory to its equivalent in the BAT, |
137 | * and vice verse. Some routines are required for coercion and to |
138 | * support the BAT administration. |
139 | * |
140 | * A new type is incrementally build using the routine |
141 | * ATOMallocate(id). The parameter id denotes the type name; an entry |
142 | * is created if the type is so far unknown. |
143 | * |
144 | * The size describes the amount of space to be reserved in the BUN. |
145 | * |
146 | * The routine put takes a pointer to a memory resident copy and |
147 | * prepares a persistent copy in the BAT passed. The inverse |
148 | * operation is get. A new value can be directly included into the |
149 | * BAT using new, which should prepare a null-value representation. A |
150 | * value is removed from the BAT store using del, which can take care |
151 | * of garbage collection and BAT administration. |
152 | * |
153 | * The pair tostr and fromstr should convert a reference to a |
154 | * persistent value to a memory resident string equivalent. FromStr |
155 | * takes a string and applies a put to store it within a BAT. They |
156 | * are used to prepare for readable output/input and to support |
157 | * coercion. |
158 | * |
159 | * The routines cmp and eq are comparison routines used to build |
160 | * access structures. The null returns a reference to a null value |
161 | * representation. |
162 | * |
163 | * The incremental atom construction uses hardwired properties. This |
164 | * should be improved later on. |
165 | */ |
166 | int |
167 | ATOMallocate(const char *id) |
168 | { |
169 | int t; |
170 | |
171 | if (strlen(id) >= IDLENGTH) { |
172 | GDKerror("ATOMallocate: name too long" ); |
173 | return int_nil; |
174 | } |
175 | |
176 | MT_lock_set(&GDKthreadLock); |
177 | t = ATOMindex(id); |
178 | if (t < 0) { |
179 | t = -t; |
180 | if (t == GDKatomcnt) { |
181 | if (GDKatomcnt == MAXATOMS) { |
182 | MT_lock_unset(&GDKthreadLock); |
183 | GDKerror("ATOMallocate: too many types" ); |
184 | return int_nil; |
185 | } |
186 | GDKatomcnt++; |
187 | } |
188 | BATatoms[t] = (atomDesc) { |
189 | .size = sizeof(int), /* default */ |
190 | .linear = true, /* default */ |
191 | .storage = t, /* default */ |
192 | }; |
193 | strcpy(BATatoms[t].name, id); |
194 | } |
195 | MT_lock_unset(&GDKthreadLock); |
196 | return t; |
197 | } |
198 | |
199 | int |
200 | ATOMindex(const char *nme) |
201 | { |
202 | int t, j = GDKatomcnt; |
203 | |
204 | for (t = 0; t < GDKatomcnt; t++) { |
205 | if (!BATatoms[t].name[0]) { |
206 | if (j == GDKatomcnt) |
207 | j = t; |
208 | } else if (strcmp(nme, BATatoms[t].name) == 0) { |
209 | return t; |
210 | } |
211 | |
212 | } |
213 | if (strcmp(nme, "bat" ) == 0) { |
214 | return TYPE_bat; |
215 | } |
216 | return -j; |
217 | } |
218 | |
219 | char * |
220 | ATOMname(int t) |
221 | { |
222 | return t >= 0 && t < GDKatomcnt && *BATatoms[t].name ? BATatoms[t].name : "null" ; |
223 | } |
224 | |
225 | bool |
226 | ATOMisdescendant(int tpe, int parent) |
227 | { |
228 | int cur = -1; |
229 | |
230 | while (cur != tpe) { |
231 | cur = tpe; |
232 | if (cur == parent) |
233 | return true; |
234 | tpe = ATOMstorage(tpe); |
235 | } |
236 | return false; |
237 | } |
238 | |
239 | |
240 | const bte bte_nil = GDK_bte_min-1; |
241 | const sht sht_nil = GDK_sht_min-1; |
242 | const int int_nil = GDK_int_min-1; |
243 | #ifdef NAN_CANNOT_BE_USED_AS_INITIALIZER |
244 | /* Definition of NAN is seriously broken on Intel compiler (at least |
245 | * in some versions), so we work around it. */ |
246 | const union _flt_nil_t _flt_nil_ = { |
247 | .l = UINT32_C(0x7FC00000) |
248 | }; |
249 | const union _dbl_nil_t _dbl_nil_ = { |
250 | .l = UINT64_C(0x7FF8000000000000) |
251 | }; |
252 | #else |
253 | const flt flt_nil = NAN; |
254 | const dbl dbl_nil = NAN; |
255 | #endif |
256 | const lng lng_nil = GDK_lng_min-1; |
257 | #ifdef HAVE_HGE |
258 | const hge hge_nil = GDK_hge_min-1; |
259 | #endif |
260 | const oid oid_nil = (oid) 1 << (sizeof(oid) * 8 - 1); |
261 | const ptr ptr_nil = NULL; |
262 | |
263 | ptr |
264 | ATOMnil(int t) |
265 | { |
266 | const void *src = ATOMnilptr(t); |
267 | size_t len = ATOMlen(ATOMtype(t), src); |
268 | ptr dst = GDKmalloc(len); |
269 | |
270 | if (dst) |
271 | memcpy(dst, src, len); |
272 | return dst; |
273 | } |
274 | |
275 | /* |
276 | * @- Atomic ADT functions |
277 | */ |
278 | size_t |
279 | ATOMlen(int t, const void *src) |
280 | { |
281 | size_t (*l)(const void *) = BATatoms[t].atomLen; |
282 | |
283 | return l ? (*l) (src) : ATOMsize(t); |
284 | } |
285 | |
286 | gdk_return |
287 | ATOMheap(int t, Heap *hp, size_t cap) |
288 | { |
289 | void (*h) (Heap *, size_t) = BATatoms[t].atomHeap; |
290 | |
291 | if (h) { |
292 | (*h) (hp, cap); |
293 | if (hp->base == NULL) |
294 | return GDK_FAIL; |
295 | } |
296 | return GDK_SUCCEED; |
297 | } |
298 | |
299 | /* |
300 | * Atom print avoids coercion to strings for built-in types. |
301 | * The comparison against the NULL value is hard coded for speed. |
302 | */ |
303 | #define LINE_LEN 60 |
304 | |
305 | int |
306 | ATOMprint(int t, const void *p, stream *s) |
307 | { |
308 | ssize_t (*tostr) (char **, size_t *, const void *, bool); |
309 | ssize_t res; |
310 | |
311 | if (p && t >= 0 && t < GDKatomcnt && (tostr = BATatoms[t].atomToStr)) { |
312 | size_t sz; |
313 | |
314 | if (t != TYPE_bat && t < TYPE_str) { |
315 | char buf[dblStrlen], *addr = buf; /* use memory from stack */ |
316 | |
317 | sz = dblStrlen; |
318 | res = (*tostr) (&addr, &sz, p, true); |
319 | if (res > 0) |
320 | res = mnstr_write(s, buf, (size_t) res, 1); |
321 | } else { |
322 | str buf = NULL; |
323 | |
324 | sz = 0; |
325 | res = (*tostr) (&buf, &sz, p, true); |
326 | if (res > 0) |
327 | res = mnstr_write(s, buf, (size_t) res, 1); |
328 | GDKfree(buf); |
329 | } |
330 | } else { |
331 | res = mnstr_write(s, "nil" , 1, 3); |
332 | } |
333 | if (res < 0) |
334 | GDKsyserror("ATOMprint: write failure\n" ); |
335 | return (int) res; |
336 | } |
337 | |
338 | |
339 | char * |
340 | ATOMformat(int t, const void *p) |
341 | { |
342 | ssize_t (*tostr) (char **, size_t *, const void *, bool); |
343 | |
344 | if (p && 0 <= t && t < GDKatomcnt && (tostr = BATatoms[t].atomToStr)) { |
345 | size_t sz = 0; |
346 | char *buf = NULL; |
347 | ssize_t res = (*tostr) (&buf, &sz, p, true); |
348 | if (res < 0 && buf) { |
349 | GDKfree(buf); |
350 | buf = NULL; |
351 | } |
352 | return buf; |
353 | } |
354 | return GDKstrdup("nil" ); |
355 | } |
356 | |
357 | ptr |
358 | ATOMdup(int t, const void *p) |
359 | { |
360 | size_t len = ATOMlen(t, p); |
361 | ptr n = GDKmalloc(len); |
362 | |
363 | if (n) |
364 | memcpy(n, p, len); |
365 | return n; |
366 | } |
367 | |
368 | /* |
369 | * @* Builtin Atomic Operator Implementations |
370 | * |
371 | * @+ Atom-from-String Conversions |
372 | * These routines convert from string to atom. They are used during |
373 | * conversion and BAT import. In order to avoid unnecessary |
374 | * malloc()/free() sequences, the conversion functions have a meta |
375 | * 'dst' pointer to a destination region, and an integer* 'len' |
376 | * parameter, that denotes the length of that region (a char region |
377 | * for ToStr functions, an atom region from FromStr conversions). Only |
378 | * if necessary will the conversion routine do a GDKfree()/GDKmalloc() |
379 | * sequence, and increment the 'len'. Passing a pointer to a nil-ptr |
380 | * as 'dst' and/or a *len==0 is valid; the conversion function will |
381 | * then alloc some region for you. |
382 | */ |
383 | #define atommem(size) \ |
384 | do { \ |
385 | if (*dst == NULL || *len < (size)) { \ |
386 | GDKfree(*dst); \ |
387 | *len = (size); \ |
388 | *dst = GDKmalloc(*len); \ |
389 | if (*dst == NULL) { \ |
390 | *len = 0; \ |
391 | return -1; \ |
392 | } \ |
393 | } \ |
394 | } while (0) |
395 | |
396 | #define is_ptr_nil(val) ((val) == ptr_nil) |
397 | |
398 | #define atomtostr(TYPE, FMT, FMTCAST) \ |
399 | ssize_t \ |
400 | TYPE##ToStr(char **dst, size_t *len, const TYPE *src, bool external) \ |
401 | { \ |
402 | atommem(TYPE##Strlen); \ |
403 | if (is_##TYPE##_nil(*src)) { \ |
404 | if (external) { \ |
405 | strcpy(*dst, "nil"); \ |
406 | return 3; \ |
407 | } \ |
408 | strcpy(*dst, str_nil); \ |
409 | return 1; \ |
410 | } \ |
411 | return snprintf(*dst, *len, FMT, FMTCAST *src); \ |
412 | } |
413 | |
414 | #define num10(x) GDKisdigit(x) |
415 | #define base10(x) ((x) - '0') |
416 | |
417 | #define num16(x) isxdigit((unsigned char) (x)) |
418 | #define base16(x) (((x) >= 'a' && (x) <= 'f') ? ((x) - 'a' + 10) : ((x) >= 'A' && (x) <= 'F') ? ((x) - 'A' + 10) : (x) - '0') |
419 | #define mult16(x) ((x) << 4) |
420 | |
421 | static void * |
422 | voidRead(void *a, stream *s, size_t cnt) |
423 | { |
424 | (void) s; |
425 | (void) cnt; |
426 | return a; |
427 | } |
428 | |
429 | static gdk_return |
430 | voidWrite(const void *a, stream *s, size_t cnt) |
431 | { |
432 | (void) a; |
433 | (void) s; |
434 | (void) cnt; |
435 | return GDK_SUCCEED; |
436 | } |
437 | |
438 | /* |
439 | * Converts string values such as TRUE/FALSE/true/false etc to 1/0/NULL. |
440 | * Switched from byte-to-byte compare to library function strncasecmp, |
441 | * experiments showed that library function is even slightly faster and we |
442 | * now also support True/False (and trUe/FAlSE should this become a thing). |
443 | */ |
444 | ssize_t |
445 | bitFromStr(const char *src, size_t *len, bit **dst, bool external) |
446 | { |
447 | const char *p = src; |
448 | |
449 | atommem(sizeof(bit)); |
450 | |
451 | **dst = bit_nil; |
452 | |
453 | if (GDK_STRNIL(src)) |
454 | return 1; |
455 | |
456 | while (GDKisspace(*p)) |
457 | p++; |
458 | if (*p == '0') { |
459 | **dst = FALSE; |
460 | p++; |
461 | } else if (*p == '1') { |
462 | **dst = TRUE; |
463 | p++; |
464 | } else if (strncasecmp(p, "true" , 4) == 0) { |
465 | **dst = TRUE; |
466 | p += 4; |
467 | } else if (strncasecmp(p, "false" , 5) == 0) { |
468 | **dst = FALSE; |
469 | p += 5; |
470 | } else if (external && strncasecmp(p, "nil" , 3) == 0) { |
471 | p += 3; |
472 | } else { |
473 | return -1; |
474 | } |
475 | while (GDKisspace(*p)) |
476 | p++; |
477 | return (ssize_t) (p - src); |
478 | } |
479 | |
480 | ssize_t |
481 | bitToStr(char **dst, size_t *len, const bit *src, bool external) |
482 | { |
483 | atommem(6); |
484 | |
485 | if (is_bit_nil(*src)) { |
486 | if (external) { |
487 | strcpy(*dst, "nil" ); |
488 | return 3; |
489 | } |
490 | strcpy(*dst, str_nil); |
491 | return 1; |
492 | } |
493 | if (*src) { |
494 | strcpy(*dst, "true" ); |
495 | return 4; |
496 | } |
497 | strcpy(*dst, "false" ); |
498 | return 5; |
499 | } |
500 | |
501 | ssize_t |
502 | batFromStr(const char *src, size_t *len, bat **dst, bool external) |
503 | { |
504 | char *s; |
505 | const char *t, *r = src; |
506 | int c; |
507 | bat bid = 0; |
508 | |
509 | atommem(sizeof(bat)); |
510 | |
511 | if (GDK_STRNIL(src)) { |
512 | **dst = bat_nil; |
513 | return 1; |
514 | } |
515 | |
516 | while (GDKisspace(*r)) |
517 | r++; |
518 | |
519 | if (external && strcmp(r, "nil" ) == 0) { |
520 | **dst = bat_nil; |
521 | return (ssize_t) (r - src) + 3; |
522 | } |
523 | |
524 | if (*r == '<') |
525 | r++; |
526 | t = r; |
527 | while ((c = *t) && (c == '_' || GDKisalnum(c))) |
528 | t++; |
529 | |
530 | s = GDKstrndup(r, t - r); |
531 | if (s == NULL) |
532 | return -1; |
533 | bid = BBPindex(s); |
534 | GDKfree(s); |
535 | **dst = bid == 0 ? bat_nil : bid; |
536 | return (ssize_t) (t + (c == '>') - src); |
537 | } |
538 | |
539 | ssize_t |
540 | batToStr(char **dst, size_t *len, const bat *src, bool external) |
541 | { |
542 | bat b = *src; |
543 | size_t i; |
544 | str s; |
545 | |
546 | if (is_bat_nil(b) || (s = BBPname(b)) == NULL || *s == 0) { |
547 | atommem(4); |
548 | if (external) { |
549 | strcpy(*dst, "nil" ); |
550 | return 3; |
551 | } |
552 | strcpy(*dst, str_nil); |
553 | return 1; |
554 | } |
555 | i = strlen(s) + 3; |
556 | atommem(i); |
557 | return (ssize_t) strconcat_len(*dst, *len, "<" , s, ">" , NULL); |
558 | } |
559 | |
560 | |
561 | /* |
562 | * numFromStr parses the head of the string for a number, accepting an |
563 | * optional sign. The code has been prepared to continue parsing by |
564 | * returning the number of characters read. Both overflow and |
565 | * incorrect syntax (not a number) result in the function returning 0 |
566 | * and setting the destination to nil. |
567 | */ |
568 | struct maxdiv { |
569 | /* if we want to multiply a value with scale, the value must |
570 | * be no larger than maxval for there to not be overflow */ |
571 | #ifdef HAVE_HGE |
572 | hge scale, maxval; |
573 | #else |
574 | lng scale, maxval; |
575 | #endif |
576 | }; |
577 | static const struct maxdiv maxdiv[] = { |
578 | #ifdef HAVE_HGE |
579 | /* maximum hge value: 170141183460469231731687303715884105727 (2**127-1) |
580 | * GCC doesn't currently support integer constants that don't |
581 | * fit in 8 bytes, so we split large values up*/ |
582 | {(hge) LL_CONSTANT(1), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(10000000000000000000U)+ (hge) LL_CONSTANT(1687303715884105727)}, |
583 | {(hge) LL_CONSTANT(10), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(1000000000000000000) + (hge) LL_CONSTANT(168730371588410572)}, |
584 | {(hge) LL_CONSTANT(100), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(100000000000000000) + (hge) LL_CONSTANT(16873037158841057)}, |
585 | {(hge) LL_CONSTANT(1000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(10000000000000000) + (hge) LL_CONSTANT(1687303715884105)}, |
586 | {(hge) LL_CONSTANT(10000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(1000000000000000) + (hge) LL_CONSTANT(168730371588410)}, |
587 | {(hge) LL_CONSTANT(100000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(100000000000000) + (hge) LL_CONSTANT(16873037158841)}, |
588 | {(hge) LL_CONSTANT(1000000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(10000000000000) + (hge) LL_CONSTANT(1687303715884)}, |
589 | {(hge) LL_CONSTANT(10000000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(1000000000000) + (hge) LL_CONSTANT(168730371588)}, |
590 | {(hge) LL_CONSTANT(100000000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(100000000000) + (hge) LL_CONSTANT(16873037158)}, |
591 | {(hge) LL_CONSTANT(1000000000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(10000000000) + (hge) LL_CONSTANT(1687303715)}, |
592 | {(hge) LL_CONSTANT(10000000000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(1000000000) + (hge) LL_CONSTANT(168730371)}, |
593 | {(hge) LL_CONSTANT(100000000000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(100000000) + (hge) LL_CONSTANT(16873037)}, |
594 | {(hge) LL_CONSTANT(1000000000000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(10000000) + (hge) LL_CONSTANT(1687303)}, |
595 | {(hge) LL_CONSTANT(10000000000000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(1000000) + (hge) LL_CONSTANT(168730)}, |
596 | {(hge) LL_CONSTANT(100000000000000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(100000) + (hge) LL_CONSTANT(16873)}, |
597 | {(hge) LL_CONSTANT(1000000000000000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(10000) + (hge) LL_CONSTANT(1687)}, |
598 | {(hge) LL_CONSTANT(10000000000000000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(1000) + (hge) LL_CONSTANT(168)}, |
599 | {(hge) LL_CONSTANT(100000000000000000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(100) + (hge) LL_CONSTANT(16)}, |
600 | {(hge) LL_CONSTANT(1000000000000000000), (hge) LL_CONSTANT(17014118346046923173U) * LL_CONSTANT(10) + (hge) LL_CONSTANT(1)}, |
601 | {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(1), (hge) LL_CONSTANT(17014118346046923173U)}, |
602 | {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(10), (hge) LL_CONSTANT(1701411834604692317)}, |
603 | {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(100), (hge) LL_CONSTANT(170141183460469231)}, |
604 | {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(1000), (hge) LL_CONSTANT(17014118346046923)}, |
605 | {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(10000), (hge) LL_CONSTANT(1701411834604692)}, |
606 | {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(100000), (hge) LL_CONSTANT(170141183460469)}, |
607 | {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(1000000), (hge) LL_CONSTANT(17014118346046)}, |
608 | {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(10000000), (hge) LL_CONSTANT(1701411834604)}, |
609 | {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(100000000), (hge) LL_CONSTANT(170141183460)}, |
610 | {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(1000000000), (hge) LL_CONSTANT(17014118346)}, |
611 | {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(10000000000), (hge) LL_CONSTANT(1701411834)}, |
612 | {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(100000000000), (hge) LL_CONSTANT(170141183)}, |
613 | {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(1000000000000), (hge) LL_CONSTANT(17014118)}, |
614 | {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(10000000000000), (hge) LL_CONSTANT(1701411)}, |
615 | {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(100000000000000), (hge) LL_CONSTANT(170141)}, |
616 | {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(1000000000000000), (hge) LL_CONSTANT(17014)}, |
617 | {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(10000000000000000), (hge) LL_CONSTANT(1701)}, |
618 | {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(100000000000000000), (hge) LL_CONSTANT(170)}, |
619 | {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(1000000000000000000), (hge) LL_CONSTANT(17)}, |
620 | {(hge) LL_CONSTANT(10000000000000000000U) * LL_CONSTANT(10000000000000000000U),(hge) LL_CONSTANT(1)}, |
621 | #else |
622 | /* maximum lng value: 9223372036854775807 (2**63-1) */ |
623 | {LL_CONSTANT(1), LL_CONSTANT(9223372036854775807)}, |
624 | {LL_CONSTANT(10), LL_CONSTANT(922337203685477580)}, |
625 | {LL_CONSTANT(100), LL_CONSTANT(92233720368547758)}, |
626 | {LL_CONSTANT(1000), LL_CONSTANT(9223372036854775)}, |
627 | {LL_CONSTANT(10000), LL_CONSTANT(922337203685477)}, |
628 | {LL_CONSTANT(100000), LL_CONSTANT(92233720368547)}, |
629 | {LL_CONSTANT(1000000), LL_CONSTANT(9223372036854)}, |
630 | {LL_CONSTANT(10000000), LL_CONSTANT(922337203685)}, |
631 | {LL_CONSTANT(100000000), LL_CONSTANT(92233720368)}, |
632 | {LL_CONSTANT(1000000000), LL_CONSTANT(9223372036)}, |
633 | {LL_CONSTANT(10000000000), LL_CONSTANT(922337203)}, |
634 | {LL_CONSTANT(100000000000), LL_CONSTANT(92233720)}, |
635 | {LL_CONSTANT(1000000000000), LL_CONSTANT(9223372)}, |
636 | {LL_CONSTANT(10000000000000), LL_CONSTANT(922337)}, |
637 | {LL_CONSTANT(100000000000000), LL_CONSTANT(92233)}, |
638 | {LL_CONSTANT(1000000000000000), LL_CONSTANT(9223)}, |
639 | {LL_CONSTANT(10000000000000000), LL_CONSTANT(922)}, |
640 | {LL_CONSTANT(100000000000000000), LL_CONSTANT(92)}, |
641 | {LL_CONSTANT(1000000000000000000), LL_CONSTANT(9)}, |
642 | #endif |
643 | }; |
644 | static const int maxmod10 = 7; /* (int) (maxdiv[0].maxval % 10) */ |
645 | |
646 | static ssize_t |
647 | numFromStr(const char *src, size_t *len, void **dst, int tp, bool external) |
648 | { |
649 | const char *p = src; |
650 | size_t sz = ATOMsize(tp); |
651 | #ifdef HAVE_HGE |
652 | hge base = 0; |
653 | #else |
654 | lng base = 0; |
655 | #endif |
656 | int sign = 1; |
657 | |
658 | /* a valid number has the following syntax: |
659 | * [-+]?[0-9]+([eE][0-9]+)?(LL)? -- PCRE syntax, or in other words |
660 | * optional sign, one or more digits, optional exponent, optional LL |
661 | * the exponent has the following syntax: |
662 | * lower or upper case letter E, one or more digits |
663 | * embedded spaces are not allowed |
664 | * the optional LL at the end are only allowed for lng and hge |
665 | * values */ |
666 | atommem(sz); |
667 | |
668 | if (GDK_STRNIL(src)) { |
669 | memcpy(*dst, ATOMnilptr(tp), sz); |
670 | return 1; |
671 | } |
672 | |
673 | while (GDKisspace(*p)) |
674 | p++; |
675 | if (!num10(*p)) { |
676 | switch (*p) { |
677 | case 'n': |
678 | if (external) { |
679 | memcpy(*dst, ATOMnilptr(tp), sz); |
680 | if (p[1] == 'i' && p[2] == 'l') { |
681 | p += 3; |
682 | return (ssize_t) (p - src); |
683 | } |
684 | } |
685 | GDKerror("not a number" ); |
686 | goto bailout; |
687 | case '-': |
688 | sign = -1; |
689 | p++; |
690 | break; |
691 | case '+': |
692 | p++; |
693 | break; |
694 | } |
695 | if (!num10(*p)) { |
696 | GDKerror("not a number" ); |
697 | goto bailout; |
698 | } |
699 | } |
700 | do { |
701 | int dig = base10(*p); |
702 | if (base > maxdiv[1].maxval || |
703 | (base == maxdiv[1].maxval && dig > maxmod10)) { |
704 | /* overflow */ |
705 | goto overflow; |
706 | } |
707 | base = 10 * base + dig; |
708 | p++; |
709 | } while (num10(*p)); |
710 | if ((*p == 'e' || *p == 'E') && num10(p[1])) { |
711 | p++; |
712 | if (base == 0) { |
713 | /* if base is 0, any exponent will do, the |
714 | * result is still 0 */ |
715 | while (num10(*p)) |
716 | p++; |
717 | } else { |
718 | int exp = 0; |
719 | do { |
720 | /* this calculation cannot overflow */ |
721 | exp = exp * 10 + base10(*p); |
722 | if (exp >= (int) (sizeof(maxdiv) / sizeof(maxdiv[0]))) { |
723 | /* overflow */ |
724 | goto overflow; |
725 | } |
726 | p++; |
727 | } while (num10(*p)); |
728 | if (base > maxdiv[exp].maxval) { |
729 | /* overflow */ |
730 | goto overflow; |
731 | } |
732 | base *= maxdiv[exp].scale; |
733 | } |
734 | } |
735 | base *= sign; |
736 | switch (sz) { |
737 | case 1: { |
738 | bte **dstbte = (bte **) dst; |
739 | if (base < GDK_bte_min || base > GDK_bte_max) { |
740 | goto overflow; |
741 | } |
742 | **dstbte = (bte) base; |
743 | break; |
744 | } |
745 | case 2: { |
746 | sht **dstsht = (sht **) dst; |
747 | if (base < GDK_sht_min || base > GDK_sht_max) { |
748 | goto overflow; |
749 | } |
750 | **dstsht = (sht) base; |
751 | break; |
752 | } |
753 | case 4: { |
754 | int **dstint = (int **) dst; |
755 | if (base < GDK_int_min || base > GDK_int_max) { |
756 | goto overflow; |
757 | } |
758 | **dstint = (int) base; |
759 | break; |
760 | } |
761 | case 8: { |
762 | lng **dstlng = (lng **) dst; |
763 | #ifdef HAVE_HGE |
764 | if (base < GDK_lng_min || base > GDK_lng_max) { |
765 | goto overflow; |
766 | } |
767 | #endif |
768 | **dstlng = (lng) base; |
769 | if (p[0] == 'L' && p[1] == 'L') |
770 | p += 2; |
771 | break; |
772 | } |
773 | #ifdef HAVE_HGE |
774 | case 16: { |
775 | hge **dsthge = (hge **) dst; |
776 | **dsthge = (hge) base; |
777 | if (p[0] == 'L' && p[1] == 'L') |
778 | p += 2; |
779 | break; |
780 | } |
781 | #endif |
782 | } |
783 | while (GDKisspace(*p)) |
784 | p++; |
785 | return (ssize_t) (p - src); |
786 | |
787 | overflow: |
788 | while (num10(*p)) |
789 | p++; |
790 | GDKerror("overflow: \"%.*s\" does not fit in %s\n" , |
791 | (int) (p - src), src, ATOMname(tp)); |
792 | bailout: |
793 | memcpy(*dst, ATOMnilptr(tp), sz); |
794 | return -1; |
795 | } |
796 | |
797 | ssize_t |
798 | bteFromStr(const char *src, size_t *len, bte **dst, bool external) |
799 | { |
800 | return numFromStr(src, len, (void **) dst, TYPE_bte, external); |
801 | } |
802 | |
803 | ssize_t |
804 | shtFromStr(const char *src, size_t *len, sht **dst, bool external) |
805 | { |
806 | return numFromStr(src, len, (void **) dst, TYPE_sht, external); |
807 | } |
808 | |
809 | ssize_t |
810 | intFromStr(const char *src, size_t *len, int **dst, bool external) |
811 | { |
812 | return numFromStr(src, len, (void **) dst, TYPE_int, external); |
813 | } |
814 | |
815 | ssize_t |
816 | lngFromStr(const char *src, size_t *len, lng **dst, bool external) |
817 | { |
818 | return numFromStr(src, len, (void **) dst, TYPE_lng, external); |
819 | } |
820 | |
821 | #ifdef HAVE_HGE |
822 | ssize_t |
823 | hgeFromStr(const char *src, size_t *len, hge **dst, bool external) |
824 | { |
825 | return numFromStr(src, len, (void **) dst, TYPE_hge, external); |
826 | } |
827 | #endif |
828 | |
829 | #define atom_io(TYPE, NAME, CAST) \ |
830 | static TYPE * \ |
831 | TYPE##Read(TYPE *A, stream *s, size_t cnt) \ |
832 | { \ |
833 | TYPE *a = A; \ |
834 | if (a == NULL && (a = GDKmalloc(cnt * sizeof(TYPE))) == NULL) \ |
835 | return NULL; \ |
836 | if (mnstr_read##NAME##Array(s, (CAST *) a, cnt) == 0 || \ |
837 | mnstr_errnr(s)) { \ |
838 | if (a != A) \ |
839 | GDKfree(a); \ |
840 | return NULL; \ |
841 | } \ |
842 | return a; \ |
843 | } \ |
844 | static gdk_return \ |
845 | TYPE##Write(const TYPE *a, stream *s, size_t cnt) \ |
846 | { \ |
847 | return mnstr_write##NAME##Array(s, (const CAST *) a, cnt) ? \ |
848 | GDK_SUCCEED : GDK_FAIL; \ |
849 | } |
850 | |
851 | atom_io(bat, Int, int) |
852 | atom_io(bit, Bte, bte) |
853 | |
854 | atomtostr(bte, "%hhd" , ) |
855 | atom_io(bte, Bte, bte) |
856 | |
857 | atomtostr(sht, "%hd" , ) |
858 | atom_io(sht, Sht, sht) |
859 | |
860 | atomtostr(int, "%d" , ) |
861 | atom_io(int, Int, int) |
862 | |
863 | atomtostr(lng, LLFMT, ) |
864 | atom_io(lng, Lng, lng) |
865 | |
866 | #ifdef HAVE_HGE |
867 | #define HGE_LL018FMT "%018" PRId64 |
868 | #define HGE_LL18DIGITS LL_CONSTANT(1000000000000000000) |
869 | #define HGE_ABS(a) (((a) < 0) ? -(a) : (a)) |
870 | ssize_t |
871 | hgeToStr(char **dst, size_t *len, const hge *src, bool external) |
872 | { |
873 | atommem(hgeStrlen); |
874 | if (is_hge_nil(*src)) { |
875 | if (external) { |
876 | return (ssize_t) strcpy_len(*dst, "nil" , 4); |
877 | } |
878 | strcpy(*dst, str_nil); |
879 | return 1; |
880 | } |
881 | if ((hge) GDK_lng_min <= *src && *src <= (hge) GDK_lng_max) { |
882 | lng s = (lng) *src; |
883 | return lngToStr(dst, len, &s, external); |
884 | } else { |
885 | hge s = *src / HGE_LL18DIGITS; |
886 | ssize_t llen = hgeToStr(dst, len, &s, external); |
887 | if (llen < 0) |
888 | return llen; |
889 | snprintf(*dst + llen, *len - llen, HGE_LL018FMT, |
890 | (lng) HGE_ABS(*src % HGE_LL18DIGITS)); |
891 | return strlen(*dst); |
892 | } |
893 | } |
894 | atom_io(hge, Hge, hge) |
895 | #endif |
896 | |
897 | ssize_t |
898 | ptrFromStr(const char *src, size_t *len, ptr **dst, bool external) |
899 | { |
900 | size_t base = 0; |
901 | const char *p = src; |
902 | |
903 | atommem(sizeof(ptr)); |
904 | |
905 | **dst = ptr_nil; |
906 | if (GDK_STRNIL(src)) |
907 | return 1; |
908 | |
909 | while (GDKisspace(*p)) |
910 | p++; |
911 | if (external && strncmp(p, "nil" , 3) == 0) { |
912 | p += 3; |
913 | } else { |
914 | if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) { |
915 | p += 2; |
916 | } |
917 | if (!num16(*p)) { |
918 | GDKerror("not a number\n" ); |
919 | return -1; |
920 | } |
921 | while (num16(*p)) { |
922 | if (base >= ((size_t) 1 << (8 * sizeof(size_t) - 4))) { |
923 | GDKerror("overflow\n" ); |
924 | return -1; |
925 | } |
926 | base = mult16(base) + base16(*p); |
927 | p++; |
928 | } |
929 | **dst = (ptr) base; |
930 | } |
931 | while (GDKisspace(*p)) |
932 | p++; |
933 | return (ssize_t) (p - src); |
934 | } |
935 | |
936 | atomtostr(ptr, "%p" , ) |
937 | |
938 | #if SIZEOF_VOID_P == SIZEOF_INT |
939 | atom_io(ptr, Int, int) |
940 | #else /* SIZEOF_VOID_P == SIZEOF_LNG */ |
941 | atom_io(ptr, Lng, lng) |
942 | #endif |
943 | |
944 | ssize_t |
945 | dblFromStr(const char *src, size_t *len, dbl **dst, bool external) |
946 | { |
947 | const char *p = src; |
948 | ssize_t n = 0; |
949 | double d; |
950 | |
951 | /* alloc memory */ |
952 | atommem(sizeof(dbl)); |
953 | |
954 | if (GDK_STRNIL(src)) { |
955 | **dst = dbl_nil; |
956 | return 1; |
957 | } |
958 | |
959 | while (GDKisspace(*p)) |
960 | p++; |
961 | if (external && strncmp(p, "nil" , 3) == 0) { |
962 | **dst = dbl_nil; |
963 | p += 3; |
964 | n = (ssize_t) (p - src); |
965 | } else { |
966 | /* on overflow, strtod returns HUGE_VAL and sets |
967 | * errno to ERANGE; on underflow, it returns a value |
968 | * whose magnitude is no greater than the smallest |
969 | * normalized double, and may or may not set errno to |
970 | * ERANGE. We accept underflow, but not overflow. */ |
971 | char *pe; |
972 | errno = 0; |
973 | d = strtod(p, &pe); |
974 | if (p == pe) |
975 | p = src; /* nothing converted */ |
976 | else |
977 | p = pe; |
978 | n = (ssize_t) (p - src); |
979 | if (n == 0 || (errno == ERANGE && (d < -1 || d > 1)) |
980 | || !isfinite(d) /* no NaN or Infinte */ |
981 | ) { |
982 | GDKerror("overflow or not a number\n" ); |
983 | return -1; |
984 | } else { |
985 | while (src[n] && GDKisspace(src[n])) |
986 | n++; |
987 | **dst = (dbl) d; |
988 | } |
989 | } |
990 | return n; |
991 | } |
992 | |
993 | ssize_t |
994 | dblToStr(char **dst, size_t *len, const dbl *src, bool external) |
995 | { |
996 | int i; |
997 | |
998 | atommem(dblStrlen); |
999 | if (is_dbl_nil(*src)) { |
1000 | if (external) { |
1001 | strcpy(*dst, "nil" ); |
1002 | return 3; |
1003 | } |
1004 | strcpy(*dst, str_nil); |
1005 | return 1; |
1006 | } |
1007 | for (i = 4; i < 18; i++) { |
1008 | snprintf(*dst, *len, "%.*g" , i, *src); |
1009 | if (strtod(*dst, NULL) == *src) |
1010 | break; |
1011 | } |
1012 | return (ssize_t) strlen(*dst); |
1013 | } |
1014 | |
1015 | atom_io(dbl, Lng, lng) |
1016 | |
1017 | ssize_t |
1018 | fltFromStr(const char *src, size_t *len, flt **dst, bool external) |
1019 | { |
1020 | const char *p = src; |
1021 | ssize_t n = 0; |
1022 | float f; |
1023 | |
1024 | /* alloc memory */ |
1025 | atommem(sizeof(flt)); |
1026 | |
1027 | if (GDK_STRNIL(src)) { |
1028 | **dst = flt_nil; |
1029 | return 1; |
1030 | } |
1031 | |
1032 | while (GDKisspace(*p)) |
1033 | p++; |
1034 | if (external && strncmp(p, "nil" , 3) == 0) { |
1035 | **dst = flt_nil; |
1036 | p += 3; |
1037 | n = (ssize_t) (p - src); |
1038 | } else { |
1039 | /* on overflow, strtof returns HUGE_VALF and sets |
1040 | * errno to ERANGE; on underflow, it returns a value |
1041 | * whose magnitude is no greater than the smallest |
1042 | * normalized float, and may or may not set errno to |
1043 | * ERANGE. We accept underflow, but not overflow. */ |
1044 | char *pe; |
1045 | errno = 0; |
1046 | f = strtof(p, &pe); |
1047 | if (p == pe) |
1048 | p = src; /* nothing converted */ |
1049 | else |
1050 | p = pe; |
1051 | n = (ssize_t) (p - src); |
1052 | if (n == 0 || (errno == ERANGE && (f < -1 || f > 1)) |
1053 | || !isfinite(f) /* no NaN or infinite */) { |
1054 | GDKerror("overflow or not a number\n" ); |
1055 | return -1; |
1056 | } else { |
1057 | while (src[n] && GDKisspace(src[n])) |
1058 | n++; |
1059 | **dst = (flt) f; |
1060 | } |
1061 | } |
1062 | return n; |
1063 | } |
1064 | |
1065 | ssize_t |
1066 | fltToStr(char **dst, size_t *len, const flt *src, bool external) |
1067 | { |
1068 | int i; |
1069 | |
1070 | atommem(fltStrlen); |
1071 | if (is_flt_nil(*src)) { |
1072 | if (external) { |
1073 | strcpy(*dst, "nil" ); |
1074 | return 3; |
1075 | } |
1076 | strcpy(*dst, str_nil); |
1077 | return 1; |
1078 | } |
1079 | for (i = 4; i < 10; i++) { |
1080 | snprintf(*dst, *len, "%.*g" , i, *src); |
1081 | if (strtof(*dst, NULL) == *src) |
1082 | break; |
1083 | } |
1084 | return (ssize_t) strlen(*dst); |
1085 | } |
1086 | |
1087 | atom_io(flt, Int, int) |
1088 | |
1089 | |
1090 | /* |
1091 | * String conversion routines. |
1092 | */ |
1093 | ssize_t |
1094 | OIDfromStr(const char *src, size_t *len, oid **dst, bool external) |
1095 | { |
1096 | #if SIZEOF_OID == SIZEOF_INT |
1097 | int ui = 0, *uip = &ui; |
1098 | #else |
1099 | lng ui = 0, *uip = &ui; |
1100 | #endif |
1101 | size_t l = sizeof(ui); |
1102 | ssize_t pos = 0; |
1103 | const char *p = src; |
1104 | |
1105 | atommem(sizeof(oid)); |
1106 | |
1107 | **dst = oid_nil; |
1108 | if (GDK_STRNIL(src)) |
1109 | return 1; |
1110 | |
1111 | while (GDKisspace(*p)) |
1112 | p++; |
1113 | |
1114 | if (external && strncmp(p, "nil" , 3) == 0) |
1115 | return (ssize_t) (p - src) + 3; |
1116 | |
1117 | if (GDKisdigit(*p)) { |
1118 | #if SIZEOF_OID == SIZEOF_INT |
1119 | pos = intFromStr(p, &l, &uip, external); |
1120 | #else |
1121 | pos = lngFromStr(p, &l, &uip, external); |
1122 | #endif |
1123 | if (pos < 0) |
1124 | return pos; |
1125 | if (p[pos] == '@') { |
1126 | pos++; |
1127 | while (GDKisdigit(p[pos])) |
1128 | pos++; |
1129 | } |
1130 | if (ui >= 0) { |
1131 | **dst = ui; |
1132 | } |
1133 | p += pos; |
1134 | } else { |
1135 | GDKerror("not an OID\n" ); |
1136 | return -1; |
1137 | } |
1138 | while (GDKisspace(*p)) |
1139 | p++; |
1140 | return (ssize_t) (p - src); |
1141 | } |
1142 | |
1143 | ssize_t |
1144 | OIDtoStr(char **dst, size_t *len, const oid *src, bool external) |
1145 | { |
1146 | atommem(oidStrlen); |
1147 | |
1148 | if (is_oid_nil(*src)) { |
1149 | if (external) { |
1150 | strcpy(*dst, "nil" ); |
1151 | return 3; |
1152 | } |
1153 | strcpy(*dst, str_nil); |
1154 | return 1; |
1155 | } |
1156 | return snprintf(*dst, *len, OIDFMT "@0" , *src); |
1157 | } |
1158 | |
1159 | atomDesc BATatoms[MAXATOMS] = { |
1160 | [TYPE_void] = { |
1161 | .name = "void" , |
1162 | .storage = TYPE_void, |
1163 | .linear = true, |
1164 | #if SIZEOF_OID == SIZEOF_INT |
1165 | .atomNull = (void *) &int_nil, |
1166 | .atomCmp = (int (*)(const void *, const void *)) intCmp, |
1167 | .atomHash = (BUN (*)(const void *)) intHash, |
1168 | #else |
1169 | .atomNull = (void *) &lng_nil, |
1170 | .atomCmp = (int (*)(const void *, const void *)) lngCmp, |
1171 | .atomHash = (BUN (*)(const void *)) lngHash, |
1172 | #endif |
1173 | .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) OIDfromStr, |
1174 | .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) OIDtoStr, |
1175 | .atomRead = (void *(*)(void *, stream *, size_t)) voidRead, |
1176 | .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) voidWrite, |
1177 | }, |
1178 | [TYPE_bit] = { |
1179 | .name = "bit" , |
1180 | .storage = TYPE_bte, |
1181 | .linear = true, |
1182 | .size = sizeof(bit), |
1183 | .atomNull = (void *) &bte_nil, |
1184 | .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) bitFromStr, |
1185 | .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) bitToStr, |
1186 | .atomRead = (void *(*)(void *, stream *, size_t)) bitRead, |
1187 | .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) bitWrite, |
1188 | .atomCmp = (int (*)(const void *, const void *)) bteCmp, |
1189 | .atomHash = (BUN (*)(const void *)) bteHash, |
1190 | }, |
1191 | [TYPE_bte] = { |
1192 | .name = "bte" , |
1193 | .storage = TYPE_bte, |
1194 | .linear = true, |
1195 | .size = sizeof(bte), |
1196 | .atomNull = (void *) &bte_nil, |
1197 | .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) bteFromStr, |
1198 | .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) bteToStr, |
1199 | .atomRead = (void *(*)(void *, stream *, size_t)) bteRead, |
1200 | .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) bteWrite, |
1201 | .atomCmp = (int (*)(const void *, const void *)) bteCmp, |
1202 | .atomHash = (BUN (*)(const void *)) bteHash, |
1203 | }, |
1204 | [TYPE_sht] = { |
1205 | .name = "sht" , |
1206 | .storage = TYPE_sht, |
1207 | .linear = true, |
1208 | .size = sizeof(sht), |
1209 | .atomNull = (void *) &sht_nil, |
1210 | .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) shtFromStr, |
1211 | .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) shtToStr, |
1212 | .atomRead = (void *(*)(void *, stream *, size_t)) shtRead, |
1213 | .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) shtWrite, |
1214 | .atomCmp = (int (*)(const void *, const void *)) shtCmp, |
1215 | .atomHash = (BUN (*)(const void *)) shtHash, |
1216 | }, |
1217 | [TYPE_bat] = { |
1218 | .name = "BAT" , |
1219 | .storage = TYPE_int, |
1220 | .linear = true, |
1221 | .size = sizeof(bat), |
1222 | .atomNull = (void *) &int_nil, |
1223 | .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) batFromStr, |
1224 | .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) batToStr, |
1225 | .atomRead = (void *(*)(void *, stream *, size_t)) batRead, |
1226 | .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) batWrite, |
1227 | .atomCmp = (int (*)(const void *, const void *)) intCmp, |
1228 | .atomHash = (BUN (*)(const void *)) intHash, |
1229 | .atomFix = (int (*)(const void *)) batFix, |
1230 | .atomUnfix = (int (*)(const void *)) batUnfix, |
1231 | }, |
1232 | [TYPE_int] = { |
1233 | .name = "int" , |
1234 | .storage = TYPE_int, |
1235 | .linear = true, |
1236 | .size = sizeof(int), |
1237 | .atomNull = (void *) &int_nil, |
1238 | .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) intFromStr, |
1239 | .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) intToStr, |
1240 | .atomRead = (void *(*)(void *, stream *, size_t)) intRead, |
1241 | .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) intWrite, |
1242 | .atomCmp = (int (*)(const void *, const void *)) intCmp, |
1243 | .atomHash = (BUN (*)(const void *)) intHash, |
1244 | }, |
1245 | [TYPE_oid] = { |
1246 | .name = "oid" , |
1247 | .linear = true, |
1248 | .size = sizeof(oid), |
1249 | #if SIZEOF_OID == SIZEOF_INT |
1250 | .storage = TYPE_int, |
1251 | .atomNull = (void *) &int_nil, |
1252 | .atomRead = (void *(*)(void *, stream *, size_t)) intRead, |
1253 | .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) intWrite, |
1254 | .atomCmp = (int (*)(const void *, const void *)) intCmp, |
1255 | .atomHash = (BUN (*)(const void *)) intHash, |
1256 | #else |
1257 | .storage = TYPE_lng, |
1258 | .atomNull = (void *) &lng_nil, |
1259 | .atomRead = (void *(*)(void *, stream *, size_t)) lngRead, |
1260 | .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) lngWrite, |
1261 | .atomCmp = (int (*)(const void *, const void *)) lngCmp, |
1262 | .atomHash = (BUN (*)(const void *)) lngHash, |
1263 | #endif |
1264 | .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) OIDfromStr, |
1265 | .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) OIDtoStr, |
1266 | }, |
1267 | [TYPE_ptr] = { |
1268 | .name = "ptr" , |
1269 | .storage = TYPE_ptr, |
1270 | .linear = true, |
1271 | .size = sizeof(void *), |
1272 | .atomNull = (void *) &ptr_nil, |
1273 | .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) ptrFromStr, |
1274 | .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) ptrToStr, |
1275 | .atomRead = (void *(*)(void *, stream *, size_t)) ptrRead, |
1276 | .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) ptrWrite, |
1277 | #if SIZEOF_VOID_P == SIZEOF_INT |
1278 | .atomCmp = (int (*)(const void *, const void *)) intCmp, |
1279 | .atomHash = (BUN (*)(const void *)) intHash, |
1280 | #else /* SIZEOF_VOID_P == SIZEOF_LNG */ |
1281 | .atomCmp = (int (*)(const void *, const void *)) lngCmp, |
1282 | .atomHash = (BUN (*)(const void *)) lngHash, |
1283 | #endif |
1284 | }, |
1285 | [TYPE_flt] = { |
1286 | .name = "flt" , |
1287 | .storage = TYPE_flt, |
1288 | .linear = true, |
1289 | .size = sizeof(flt), |
1290 | .atomNull = (void *) &flt_nil, |
1291 | .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) fltFromStr, |
1292 | .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) fltToStr, |
1293 | .atomRead = (void *(*)(void *, stream *, size_t)) fltRead, |
1294 | .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) fltWrite, |
1295 | .atomCmp = (int (*)(const void *, const void *)) fltCmp, |
1296 | .atomHash = (BUN (*)(const void *)) intHash, |
1297 | }, |
1298 | [TYPE_dbl] = { |
1299 | .name = "dbl" , |
1300 | .storage = TYPE_dbl, |
1301 | .linear = true, |
1302 | .size = sizeof(dbl), |
1303 | .atomNull = (void *) &dbl_nil, |
1304 | .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) dblFromStr, |
1305 | .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) dblToStr, |
1306 | .atomRead = (void *(*)(void *, stream *, size_t)) dblRead, |
1307 | .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) dblWrite, |
1308 | .atomCmp = (int (*)(const void *, const void *)) dblCmp, |
1309 | .atomHash = (BUN (*)(const void *)) lngHash, |
1310 | }, |
1311 | [TYPE_lng] = { |
1312 | .name = "lng" , |
1313 | .storage = TYPE_lng, |
1314 | .linear = true, |
1315 | .size = sizeof(lng), |
1316 | .atomNull = (void *) &lng_nil, |
1317 | .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) lngFromStr, |
1318 | .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) lngToStr, |
1319 | .atomRead = (void *(*)(void *, stream *, size_t)) lngRead, |
1320 | .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) lngWrite, |
1321 | .atomCmp = (int (*)(const void *, const void *)) lngCmp, |
1322 | .atomHash = (BUN (*)(const void *)) lngHash, |
1323 | }, |
1324 | #ifdef HAVE_HGE |
1325 | [TYPE_hge] = { |
1326 | .name = "hge" , |
1327 | .storage = TYPE_hge, |
1328 | .linear = true, |
1329 | .size = sizeof(hge), |
1330 | .atomNull = (void *) &hge_nil, |
1331 | .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) hgeFromStr, |
1332 | .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) hgeToStr, |
1333 | .atomRead = (void *(*)(void *, stream *, size_t)) hgeRead, |
1334 | .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) hgeWrite, |
1335 | .atomCmp = (int (*)(const void *, const void *)) hgeCmp, |
1336 | .atomHash = (BUN (*)(const void *)) hgeHash, |
1337 | }, |
1338 | #endif |
1339 | [TYPE_str] = { |
1340 | .name = "str" , |
1341 | .storage = TYPE_str, |
1342 | .linear = true, |
1343 | .size = sizeof(var_t), |
1344 | .atomNull = (void *) str_nil, |
1345 | .atomFromStr = (ssize_t (*)(const char *, size_t *, void **, bool)) strFromStr, |
1346 | .atomToStr = (ssize_t (*)(char **, size_t *, const void *, bool)) strToStr, |
1347 | .atomRead = (void *(*)(void *, stream *, size_t)) strRead, |
1348 | .atomWrite = (gdk_return (*)(const void *, stream *, size_t)) strWrite, |
1349 | .atomCmp = (int (*)(const void *, const void *)) strCmp, |
1350 | .atomHash = (BUN (*)(const void *)) strHash, |
1351 | .atomPut = (var_t (*)(Heap *, var_t *, const void *)) strPut, |
1352 | .atomLen = (size_t (*)(const void *)) strLen, |
1353 | .atomHeap = strHeap, |
1354 | }, |
1355 | }; |
1356 | |
1357 | int GDKatomcnt = TYPE_str + 1; |
1358 | |
1359 | /* |
1360 | * Sometimes a bat descriptor is loaded before the dynamic module |
1361 | * defining the atom is loaded. To support this an extra set of |
1362 | * unknown atoms is kept. These can be accessed via the ATOMunknown |
1363 | * interface. Finding an (negative) atom index can be done via |
1364 | * ATOMunknown_find, which simply adds the atom if it's not in the |
1365 | * unknown set. The index can be used to find the name of an unknown |
1366 | * ATOM via ATOMunknown_name. |
1367 | */ |
1368 | static str unknown[MAXATOMS] = { NULL }; |
1369 | |
1370 | int |
1371 | ATOMunknown_find(const char *nme) |
1372 | { |
1373 | int i, j = 0; |
1374 | |
1375 | /* first try to find the atom */ |
1376 | MT_lock_set(&GDKthreadLock); |
1377 | for (i = 1; i < MAXATOMS; i++) { |
1378 | if (unknown[i]) { |
1379 | if (strcmp(unknown[i], nme) == 0) { |
1380 | MT_lock_unset(&GDKthreadLock); |
1381 | return -i; |
1382 | } |
1383 | } else if (j == 0) |
1384 | j = i; |
1385 | } |
1386 | if (j == 0) { |
1387 | /* no space for new atom (shouldn't happen) */ |
1388 | MT_lock_unset(&GDKthreadLock); |
1389 | return 0; |
1390 | } |
1391 | if ((unknown[j] = GDKstrdup(nme)) == NULL) { |
1392 | MT_lock_unset(&GDKthreadLock); |
1393 | return 0; |
1394 | } |
1395 | MT_lock_unset(&GDKthreadLock); |
1396 | return -j; |
1397 | } |
1398 | |
1399 | str |
1400 | ATOMunknown_name(int i) |
1401 | { |
1402 | assert(i < 0); |
1403 | assert(unknown[-i]); |
1404 | return unknown[-i]; |
1405 | } |
1406 | |
1407 | void |
1408 | ATOMunknown_clean(void) |
1409 | { |
1410 | int i; |
1411 | |
1412 | MT_lock_set(&GDKthreadLock); |
1413 | for (i = 1; i < MAXATOMS; i++) { |
1414 | if(unknown[i]) { |
1415 | GDKfree(unknown[i]); |
1416 | unknown[i] = NULL; |
1417 | } else { |
1418 | break; |
1419 | } |
1420 | } |
1421 | MT_lock_unset(&GDKthreadLock); |
1422 | } |
1423 | |