Reduct  v4.0.5-1-g4851deb
A functional and immutable language.
Loading...
Searching...
No Matches
handle.h
Go to the documentation of this file.
1#ifndef REDUCT_HANDLE_H
2#define REDUCT_HANDLE_H 1
3
4#include <reduct/atom.h>
5#include <reduct/defs.h>
6#include <reduct/error.h>
7#include <reduct/item.h>
8#include <reduct/standard.h>
9
10#include <math.h>
11
12struct reduct;
13
14/**
15 * @file handle.h
16 * @brief Handle management.
17 * @defgroup handle Handle
18 *
19 * A handle is a lightweight reference to a Reduct item, with the ability to cache a numeric value or reference
20 * an item using Tagged Pointers (NaN Boxing).
21 *
22 * ## 64-bit Handle Bit Layout
23 *
24 * The top 16 bits are used as a type tag. The remaining 48 bits represent the payload
25 * (either a 48-bit pointer or a shifted IEEE 754 double).
26 *
27 * | Tag (16 bits) | Payload (48 bits) |
28 * |-----------------|-----------------------------------|
29 * | `0x0000` | Item Pointer (`reduct_item_t*`) |
30 * | `0x0007...FFFF` | Number (Shifted IEEE 754 double) |
31 *
32 * @see [Wikipedia Tagged pointer](https://en.wikipedia.org/wiki/Tagged_pointer)
33 *
34 * @{
35 */
36
37/**
38 * @brief High-level handle types.
39 * @enum reduct_handle_type_t
40 */
41typedef enum
42{
43 REDUCT_HANDLE_TYPE_NONE = 0, ///< Invalid type.
44 REDUCT_HANDLE_TYPE_NUMBER, ///< Handle is a number or references a number shaped atom.
45 REDUCT_HANDLE_TYPE_ATOM, ///< Handle is a reference to an atom.
46 REDUCT_HANDLE_TYPE_LIST, ///< Handle is a reference to a list.
47 REDUCT_HANDLE_TYPE_FUNCTION, ///< Handle is a reference to a function.
48 REDUCT_HANDLE_TYPE_CLOSURE, ///< Handle is a reference to a closure.
49 REDUCT_HANDLE_TYPE_ARENA, ///< Handle is a reference to an arena.
50 REDUCT_HANDLE_TYPE_RVSDG_NODE, ///< Handle is a reference to an IR node.
51 REDUCT_HANDLE_TYPE_RVSDG_EDGE, ///< Handle is a reference to an IR edge.
52 REDUCT_HANDLE_TYPE_FUTURE, ///< Handle is a reference to a future.
53 REDUCT_HANDLE_TYPE_UNKNOWN ///< Handle is corrupt or otherwise invalid.
55
56#define REDUCT_HANDLE_OFFSET_NUMBER 0x0007000000000000ULL ///< Offset used for encoding doubles.
57
58#define REDUCT_HANDLE_TAG_ITEM 0x0000000000000000ULL ///< Tag for item handles.
59
60#define REDUCT_HANDLE_MASK_TAG 0xFFFF000000000000ULL ///< Mask for handle tag bits.
61#define REDUCT_HANDLE_MASK_VAL 0x0000FFFFFFFFFFFFULL ///< Mask for handle value bits.
62#define REDUCT_HANDLE_MASK_PTR REDUCT_HANDLE_MASK_VAL ///< Mask for item pointer bits.
63
64#define REDUCT_HANDLE_NUMBER_WIDTH 64 ///< The bit width used for shift operations on numbers.
65
66/**
67 * @brief Create a handle from a number.
68 *
69 * @param _val The number value.
70 * @return The handle.
71 */
72#define REDUCT_HANDLE_FROM_NUMBER(_val) \
73 ((reduct_handle_t){((union { \
74 double d; \
75 uint64_t u; \
76 }){.d = (_val)}) \
77 .u + \
78 REDUCT_HANDLE_OFFSET_NUMBER})
79
80/**
81 * @brief Create a handle from an item pointer.
82 *
83 * @param _ptr The pointer to the reduct_item_t.
84 * @return The handle.
85 */
86#define REDUCT_HANDLE_FROM_ITEM(_ptr) \
87 ((reduct_handle_t){REDUCT_HANDLE_TAG_ITEM | ((uintptr_t)(void*)(_ptr) & REDUCT_HANDLE_MASK_PTR)})
88
89/**
90 * @brief Create a handle from an atom pointer.
91 *
92 * @param _atom The pointer to the reduct_atom_t.
93 * @return The handle.
94 */
95#define REDUCT_HANDLE_FROM_ATOM(_atom) REDUCT_HANDLE_FROM_ITEM(REDUCT_CONTAINER_OF(_atom, reduct_item_t, atom))
96
97/**
98 * @brief Create a handle from a list pointer.
99 *
100 * @param _list The pointer to the reduct_list_t.
101 * @return The handle.
102 */
103#define REDUCT_HANDLE_FROM_LIST(_list) REDUCT_HANDLE_FROM_ITEM(REDUCT_CONTAINER_OF(_list, reduct_item_t, list))
104
105/**
106 * @brief Create a handle from a function pointer.
107 *
108 * @param _func The pointer to the reduct_function_t.
109 * @return The handle.
110 */
111#define REDUCT_HANDLE_FROM_FUNCTION(_func) REDUCT_HANDLE_FROM_ITEM(REDUCT_CONTAINER_OF(_func, reduct_item_t, function))
112
113/**
114 * @brief Create a handle from a closure pointer.
115 *
116 * @param _closure The pointer to the reduct_closure_t.
117 * @return The handle.
118 */
119#define REDUCT_HANDLE_FROM_CLOSURE(_closure) \
120 REDUCT_HANDLE_FROM_ITEM(REDUCT_CONTAINER_OF(_closure, reduct_item_t, closure))
121
122/**
123 * @brief Create a handle from an IR node pointer.
124 *
125 * @param _node The pointer to the reduct_rvsdg_node_t.
126 * @return The handle.
127 */
128#define REDUCT_HANDLE_FROM_RVSDG_NODE(_node) \
129 REDUCT_HANDLE_FROM_ITEM(REDUCT_CONTAINER_OF(_node, reduct_item_t, rvsdgNode))
130
131/**
132 * @brief Create a handle from an IR edge pointer.
133 *
134 * @param _edge The pointer to the reduct_rvsdg_edge_t.
135 * @return The handle.
136 */
137#define REDUCT_HANDLE_FROM_RVSDG_EDGE(_edge) \
138 REDUCT_HANDLE_FROM_ITEM(REDUCT_CONTAINER_OF(_edge, reduct_item_t, rvsdgEdge))
139
140/**
141 * @brief Create a boolean handle from a C condition.
142 *
143 * @param _reduct Pointer to the Reduct structure.
144 * @param _cond The condition to evaluate.
145 */
146#define REDUCT_HANDLE_FROM_BOOL(_reduct, _cond) ((_cond) ? REDUCT_HANDLE_TRUE() : REDUCT_HANDLE_FALSE(_reduct))
147
148/**
149 * @brief Create a handle from a future pointer.
150 *
151 * @param _future The pointer to the reduct_future_t.
152 * @return The handle.
153 */
154#define REDUCT_HANDLE_FROM_FUTURE(_future) REDUCT_HANDLE_FROM_ITEM(REDUCT_CONTAINER_OF(_future, reduct_item_t, future))
155
156/**
157 * @brief Check if a handle is a number.
158 *
159 * @param _handle Pointer to the handle.
160 * @return Non-zero if the handle is a number, zero otherwise.
161 */
162#define REDUCT_HANDLE_IS_NUMBER(_handle) (((_handle)._value) >= REDUCT_HANDLE_OFFSET_NUMBER)
163
164/**
165 * @brief Check if a handle is a number or references a number shaped item.
166 *
167 * @param _handle Pointer to the handle.
168 * @return Non-zero if the handle is number shaped, zero otherwise.
169 */
170#define REDUCT_HANDLE_IS_NUMBER_SHAPED(_handle) \
171 (REDUCT_HANDLE_IS_NUMBER(_handle) || \
172 (REDUCT_HANDLE_IS_ATOM(_handle) && reduct_atom_is_number(REDUCT_HANDLE_TO_ATOM(_handle))))
173
174/**
175 * @brief Get the high-level type of a handle.
176 *
177 * @param handle Pointer to the handle.
178 * @return The type of the handle.
179 */
181
182/**
183 * @brief Get the string name of a handle type.
184 *
185 * @param type The handle type.
186 * @return A constant string representing the type.
187 */
189
190/**
191 * @brief Get the string representation of the type of the item referenced by the handle.
192 *
193 * @param _handle Pointer to the handle.
194 * @return The string representation of the item type.
195 */
196#define REDUCT_HANDLE_GET_TYPE_STRING(_handle) (reduct_handle_type_string(reduct_handle_get_type(_handle)))
197
198/**
199 * @brief Check if a handle is nil (an empty list).
200 *
201 * @param _handle Pointer to the handle.
202 * @return Non-zero if the handle is nil, zero otherwise.
203 */
204#define REDUCT_HANDLE_IS_NIL(_handle) (REDUCT_HANDLE_IS_LIST(_handle) && REDUCT_HANDLE_TO_LIST(_handle)->length == 0)
205
206/**
207 * @brief Check if a handle is empty (nil or empty atom).
208 *
209 * @param _handle Pointer to the handle.
210 */
211#define REDUCT_HANDLE_IS_EMPTY(_handle) \
212 (REDUCT_HANDLE_IS_NIL(_handle) || (REDUCT_HANDLE_IS_ATOM(_handle) && REDUCT_HANDLE_TO_ATOM(_handle)->length == 0))
213
214/**
215 * @brief Check if a handle is an item.
216 *
217 * @param _handle Pointer to the handle.
218 * @return Non-zero if the handle is an item, zero otherwise.
219 */
220#define REDUCT_HANDLE_IS_ITEM(_handle) ((((_handle)._value) & REDUCT_HANDLE_MASK_TAG) == REDUCT_HANDLE_TAG_ITEM)
221
222/**
223 * @brief Check if a handle is an atom.
224 *
225 * @param _handle Pointer to the handle.
226 * @return Non-zero if the handle is an atom, zero otherwise.
227 */
228#define REDUCT_HANDLE_IS_ATOM(_handle) \
229 (REDUCT_HANDLE_IS_ITEM(_handle) && REDUCT_HANDLE_TO_ITEM(_handle)->type == REDUCT_ITEM_TYPE_ATOM)
230
231/**
232 * @brief Check if a handle is a list.
233 *
234 * @param _handle Pointer to the handle.
235 * @return Non-zero if the handle is a list, zero otherwise.
236 */
237#define REDUCT_HANDLE_IS_LIST(_handle) \
238 (REDUCT_HANDLE_IS_ITEM(_handle) && REDUCT_HANDLE_TO_ITEM(_handle)->type == REDUCT_ITEM_TYPE_LIST)
239
240/**
241 * @brief Check if a handle is a function.
242 *
243 * @param _handle Pointer to the handle.
244 * @return Non-zero if the handle is a function, zero otherwise.
245 */
246#define REDUCT_HANDLE_IS_FUNCTION(_handle) \
247 (REDUCT_HANDLE_IS_ITEM(_handle) && REDUCT_HANDLE_TO_ITEM(_handle)->type == REDUCT_ITEM_TYPE_FUNCTION)
248
249/**
250 * @brief Check if a handle is a closure.
251 *
252 * @param _handle Pointer to the handle.
253 * @return Non-zero if the handle is a closure, zero otherwise.
254 */
255#define REDUCT_HANDLE_IS_CLOSURE(_handle) \
256 (REDUCT_HANDLE_IS_ITEM(_handle) && REDUCT_HANDLE_TO_ITEM(_handle)->type == REDUCT_ITEM_TYPE_CLOSURE)
257
258/**
259 * @brief Check if a handle is an IR node.
260 *
261 * @param _handle Pointer to the handle.
262 * @return Non-zero if the handle is an IR node, zero otherwise.
263 */
264#define REDUCT_HANDLE_IS_RVSDG_NODE(_handle) \
265 (REDUCT_HANDLE_IS_ITEM(_handle) && REDUCT_HANDLE_TO_ITEM(_handle)->type == REDUCT_ITEM_TYPE_RVSDG_NODE)
266
267/**
268 * @brief Check if a handle is an IR edge.
269 *
270 * @param _handle Pointer to the handle.
271 * @return Non-zero if the handle is an IR edge, zero otherwise.
272 */
273#define REDUCT_HANDLE_IS_RVSDG_EDGE(_handle) \
274 (REDUCT_HANDLE_IS_ITEM(_handle) && REDUCT_HANDLE_TO_ITEM(_handle)->type == REDUCT_ITEM_TYPE_RVSDG_EDGE)
275
276/**
277 * @brief Check if a handle is a future.
278 *
279 * @param _handle Pointer to the handle.
280 */
281#define REDUCT_HANDLE_IS_FUTURE(_handle) \
282 (REDUCT_HANDLE_IS_ITEM(_handle) && REDUCT_HANDLE_TO_ITEM(_handle)->type == REDUCT_ITEM_TYPE_FUTURE)
283
284/**
285 * @brief Check if a handle is a lambda.
286 *
287 * @param _handle Pointer to the handle.
288 * @return Non-zero if the handle is a lambda, zero otherwise.
289 */
290#define REDUCT_HANDLE_IS_LAMBDA(_handle) (REDUCT_HANDLE_IS_FUNCTION(_handle) || REDUCT_HANDLE_IS_CLOSURE(_handle))
291
292/**
293 * @brief Check if a handle is a native function.
294 *
295 * @param _handle Pointer to the handle.
296 * @return Non-zero if the handle is a native function, zero otherwise.
297 */
298#define REDUCT_HANDLE_IS_NATIVE(_reduct, _handle) \
299 (REDUCT_HANDLE_IS_ATOM(_handle) && reduct_atom_is_native(_reduct, REDUCT_HANDLE_TO_ATOM(_handle)))
300
301/**
302 * @brief Check if a handle is an intrinsic function.
303 *
304 * @param _reduct Pointer to the Reduct structure.
305 * @param _handle Pointer to the handle.
306 * @return Non-zero if the handle is an intrinsic function, zero otherwise.
307 */
308#define REDUCT_HANDLE_IS_INTRINSIC(_reduct, _handle) \
309 (REDUCT_HANDLE_IS_ATOM(_handle) && reduct_atom_is_intrinsic(_reduct, REDUCT_HANDLE_TO_ATOM(_handle)))
310
311/**
312 * @brief Check if a handle is callable.
313 *
314 * @param _handle Pointer to the handle.
315 * @return Non-zero if the handle is callable, zero otherwise.
316 */
317#define REDUCT_HANDLE_IS_CALLABLE(_reduct, _handle) \
318 (REDUCT_HANDLE_IS_LAMBDA(_handle) || REDUCT_HANDLE_IS_NATIVE(_reduct, _handle))
319
320/**
321 * @brief Check if a handle either is an atom, or could be represented by an atom item.
322 *
323 * @param _handle Pointer to the handle.
324 * @return Non-zero if the handle is atom-like, zero otherwise.
325 */
326#define REDUCT_HANDLE_IS_ATOM_LIKE(_handle) (REDUCT_HANDLE_IS_NUMBER(_handle) || REDUCT_HANDLE_IS_ATOM(_handle))
327
328/**
329 * @brief Get the number value of a handle.
330 *
331 * @param _handle Pointer to the handle.
332 * @return The number value.
333 */
334#define REDUCT_HANDLE_TO_NUMBER(_handle) \
335 (((union { \
336 uint64_t u; \
337 double d; \
338 }){.u = ((_handle)._value) - REDUCT_HANDLE_OFFSET_NUMBER}) \
339 .d)
340
341/**
342 * @brief Get the item pointer of a handle.
343 *
344 * @param _handle Pointer to the handle.
345 * @return The item pointer.
346 */
347#define REDUCT_HANDLE_TO_ITEM(_handle) ((reduct_item_t*)(void*)(((_handle)._value) & REDUCT_HANDLE_MASK_PTR))
348
349/**
350 * @brief Get the atom pointer of a handle.
351 *
352 * @param _handle Pointer to the handle.
353 * @return The atom pointer.
354 */
355#define REDUCT_HANDLE_TO_ATOM(_handle) (&REDUCT_HANDLE_TO_ITEM(_handle)->atom)
356
357/**
358 * @brief Get the list pointer of a handle.
359 *
360 * @param _handle Pointer to the handle.
361 * @return The list pointer.
362 */
363#define REDUCT_HANDLE_TO_LIST(_handle) (&REDUCT_HANDLE_TO_ITEM(_handle)->list)
364
365/**
366 * @brief Get the function pointer of a handle.
367 *
368 * @param _handle Pointer to the handle.
369 * @return The function pointer.
370 */
371#define REDUCT_HANDLE_TO_FUNCTION(_handle) (&REDUCT_HANDLE_TO_ITEM(_handle)->function)
372
373/**
374 * @brief Get the closure pointer of a handle.
375 *
376 * @param _handle Pointer to the handle.
377 * @return The closure pointer.
378 */
379#define REDUCT_HANDLE_TO_CLOSURE(_handle) (&REDUCT_HANDLE_TO_ITEM(_handle)->closure)
380
381/**
382 * @brief Get the IR node pointer of a handle.
383 *
384 * @param _handle Pointer to the handle.
385 * @return The IR node pointer.
386 */
387#define REDUCT_HANDLE_TO_RVSDG_NODE(_handle) (&REDUCT_HANDLE_TO_ITEM(_handle)->rvsdgNode)
388
389/**
390 * @brief Get the IR edge pointer of a handle.
391 *
392 * @param _handle Pointer to the handle.
393 * @return The IR edge pointer.
394 */
395#define REDUCT_HANDLE_TO_RVSDG_EDGE(_handle) (&REDUCT_HANDLE_TO_ITEM(_handle)->rvsdgEdge)
396
397/**
398 * @brief Get the future pointer of a handle.
399 *
400 * @param _handle Pointer to the handle.
401 */
402#define REDUCT_HANDLE_TO_FUTURE(_handle) (&REDUCT_HANDLE_TO_ITEM(_handle)->future)
403
404/**
405 * @brief Get the boolean value of a handle.
406 *
407 * @param _handle Pointer to the handle.
408 * @return The boolean value.
409 */
410#define REDUCT_HANDLE_TO_BOOL(_handle) (REDUCT_HANDLE_IS_TRUTHY(_handle) ? true : false)
411
412/**
413 * @brief Create a list handle.
414 *
415 * @param _reduct Pointer to the Reduct structure.
416 * @param _length The length of the list.
417 */
418#define REDUCT_HANDLE_CREATE_LIST(_reduct, _length) REDUCT_HANDLE_FROM_LIST(reduct_list_new(_reduct, _length))
419
420/**
421 * @brief Create a list handle from an array of handles.
422 *
423 * @param _reduct Pointer to the Reduct structure.
424 * @param _count The number of handles.
425 * @param _handles The array of handles.
426 */
427#define REDUCT_HANDLE_CREATE_HANDLES(_reduct, _count, _handles) \
428 REDUCT_HANDLE_FROM_LIST(reduct_list_new_handles(_reduct, _count, _handles))
429
430/**
431 * @brief Create a list handle of pairs (key-value) from a variable number of pairs.
432 *
433 * @param _reduct Pointer to the Reduct structure.
434 * @param _count The number of pairs.
435 * @param ... Each pair should be provided as a `(const char*, reduct_handle_t)`.
436 */
437#define REDUCT_HANDLE_CREATE_ALIST(_reduct, _count, ...) \
438 REDUCT_HANDLE_FROM_LIST(reduct_list_new_alist(_reduct, _count, __VA_ARGS__))
439
440/**
441 * @brief Create an atom handle with a reserved size.
442 *
443 * @param _reduct Pointer to the Reduct structure.
444 * @param _len The length of the buffer.
445 */
446#define REDUCT_HANDLE_CREATE_ATOM(_reduct, _len) REDUCT_HANDLE_FROM_ATOM(reduct_atom_new(_reduct, _len))
447
448/**
449 * @brief Create an atom handle from a string.
450 *
451 * @param _reduct Pointer to the Reduct structure.
452 * @param _str The null-terminated string.
453 */
454#define REDUCT_HANDLE_CREATE_STRING(_reduct, _str) \
455 REDUCT_HANDLE_FROM_ATOM(reduct_atom_lookup(_reduct, _str, strlen(_str), REDUCT_ATOM_LOOKUP_QUOTED))
456
457/**
458 * @brief Create an interned atom handle from a string.
459 *
460 * @param _reduct Pointer to the Reduct structure.
461 * @param _str The null-terminated string.
462 */
463#define REDUCT_HANDLE_CREATE_SYMBOL(_reduct, _str) \
464 REDUCT_HANDLE_FROM_ATOM(reduct_atom_lookup(_reduct, _str, strlen(_str), REDUCT_ATOM_LOOKUP_NONE))
465
466/**
467 * @brief Create an atom handle from a number.
468 *
469 * @param _reduct Pointer to the Reduct structure.
470 * @param _val The number value.
471 */
472#define REDUCT_HANDLE_CREATE_NUMBER(_reduct, _val) REDUCT_HANDLE_FROM_ATOM(reduct_atom_new_number(_reduct, _val))
473
474/**
475 * @brief Create an atom handle from a native function.
476 *
477 * @param _reduct Pointer to the Reduct structure.
478 * @param _fn The native function pointer.
479 */
480#define REDUCT_HANDLE_CREATE_NATIVE(_reduct, _fn) REDUCT_HANDLE_FROM_ATOM(reduct_atom_new_native(_reduct, _fn))
481
482/**
483 * @brief Create a future handle.
484 *
485 * @param _reduct Pointer to the Reduct structure.
486 * @param _callable The callable handle.
487 * @param _argc The number of arguments.
488 * @param _argv Pointer to the arguments array.
489 */
490#define REDUCT_HANDLE_CREATE_FUTURE(_reduct, _callable, _argc, _argv) \
491 REDUCT_HANDLE_FROM_FUTURE(reduct_future_new(_reduct, _callable, _argc, _argv))
492
493/**
494 * @brief Macro for iterating over all elements in a list handle.
495 *
496 * @param _handle The reduct_handle_t variable to store each element.
497 * @param _list Pointer to the list handle.
498 */
499#define REDUCT_HANDLE_FOR_EACH(_handle, _list) REDUCT_LIST_FOR_EACH(_handle, REDUCT_HANDLE_TO_LIST(_list))
500
501/**
502 * @brief Get the value of the future referenced by the handle or the handle itself.
503 *
504 * @param _reduct Pointer to the Reduct structure.
505 * @param _handle The handle.
506 * @return The result of the future if the handle is a future, otherwise the handle itself.
507 */
508#define REDUCT_HANDLE_JOIN(_reduct, _handle) \
509 (REDUCT_HANDLE_IS_FUTURE(_handle) ? reduct_future_join(_reduct, REDUCT_HANDLE_TO_FUTURE(_handle)) : (_handle))
510
511/**
512 * @brief Get the constant nil handle.
513 *
514 * @param _reduct Pointer to the Reduct structure.
515 */
516#define REDUCT_HANDLE_NIL(_reduct) ((_reduct)->global->nil)
517/**
518 * @brief Get the constant false (nil) handle.
519 *
520 * @param _reduct Pointer to the Reduct structure.
521 */
522#define REDUCT_HANDLE_FALSE(_reduct) REDUCT_HANDLE_NIL(_reduct)
523
524#define REDUCT_HANDLE_TRUE() REDUCT_HANDLE_FROM_NUMBER(1.0) ///< Constant true handle.
525
526#define REDUCT_HANDLE_PI() REDUCT_HANDLE_FROM_NUMBER(REDUCT_PI) ///< Constant pi handle.
527
528#define REDUCT_HANDLE_E() REDUCT_HANDLE_FROM_NUMBER(REDUCT_E) ///< Constant e handle.
529
530#define REDUCT_HANDLE_INF() REDUCT_HANDLE_FROM_NUMBER(REDUCT_INF) ///< Constant infinity handle.
531
532#define REDUCT_HANDLE_NAN() REDUCT_HANDLE_FROM_NUMBER(REDUCT_NAN) ///< Constant not a number handle.
533
534/**
535 * @brief Compare two handles using a given operator with a fast path for numbers.
536 *
537 * @param _reduct Pointer to the Reduct structure.
538 * @param _a The first handle.
539 * @param _b The second handle.
540 * @param _op The comparison operator (e.g., <, >, <=, >=, etc.).
541 * @return The result of the comparison.
542 */
543#define REDUCT_HANDLE_COMPARE_FAST(_reduct, _a, _b, _op) \
544 (REDUCT_LIKELY((_a)._value >= REDUCT_HANDLE_OFFSET_NUMBER && (_b)._value >= REDUCT_HANDLE_OFFSET_NUMBER) \
545 ? (REDUCT_HANDLE_TO_NUMBER(_a) _op REDUCT_HANDLE_TO_NUMBER(_b)) \
546 : (reduct_handle_compare(_reduct, (_a), (_b)) _op 0))
547
548/**
549 * @brief Perform a arithmetic operation on two handles with a fast path for numbers.
550 *
551 * @param _reduct Pointer to the Reduct structure.
552 * @param _a The target handle.
553 * @param _b The first handle.
554 * @param _c The second handle.
555 * @param _op The arithmetic operator, (e.g., +, -, *, etc.)
556 */
557#define REDUCT_HANDLE_ARITHMETIC_FAST(_reduct, _a, _b, _c, _op) \
558 do \
559 { \
560 reduct_handle_t _bVal = (_b); \
561 reduct_handle_t _cVal = (_c); \
562 double _bv, _cv; \
563 if (REDUCT_LIKELY(REDUCT_HANDLE_IS_NUMBER(_bVal) && REDUCT_HANDLE_IS_NUMBER(_cVal))) \
564 { \
565 _bv = REDUCT_HANDLE_TO_NUMBER(_bVal); \
566 _cv = REDUCT_HANDLE_TO_NUMBER(_cVal); \
567 } \
568 else \
569 { \
570 _bv = reduct_handle_as_number(_reduct, _bVal); \
571 _cv = reduct_handle_as_number(_reduct, _cVal); \
572 } \
573 *(_a) = REDUCT_HANDLE_FROM_NUMBER(_bv _op _cv); \
574 } while (0)
575
576/**
577 * @brief Perform a division operation on two handles with a fast path for numbers.
578 *
579 * @param _reduct Pointer to the Reduct structure.
580 * @param _a The target handle.
581 * @param _b The first handle.
582 * @param _c The second handle.
583 */
584#define REDUCT_HANDLE_DIV_FAST(_reduct, _a, _b, _c) \
585 do \
586 { \
587 reduct_handle_t _bVal = (_b); \
588 reduct_handle_t _cVal = (_c); \
589 double _bv, _cv; \
590 if (REDUCT_LIKELY(REDUCT_HANDLE_IS_NUMBER(_bVal) && REDUCT_HANDLE_IS_NUMBER(_cVal))) \
591 { \
592 _bv = REDUCT_HANDLE_TO_NUMBER(_bVal); \
593 _cv = REDUCT_HANDLE_TO_NUMBER(_cVal); \
594 } \
595 else \
596 { \
597 _bv = reduct_handle_as_number(_reduct, _bVal); \
598 _cv = reduct_handle_as_number(_reduct, _cVal); \
599 } \
600 if (REDUCT_UNLIKELY(_cv == 0.0)) \
601 { \
602 REDUCT_ERROR_THROW(_reduct, "division by zero"); \
603 } \
604 *(_a) = REDUCT_HANDLE_FROM_NUMBER(_bv / _cv); \
605 } while (0)
606
607/**
608 * @brief Perform a modulo operation on two handles.
609 *
610 * @param _reduct Pointer to the Reduct structure.
611 * @param _a The target handle.
612 * @param _b The first handle.
613 * @param _c The second handle.
614 */
615#define REDUCT_HANDLE_MOD_FAST(_reduct, _a, _b, _c) \
616 do \
617 { \
618 reduct_handle_t _bVal = (_b); \
619 reduct_handle_t _cVal = (_c); \
620 double _bv, _cv; \
621 if (REDUCT_LIKELY(REDUCT_HANDLE_IS_NUMBER(_bVal) && REDUCT_HANDLE_IS_NUMBER(_cVal))) \
622 { \
623 _bv = REDUCT_HANDLE_TO_NUMBER(_bVal); \
624 _cv = REDUCT_HANDLE_TO_NUMBER(_cVal); \
625 } \
626 else \
627 { \
628 _bv = reduct_handle_as_number(_reduct, _bVal); \
629 _cv = reduct_handle_as_number(_reduct, _cVal); \
630 } \
631 if (REDUCT_UNLIKELY(_cv == 0.0)) \
632 { \
633 REDUCT_ERROR_THROW(_reduct, "division by zero"); \
634 } \
635 *(_a) = REDUCT_HANDLE_FROM_NUMBER(fmod(_bv, _cv)); \
636 } while (0)
637
638/**
639 * @brief Perform a bitwise operation on two handles.
640 *
641 * @param _reduct Pointer to the Reduct structure.
642 * @param _a The target handle.
643 * @param _b The first handle.
644 * @param _c The second handle
645 * @param _op The bitwise operator, (e.g., &, |, ^, etc.)
646 */
647#define REDUCT_HANDLE_BITWISE_FAST(_reduct, _a, _b, _c, _op) \
648 do \
649 { \
650 reduct_handle_t _bVal = (_b); \
651 reduct_handle_t _cVal = (_c); \
652 double _bv, _cv; \
653 if (REDUCT_LIKELY(REDUCT_HANDLE_IS_NUMBER(_bVal) && REDUCT_HANDLE_IS_NUMBER(_cVal))) \
654 { \
655 _bv = REDUCT_HANDLE_TO_NUMBER(_bVal); \
656 _cv = REDUCT_HANDLE_TO_NUMBER(_cVal); \
657 } \
658 else \
659 { \
660 _bv = reduct_handle_as_number(_reduct, _bVal); \
661 _cv = reduct_handle_as_number(_reduct, _cVal); \
662 } \
663 *(_a) = REDUCT_HANDLE_FROM_NUMBER((double)((int64_t)_bv _op(int64_t) _cv)); \
664 } while (0)
665
666/**
667 * @brief Check if a handle is truthy.
668 *
669 * @param _handle Pointer to the handle.
670 * @return `true` if the handle is truthy, `false` otherwise.
671 */
672#define REDUCT_HANDLE_IS_TRUTHY(_handle) \
673 (!REDUCT_HANDLE_IS_LIST(_handle) || REDUCT_HANDLE_TO_LIST(_handle)->length != 0)
674
675/**
676 * @brief Retain a handle, preventing its referenced item from being collected by the garbage collector.
677 *
678 * @param _reduct Pointer to the Reduct structure.
679 * @param _handle Pointer to the handle.
680 */
681#define REDUCT_HANDLE_RETAIN(_reduct, _handle) \
682 do \
683 { \
684 reduct_handle_t _h = (_handle); \
685 if (REDUCT_HANDLE_IS_ITEM(_h)) \
686 { \
687 reduct_item_retain(REDUCT_HANDLE_TO_ITEM(_h)); \
688 } \
689 } while (0)
690
691/**
692 * @brief Release a handle, allowing its referenced item to be collected by the garbage collector.
693 *
694 * @param _reduct Pointer to the Reduct structure.
695 * @param _handle The handle.
696 */
697#define REDUCT_HANDLE_RELEASE(_reduct, _handle) \
698 do \
699 { \
700 reduct_handle_t _h = (_handle); \
701 if (REDUCT_HANDLE_IS_ITEM(_h)) \
702 { \
703 reduct_item_release(REDUCT_HANDLE_TO_ITEM(_h)); \
704 } \
705 } while (0)
706
707/**
708 * @brief Free the item that a handle is referencing.
709 *
710 * Intended to be used by the GC or when it is known that a handle has no more users and its item was allocated by the
711 * current thread.
712 *
713 * @param _reduct Pointer to the Reduct structure.
714 * @param _handle The handle to the item.
715 */
716#define REDUCT_HANDLE_FREE(_reduct, _handle) \
717 do \
718 { \
719 reduct_handle_t _h = (_handle); \
720 if (REDUCT_HANDLE_IS_ITEM(_h)) \
721 { \
722 reduct_item_free((_reduct), REDUCT_HANDLE_TO_ITEM(_h)); \
723 } \
724 } while (0)
725
726/**
727 * @brief Ensure that a handle is an item handle.
728 *
729 * If the handle is a number, it will be upgraded to an item handle by looking up a corresponding atom.
730 *
731 * @param reduct Pointer to the Reduct structure.
732 * @param handle The handle to ensure.
733 */
734REDUCT_API void reduct_handle_ensure_item(struct reduct* reduct, reduct_handle_t* handle);
735
736/**
737 * @brief Ensure that a handle is an item and return the pointer.
738 *
739 * @param reduct Pointer to the Reduct structure.
740 * @param handle The handle.
741 * @return The item pointer.
742 */
743static inline REDUCT_ALWAYS_INLINE struct reduct_item* reduct_handle_as_item(struct reduct* reduct,
744 reduct_handle_t handle)
745{
747 {
748 reduct_handle_ensure_item(reduct, &handle);
749 }
750 return REDUCT_HANDLE_TO_ITEM(handle);
751}
752
753/**
754 * @brief Retrieve the integer representation of the handle.
755 *
756 * Will cast number values to integers or retrieve number values stored within an atom referenced by the handle
757 * if the handle is itself not a number.
758 *
759 * @param reduct Pointer to the Reduct structure.
760 * @param handle The handle.
761 * @return The integer value.
762 */
763static inline REDUCT_ALWAYS_INLINE int64_t reduct_handle_as_int(struct reduct* reduct, reduct_handle_t handle)
764{
766 {
767 return (int64_t)REDUCT_HANDLE_TO_NUMBER(handle);
768 }
769
770 REDUCT_ERROR_ASSERT(reduct, REDUCT_HANDLE_IS_ATOM(handle), "expected atom");
771 reduct_atom_t* atom = REDUCT_HANDLE_TO_ATOM(handle);
772 return reduct_atom_as_int(reduct, atom);
773}
774
775/**
776 * @brief Retrieve the number representation of the handle.
777 *
778 * Will retrieve number values stored within an atom referenced by the handle
779 * if the handle is itself not a number.
780 *
781 * @param reduct Pointer to the Reduct structure.
782 * @param handle The handle.
783 * @return The number value.
784 */
785static inline REDUCT_ALWAYS_INLINE double reduct_handle_as_number(struct reduct* reduct, reduct_handle_t handle)
786{
788 {
789 return REDUCT_HANDLE_TO_NUMBER(handle);
790 }
791
792 REDUCT_ERROR_ASSERT(reduct, REDUCT_HANDLE_IS_ATOM(handle), "expected atom");
793 reduct_atom_t* atom = REDUCT_HANDLE_TO_ATOM(handle);
794 return reduct_atom_as_number(reduct, atom);
795}
796
797/**
798 * @brief Retrieve the atom pointer of the handle.
799 *
800 * Will upgrade the handle to an item handle if it is a number.
801 *
802 * @param reduct Pointer to the Reduct structure.
803 * @param handle The handle.
804 * @return The atom pointer.
805 */
806static inline REDUCT_ALWAYS_INLINE reduct_atom_t* reduct_handle_as_atom(struct reduct* reduct, reduct_handle_t handle)
807{
808 reduct_item_t* item = reduct_handle_as_item(reduct, handle);
809 REDUCT_ERROR_ASSERT(reduct, item->type == REDUCT_ITEM_TYPE_ATOM, "expected atom");
810 return &item->atom;
811}
812
813/**
814 * @brief Check if two items are exactly equal string-wise or structurally.
815 *
816 * @param reduct Pointer to the Reduct structure.
817 * @param a The first handle, will be upgraded.
818 * @param b The second handle, will be upgraded.
819 * @return `true` if the items are strictly equal, `false` otherwise.
820 */
822
823/**
824 * @brief Compare two items for ordering (less than, equal, or greater than).
825 *
826 * Useful for sorting or range checks.
827 *
828 * @param reduct Pointer to the Reduct structure.
829 * @param a The first handle.
830 * @param b The second handle.
831 * @return A negative value if a < b, zero if a == b, and a positive value if a > b.
832 */
834
835/**
836 * @brief Get the string pointer and length from an atom handle.
837 *
838 * @param reduct Pointer to the Reduct structure.
839 * @param handle The handle to the atom.
840 * @param outStr Pointer to store the string pointer, not `NULL` terminated.
841 * @param outLen Pointer to store the string length.
842 */
843REDUCT_API void reduct_handle_atom_string(struct reduct* reduct, reduct_handle_t* handle, const char** outStr,
844 size_t* outLen);
845
846/**
847 * @brief Get the element at the specified index from a list or atom handle.
848 *
849 * For lists, returns the nth element. For atoms, returns the nth character as a string handle.
850 *
851 * @param reduct Pointer to the Reduct structure.
852 * @param handle The handle.
853 * @param index The index.
854 * @return The element handle.
855 */
856REDUCT_API reduct_handle_t reduct_handle_nth(struct reduct* reduct, reduct_handle_t handle, size_t index);
857
858/**
859 * @brief Get the length of a handle (list elements or atom characters).
860 *
861 * @param reduct Pointer to the Reduct structure.
862 * @param handle The handle.
863 * @return The length.
864 */
865REDUCT_API size_t reduct_handle_len(struct reduct* reduct, reduct_handle_t handle);
866
867/**
868 * @brief Check if an atom handle is equal to a string.
869 *
870 * @param reduct Pointer to the Reduct structure.
871 * @param handle The atom handle.
872 * @param str The string to compare.
873 * @return `true` if the atom is equal to the string, `false` otherwise.
874 */
875REDUCT_API bool reduct_handle_is_str(struct reduct* reduct, reduct_handle_t handle, const char* str);
876
877/** @} */
878
879#endif
Atom representation and operations.
#define REDUCT_LIKELY(_x)
Definition defs.h:58
#define REDUCT_UNLIKELY(_x)
Definition defs.h:59
#define REDUCT_ALWAYS_INLINE
Definition defs.h:61
#define REDUCT_API
Definition defs.h:24
Error handling and reporting.
REDUCT_API int64_t reduct_atom_as_int(struct reduct *reduct, reduct_atom_t *atom)
Retrieve an integer value from an atom, regardless of if it is quoted or not.
REDUCT_API double reduct_atom_as_number(struct reduct *reduct, reduct_atom_t *atom)
Retrieve a number value from an atom, regardless of if it is quoted or not.
#define REDUCT_ERROR_ASSERT(_reduct, _expr,...)
Throw a runtime error if the expression is false.
Definition error.h:224
#define REDUCT_HANDLE_TO_NUMBER(_handle)
Get the number value of a handle.
Definition handle.h:334
#define REDUCT_HANDLE_IS_ITEM(_handle)
Check if a handle is an item.
Definition handle.h:220
REDUCT_API reduct_handle_t reduct_handle_nth(struct reduct *reduct, reduct_handle_t handle, size_t index)
Get the element at the specified index from a list or atom handle.
REDUCT_API reduct_handle_type_t reduct_handle_get_type(reduct_handle_t handle)
Get the high-level type of a handle.
static REDUCT_ALWAYS_INLINE int64_t reduct_handle_as_int(struct reduct *reduct, reduct_handle_t handle)
Retrieve the integer representation of the handle.
Definition handle.h:763
REDUCT_API const char * reduct_handle_type_string(reduct_handle_type_t type)
Get the string name of a handle type.
static REDUCT_ALWAYS_INLINE double reduct_handle_as_number(struct reduct *reduct, reduct_handle_t handle)
Retrieve the number representation of the handle.
Definition handle.h:785
#define REDUCT_HANDLE_TO_ITEM(_handle)
Get the item pointer of a handle.
Definition handle.h:347
REDUCT_API bool reduct_handle_is_equal(struct reduct *reduct, reduct_handle_t a, reduct_handle_t b)
Check if two items are exactly equal string-wise or structurally.
#define REDUCT_HANDLE_IS_NUMBER(_handle)
Check if a handle is a number.
Definition handle.h:162
REDUCT_API size_t reduct_handle_len(struct reduct *reduct, reduct_handle_t handle)
Get the length of a handle (list elements or atom characters).
REDUCT_API void reduct_handle_ensure_item(struct reduct *reduct, reduct_handle_t *handle)
Ensure that a handle is an item handle.
REDUCT_API int64_t reduct_handle_compare(struct reduct *reduct, reduct_handle_t a, reduct_handle_t b)
Compare two items for ordering (less than, equal, or greater than).
REDUCT_API bool reduct_handle_is_str(struct reduct *reduct, reduct_handle_t handle, const char *str)
Check if an atom handle is equal to a string.
REDUCT_API void reduct_handle_atom_string(struct reduct *reduct, reduct_handle_t *handle, const char **outStr, size_t *outLen)
Get the string pointer and length from an atom handle.
static REDUCT_ALWAYS_INLINE reduct_atom_t * reduct_handle_as_atom(struct reduct *reduct, reduct_handle_t handle)
Retrieve the atom pointer of the handle.
Definition handle.h:806
static REDUCT_ALWAYS_INLINE struct reduct_item * reduct_handle_as_item(struct reduct *reduct, reduct_handle_t handle)
Ensure that a handle is an item and return the pointer.
Definition handle.h:743
#define REDUCT_HANDLE_TO_ATOM(_handle)
Get the atom pointer of a handle.
Definition handle.h:355
#define REDUCT_HANDLE_IS_ATOM(_handle)
Check if a handle is an atom.
Definition handle.h:228
reduct_handle_type_t
High-level handle types.
Definition handle.h:42
@ REDUCT_HANDLE_TYPE_FUTURE
Handle is a reference to a future.
Definition handle.h:52
@ REDUCT_HANDLE_TYPE_FUNCTION
Handle is a reference to a function.
Definition handle.h:47
@ REDUCT_HANDLE_TYPE_NUMBER
Handle is a number or references a number shaped atom.
Definition handle.h:44
@ REDUCT_HANDLE_TYPE_RVSDG_NODE
Handle is a reference to an IR node.
Definition handle.h:50
@ REDUCT_HANDLE_TYPE_RVSDG_EDGE
Handle is a reference to an IR edge.
Definition handle.h:51
@ REDUCT_HANDLE_TYPE_ATOM
Handle is a reference to an atom.
Definition handle.h:45
@ REDUCT_HANDLE_TYPE_UNKNOWN
Handle is corrupt or otherwise invalid.
Definition handle.h:53
@ REDUCT_HANDLE_TYPE_NONE
Invalid type.
Definition handle.h:43
@ REDUCT_HANDLE_TYPE_CLOSURE
Handle is a reference to a closure.
Definition handle.h:48
@ REDUCT_HANDLE_TYPE_ARENA
Handle is a reference to an arena.
Definition handle.h:49
@ REDUCT_HANDLE_TYPE_LIST
Handle is a reference to a list.
Definition handle.h:46
#define REDUCT_ITEM_TYPE_ATOM
An atom.
Definition item.h:31
Item management.
Built-in library registration and operations.
Atom structure.
Definition atom.h:88
Handle type.
Definition defs.h:119
Item structure.
Definition item.h:59
reduct_atom_t atom
An atom.
Definition item.h:66
reduct_item_type_t type
The type of the item.
Definition item.h:62