Reduct  v1.0.4-3-gdaf0d70
A functional and immutable language.
Loading...
Searching...
No Matches
atom_impl.h
Go to the documentation of this file.
1#ifndef REDUCT_ATOM_IMPL_H
2#define REDUCT_ATOM_IMPL_H 1
3
4#include "atom.h"
5#include "char.h"
6#include "core.h"
7
9{
10 REDUCT_ASSERT(reduct != REDUCT_NULL);
12
13 reduct_size_t bucket = atom->hash % REDUCT_BUCKETS_MAX;
14 reduct_atom_t** current = &reduct->atomBuckets[bucket];
15 while (*current)
16 {
17 if (*current == atom)
18 {
19 *current = atom->next;
20 break;
21 }
22 current = &(*current)->next;
23 }
24
25 if (atom->string != atom->small)
26 {
27 REDUCT_FREE(atom->string);
28 }
29}
30
32{
33 REDUCT_ASSERT(reduct != REDUCT_NULL);
34
35 char buf[32];
36 reduct_size_t len = 0;
37
38 unsigned long long uval;
39 reduct_bool_t isNegative;
40 if (value < 0)
41 {
42 isNegative = REDUCT_TRUE;
43 uval = (unsigned long long)(-value);
44 }
45 else
46 {
47 isNegative = REDUCT_FALSE;
48 uval = (unsigned long long)value;
49 }
50
51 if (uval == 0)
52 {
53 buf[sizeof(buf) - 1 - len++] = '0';
54 }
55 while (uval > 0)
56 {
57 buf[sizeof(buf) - 1 - len++] = (char)('0' + (uval % 10));
58 uval /= 10;
59 }
60 if (isNegative)
61 {
62 buf[sizeof(buf) - 1 - len++] = '-';
63 }
64
65 const char* str = buf + sizeof(buf) - len;
67 atom->integerValue = value;
70 return atom;
71}
72
74{
75 REDUCT_ASSERT(reduct != REDUCT_NULL);
76
77 char buf[64];
78 char sign = 1;
79 double val = value;
80
81 if (val < 0)
82 {
83 sign = -1;
84 val = -val;
85 }
86
87 val += 0.0000005;
88 unsigned long long intPart = (unsigned long long)val;
89 double fracPart = val - (double)intPart;
90 if (fracPart < 0)
91 {
92 fracPart = 0;
93 }
94
95 reduct_size_t len = 0;
96 char* p = buf + 32;
97 unsigned long long uIntPart = intPart;
98
99 if (uIntPart == 0)
100 {
101 *--p = '0';
102 len++;
103 }
104 else
105 {
106 while (uIntPart > 0)
107 {
108 *--p = (char)('0' + (uIntPart % 10));
109 uIntPart /= 10;
110 len++;
111 }
112 }
113 if (sign == -1)
114 {
115 *--p = '-';
116 len++;
117 }
118
119 char* res = p;
120 res[len++] = '.';
121
122 for (int i = 0; i < 6; i++)
123 {
124 fracPart *= 10.0;
125 int digit = (int)fracPart;
126 res[len++] = (char)('0' + digit);
127 fracPart -= (double)digit;
128 }
129
130 while (len > 1 && res[len - 1] == '0' && res[len - 2] != '.')
131 {
132 len--;
133 }
134
136 atom->floatValue = value;
139 return atom;
140}
141
144{
145 REDUCT_ASSERT(reduct != REDUCT_NULL);
147
148 reduct_size_t hash = reduct_hash(str, len);
149 if (flags & REDUCT_ATOM_LOOKUP_QUOTED)
150 {
151 hash ^= 0x5bd1e995;
152 }
153 reduct_size_t bucket = hash % REDUCT_BUCKETS_MAX;
154
155 reduct_atom_t** current = &reduct->atomBuckets[bucket];
156 while (*current)
157 {
158 reduct_atom_t* atom = *current;
160 reduct_bool_t isQuoted = (item->flags & REDUCT_ITEM_FLAG_QUOTED) != 0;
161 reduct_bool_t wantQuoted = (flags & REDUCT_ATOM_LOOKUP_QUOTED) != 0;
162 if (atom->hash == hash && isQuoted == wantQuoted && reduct_atom_is_equal(atom, str, len))
163 {
164 if (current != &reduct->atomBuckets[bucket])
165 {
166 *current = atom->next;
167 atom->next = reduct->atomBuckets[bucket];
168 reduct->atomBuckets[bucket] = atom;
169 }
170 return atom;
171 }
172 current = &(*current)->next;
173 }
174
175 reduct_item_t* item = reduct_item_new(reduct);
177 if (flags & REDUCT_ATOM_LOOKUP_QUOTED)
178 {
180 }
181 reduct_atom_t* atom = &item->atom;
182 atom->length = len;
183 atom->hash = hash;
185 atom->next = reduct->atomBuckets[bucket];
186 reduct->atomBuckets[bucket] = atom;
187
188 if (len < REDUCT_ATOM_SMALL_MAX)
189 {
190 REDUCT_MEMCPY(atom->small, str, len);
191 atom->small[len] = '\0';
192 atom->string = atom->small;
193 }
194 else
195 {
196 atom->string = REDUCT_MALLOC(len + 1);
197 if (atom->string == REDUCT_NULL)
198 {
199 REDUCT_ERROR_INTERNAL(reduct, "out of memory");
200 }
201 REDUCT_MEMCPY(atom->string, str, len);
202 atom->string[len] = '\0';
203 }
204
205 return atom;
206}
207
209{
210 REDUCT_ASSERT(atom != REDUCT_NULL);
211
212 char* str = atom->string;
213 reduct_size_t len = atom->length;
214 reduct_size_t j = 0;
215 for (reduct_size_t i = 0; i < len; i++)
216 {
217 if (str[i] == '\\' && i + 1 < len)
218 {
219 i++;
220 const reduct_char_info_t* info = &reductCharTable[(unsigned char)str[i]];
221 if (info->decodeEscape != 0)
222 {
223 str[j++] = info->decodeEscape;
224 continue;
225 }
226 else if (str[i] == 'x' && i + 2 < len)
227 {
228 unsigned char high = reductCharTable[(unsigned char)str[i + 1]].integer;
229 unsigned char low = reductCharTable[(unsigned char)str[i + 2]].integer;
230 str[j++] = (char)((high << 4) | low);
231 i += 2;
232 continue;
233 }
234 }
235 else
236 {
237 str[j++] = str[i];
238 }
239 }
240 atom->length = j;
241 if (atom->length < REDUCT_ATOM_SMALL_MAX)
242 {
243 str[j] = '\0';
244 }
245 else
246 {
247 atom->string[j] = '\0';
248 }
249}
250
252{
253 REDUCT_UNUSED(reduct);
254
255 REDUCT_ASSERT(reduct != REDUCT_NULL);
256 REDUCT_ASSERT(atom != REDUCT_NULL);
257
259 if (atom->length == 0)
260 {
262 return;
263 }
264
265 if (item->flags & REDUCT_ITEM_FLAG_QUOTED)
266 {
268 }
269
270 const char* p = atom->string;
271 const char* end = p + atom->length;
272 const char* start = p;
273 int sign = 1;
274
275 if (p < end && (*p == '+' || *p == '-'))
276 {
277 if (*p == '-')
278 {
279 sign = -1;
280 }
281 p++;
282 }
283
284 if (p == end)
285 {
286 return;
287 }
288
289 if (end - p == 3)
290 {
291 if (REDUCT_CHAR_TO_LOWER(p[0]) == 'i' && REDUCT_CHAR_TO_LOWER(p[1]) == 'n' && REDUCT_CHAR_TO_LOWER(p[2]) == 'f')
292 {
294 atom->floatValue = sign > 0 ? REDUCT_INF : -REDUCT_INF;
295 return;
296 }
297 if (p == start && REDUCT_CHAR_TO_LOWER(p[0]) == 'n' && REDUCT_CHAR_TO_LOWER(p[1]) == 'a' &&
298 REDUCT_CHAR_TO_LOWER(p[2]) == 'n')
299 {
301 atom->floatValue = REDUCT_NAN;
302 return;
303 }
304 }
305
306 int base = 10;
307 if (p + 1 < end && *p == '0')
308 {
309 char l = REDUCT_CHAR_TO_LOWER(p[1]);
310 if (l == 'x')
311 {
312 base = 16;
313 p += 2;
314 }
315 else if (l == 'o')
316 {
317 base = 8;
318 p += 2;
319 }
320 else if (l == 'b')
321 {
322 base = 2;
323 p += 2;
324 }
325 }
326
327 reduct_bool_t hasDigits = REDUCT_FALSE;
328 reduct_bool_t sectionHasDigits = REDUCT_FALSE;
330
331 if (base != 10)
332 {
333 reduct_uint64_t intValue = 0;
334 while (p < end)
335 {
336 if (*p == '_')
337 {
338 if (!sectionHasDigits)
339 {
340 valid = REDUCT_FALSE;
341 break;
342 }
343 p++;
344 continue;
345 }
346
347 int d = -1;
348 unsigned char c = (unsigned char)*p;
350 {
352 }
353
354 if (d >= 0 && d < base)
355 {
356 intValue = intValue * base + d;
357 hasDigits = REDUCT_TRUE;
358 sectionHasDigits = REDUCT_TRUE;
359 }
360 else
361 {
362 valid = REDUCT_FALSE;
363 break;
364 }
365 p++;
366 }
367 if (valid && hasDigits && p == end && *(end - 1) != '_')
368 {
370 atom->integerValue = sign * (reduct_int64_t)intValue;
371 if (atom->integerValue == 0)
372 {
374 }
375 }
376 return;
377 }
378
379 reduct_bool_t isFloat = REDUCT_FALSE;
380 reduct_uint64_t intValue = 0;
381 double floatValue = 0.0;
382 double fractionDiv = 10.0;
383 reduct_bool_t inFraction = REDUCT_FALSE;
384 reduct_bool_t inExponent = REDUCT_FALSE;
385 reduct_int64_t expSign = 1;
386 reduct_int64_t expValue = 0;
387 reduct_int64_t exponentDigits = 0;
388
389 if (*p == '.')
390 {
391 isFloat = REDUCT_TRUE;
392 inFraction = REDUCT_TRUE;
393 p++;
394 }
395
396 while (p < end)
397 {
398 if (*p == '_')
399 {
400 if (!sectionHasDigits)
401 {
402 valid = REDUCT_FALSE;
403 break;
404 }
405 p++;
406 continue;
407 }
408
409 unsigned char c = (unsigned char)*p;
411 {
412 hasDigits = REDUCT_TRUE;
413 sectionHasDigits = REDUCT_TRUE;
414 if (inExponent)
415 {
416 expValue = expValue * 10 + reductCharTable[c].integer;
417 exponentDigits++;
418 }
419 else if (inFraction)
420 {
421 floatValue = floatValue + reductCharTable[c].integer / fractionDiv;
422 fractionDiv *= 10.0;
423 }
424 else
425 {
426 intValue = intValue * 10 + reductCharTable[c].integer;
427 floatValue = floatValue * 10.0 + reductCharTable[c].integer;
428 }
429 }
430 else if (c == '.' && !inFraction && !inExponent)
431 {
432 if (*(p - 1) == '_')
433 {
434 valid = REDUCT_FALSE;
435 break;
436 }
437 isFloat = REDUCT_TRUE;
438 inFraction = REDUCT_TRUE;
439 sectionHasDigits = REDUCT_FALSE;
440 }
441 else if (REDUCT_CHAR_TO_LOWER(c) == 'e' && !inExponent && hasDigits)
442 {
443 if (*(p - 1) == '_')
444 {
445 valid = REDUCT_FALSE;
446 break;
447 }
448 isFloat = REDUCT_TRUE;
449 inExponent = REDUCT_TRUE;
450 sectionHasDigits = REDUCT_FALSE;
451 p++;
452 if (p < end && (*p == '+' || *p == '-'))
453 {
454 if (*p == '-')
455 {
456 expSign = -1;
457 }
458 p++;
459 }
460 continue;
461 }
462 else
463 {
464 valid = REDUCT_FALSE;
465 break;
466 }
467 p++;
468 }
469
470 if (inExponent && exponentDigits == 0)
471 {
472 valid = REDUCT_FALSE;
473 }
474
475 if (valid && hasDigits && p == end && *(end - 1) != '_')
476 {
477 if (isFloat)
478 {
480 double finalVal = floatValue;
481 if (inExponent && expValue != 0)
482 {
483 double eMult = 1.0;
484 double baseMult = 10.0;
485 int e = expValue;
486 while (e > 0)
487 {
488 if (e % 2 != 0)
489 {
490 eMult *= baseMult;
491 }
492 baseMult *= baseMult;
493 e /= 2;
494 }
495 if (expSign < 0)
496 {
497 finalVal /= eMult;
498 }
499 else
500 {
501 finalVal *= eMult;
502 }
503 }
504 atom->floatValue = sign * finalVal;
505 if (atom->floatValue == 0.0)
506 {
508 }
509 }
510 else
511 {
513 atom->integerValue = sign * (reduct_int64_t)intValue;
514 if (atom->integerValue == 0)
515 {
517 }
518 }
519 }
520}
521
522#endif
Atom representation and operations.
REDUCT_API void reduct_atom_normalize(reduct_t *reduct, reduct_atom_t *atom)
Definition atom_impl.h:251
REDUCT_API reduct_atom_t * reduct_atom_lookup(reduct_t *reduct, const char *str, reduct_size_t len, reduct_atom_lookup_flags_t flags)
Definition atom_impl.h:142
REDUCT_API reduct_atom_t * reduct_atom_lookup_float(reduct_t *reduct, reduct_float_t value)
Definition atom_impl.h:73
REDUCT_API void reduct_atom_deinit(reduct_t *reduct, reduct_atom_t *atom)
Definition atom_impl.h:8
static void reduct_atom_normalize_escape(reduct_atom_t *atom)
Definition atom_impl.h:208
REDUCT_API reduct_atom_t * reduct_atom_lookup_int(reduct_t *reduct, reduct_int64_t value)
Definition atom_impl.h:31
Character handling.
Core definitions and structures.
#define REDUCT_MALLOC(_size)
Definition defs.h:27
size_t reduct_size_t
Definition defs.h:100
reduct_bool_t
Boolean type.
Definition defs.h:135
@ REDUCT_FALSE
Definition defs.h:137
@ REDUCT_TRUE
Definition defs.h:136
#define REDUCT_INF
INFINITY constant.
Definition defs.h:153
#define REDUCT_CONTAINER_OF(_ptr, _type, _member)
Container of macro.
Definition defs.h:184
int64_t reduct_int64_t
Definition defs.h:92
#define REDUCT_NAN
NAN constant.
Definition defs.h:163
#define REDUCT_MEMCPY(_dest, _src, _size)
Definition defs.h:33
double reduct_float_t
Definition defs.h:102
#define REDUCT_ASSERT(_cond)
Definition defs.h:25
#define REDUCT_FREE(_ptr)
Definition defs.h:30
#define REDUCT_API
Definition defs.h:7
#define REDUCT_UNUSED(_x)
Definition defs.h:126
uint64_t reduct_uint64_t
Definition defs.h:93
#define REDUCT_NULL
Definition defs.h:23
reduct_atom_lookup_flags_t
Atom lookup flags.
Definition atom.h:38
static REDUCT_ALWAYS_INLINE reduct_bool_t reduct_atom_is_equal(reduct_atom_t *atom, const char *str, reduct_size_t len)
Check if an atom is equal to a string.
Definition atom.h:112
#define REDUCT_ATOM_SMALL_MAX
The maximum length of a small atom.
Definition atom.h:32
static REDUCT_ALWAYS_INLINE reduct_uint32_t reduct_hash(const char *str, reduct_size_t len)
Hash a string.
Definition atom.h:72
@ REDUCT_ATOM_LOOKUP_NONE
No flags.
Definition atom.h:39
@ REDUCT_ATOM_LOOKUP_QUOTED
Atom should be explicitly quoted.
Definition atom.h:40
#define REDUCT_CHAR_TO_LOWER(_c)
Get the lowercase equivalent of a character.
Definition char.h:62
reduct_char_info_t reductCharTable[256]
Global character lookup table.
Definition char_impl.h:6
#define REDUCT_CHAR_IS_DIGIT(_c)
Check if a character is a decimal digit.
Definition char.h:94
#define REDUCT_CHAR_IS_HEX_DIGIT(_c)
Check if a character is a hexidecimal digit.
Definition char.h:110
#define REDUCT_BUCKETS_MAX
Amount of buckets used for intering atoms.
Definition core.h:19
#define REDUCT_ERROR_INTERNAL(_reduct,...)
Throw an internal error using the jump buffer in the error structure.
Definition error.h:183
#define REDUCT_INTRINSIC_NONE
None.
Definition intrinsic.h:30
#define REDUCT_ITEM_TYPE_ATOM
An atom.
Definition item.h:27
#define REDUCT_ITEM_FLAG_INT_SHAPED
Item is an integer shaped atom.
Definition item.h:39
#define REDUCT_ITEM_FLAG_FLOAT_SHAPED
Item is a float shaped atom.
Definition item.h:40
REDUCT_API reduct_item_t * reduct_item_new(struct reduct *reduct)
Allocate a new Reduct item.
#define REDUCT_ITEM_FLAG_FALSY
Item is falsy.
Definition item.h:38
#define REDUCT_ITEM_FLAG_QUOTED
Item is a quoted atom.
Definition item.h:43
Atom structure.
Definition atom.h:48
char small[REDUCT_ATOM_SMALL_MAX]
The small string buffer.
Definition atom.h:51
reduct_int64_t integerValue
Pre-computed integer value, item must have REDUCT_ITEM_FLAG_INT_SHAPED.
Definition atom.h:55
reduct_uint32_t hash
The hash of the string.
Definition atom.h:50
reduct_uint32_t length
The length of the string (must be first, check the reduct_item_t structure).
Definition atom.h:49
char * string
Pointer to the string.
Definition atom.h:53
struct reduct_atom * next
Pointer to the next atom in the hash map.
Definition atom.h:59
reduct_float_t floatValue
Pre-computed float value, item must have REDUCT_ITEM_FLAG_FLOAT_SHAPED.
Definition atom.h:56
reduct_intrinsic_t intrinsic
Cached intrinsic, item must have REDUCT_ITEM_FLAG_INTRINSIC.
Definition atom.h:52
char decodeEscape
The char to decode to when escaped.
Definition char.h:38
unsigned char integer
Integer value.
Definition char.h:40
Item structure.
Definition item.h:57
reduct_item_flags_t flags
Flags for the item.
Definition item.h:60
reduct_atom_t atom
An atom.
Definition item.h:66
reduct_item_type_t type
The type of the item.
Definition item.h:61
State structure.
Definition core.h:61
struct reduct_atom * atomBuckets[REDUCT_BUCKETS_MAX]
Definition core.h:75