Reduct  v1.0.4-3-gdaf0d70
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
4struct reduct;
5
6#include "defs.h"
7#include "item.h"
8
9/**
10 * @file handle.h
11 * @brief Handle management.
12 * @defgroup handle Handle
13 *
14 * A handle is a lightweight reference to a Reduct item, with the ability to cache various flags from its referenced
15 * item or the integer/float value of an atom using Tagged Pointers (NaN Boxing).
16 *
17 * ## 64-bit Handle Bit Layout
18 *
19 * The top 16 bits are used as a type tag. The remaining 48 bits represent the payload
20 * (either a 48-bit integer or a 48-bit pointer).
21 *
22 * | Tag (16 bits) | Payload (48 bits) |
23 * |-----------------|-----------------------------------|
24 * | `0x0000` | Item Pointer (`reduct_item_t*`) |
25 * | `0x0006` | Integer Value (48-bit signed) |
26 * | `0x0007...FFFF` | Float (Shifted IEEE 754 double) |
27 *
28 * @see [Wikipedia Tagged pointer](https://en.wikipedia.org/wiki/Tagged_pointer)
29 *
30 * @{
31 */
32
33/**
34 * @brief Invalid handle constant.
35 */
36#define REDUCT_HANDLE_NONE 0x0000000000000000ULL
37
38#define REDUCT_HANDLE_OFFSET_FLOAT 0x0007000000000000ULL ///< Offset used for encoding doubles.
39
40#define REDUCT_HANDLE_TAG_INT 0x0006000000000000ULL ///< Tag for integer handles.
41#define REDUCT_HANDLE_TAG_ITEM 0x0000000000000000ULL ///< Tag for item handles.
42
43#define REDUCT_HANDLE_MASK_TAG 0xFFFF000000000000ULL ///< Mask for handle tag bits.
44#define REDUCT_HANDLE_MASK_VAL 0x0000FFFFFFFFFFFFULL ///< Mask for handle value bits.
45#define REDUCT_HANDLE_MASK_PTR REDUCT_HANDLE_MASK_VAL ///< Mask for item pointer bits.
46#define REDUCT_HANDLE_MASK_FLAGS 0x00000000000000FFULL ///< Mask for flags (not stored in handle anymore).
47
48/**
49 * @brief Create a handle from an integer.
50 *
51 * @param _val The integer value.
52 * @return The handle.
53 */
54#define REDUCT_HANDLE_FROM_INT(_val) (REDUCT_HANDLE_TAG_INT | ((reduct_handle_t)(_val) & REDUCT_HANDLE_MASK_VAL))
55
56/**
57 * @brief Create a handle from a float.
58 *
59 * @param _val The float value.
60 * @return The handle.
61 */
62#define REDUCT_HANDLE_FROM_FLOAT(_val) \
63 (((union { \
64 double d; \
65 reduct_handle_t u; \
66 }){.d = (_val)}) \
67 .u + \
68 REDUCT_HANDLE_OFFSET_FLOAT)
69
70/**
71 * @brief Create a handle from an item pointer.
72 *
73 * @param _ptr The pointer to the reduct_item_t.
74 * @return The handle.
75 */
76#define REDUCT_HANDLE_FROM_ITEM(_ptr) \
77 (REDUCT_HANDLE_TAG_ITEM | ((reduct_handle_t)(void*)(_ptr) & REDUCT_HANDLE_MASK_PTR))
78
79/**
80 * @brief Create a handle from an atom pointer.
81 *
82 * @param _atom The pointer to the reduct_atom_t.
83 * @return The handle.
84 */
85#define REDUCT_HANDLE_FROM_ATOM(_atom) REDUCT_HANDLE_FROM_ITEM(REDUCT_CONTAINER_OF(_atom, reduct_item_t, atom))
86
87/**
88 * @brief Create a handle from a list pointer.
89 *
90 * @param _list The pointer to the reduct_list_t.
91 * @return The handle.
92 */
93#define REDUCT_HANDLE_FROM_LIST(_list) REDUCT_HANDLE_FROM_ITEM(REDUCT_CONTAINER_OF(_list, reduct_item_t, list))
94
95/**
96 * @brief Create a handle from a function pointer.
97 *
98 * @param _func The pointer to the reduct_function_t.
99 * @return The handle.
100 */
101#define REDUCT_HANDLE_FROM_FUNCTION(_func) REDUCT_HANDLE_FROM_ITEM(REDUCT_CONTAINER_OF(_func, reduct_item_t, function))
102
103/**
104 * @brief Create a handle from a closure pointer.
105 *
106 * @param _closure The pointer to the reduct_closure_t.
107 * @return The handle.
108 */
109#define REDUCT_HANDLE_FROM_CLOSURE(_closure) \
110 REDUCT_HANDLE_FROM_ITEM(REDUCT_CONTAINER_OF(_closure, reduct_item_t, closure))
111
112/**
113 * @brief Check if a handle is an integer.
114 *
115 * @param _handle Pointer to the handle.
116 * @return Non-zero if the handle is an integer, zero otherwise.
117 */
118#define REDUCT_HANDLE_IS_INT(_handle) (((*(_handle)) & REDUCT_HANDLE_MASK_TAG) == REDUCT_HANDLE_TAG_INT)
119
120/**
121 * @brief Check if a handle is a float.
122 *
123 * @param _handle Pointer to the handle.
124 * @return Non-zero if the handle is a float, zero otherwise.
125 */
126#define REDUCT_HANDLE_IS_FLOAT(_handle) ((*(_handle)) >= REDUCT_HANDLE_OFFSET_FLOAT)
127
128/**
129 * @brief Check if a handle is an integer of references a integer shaped item.
130 *
131 * @param _handle Pointer to the handle.
132 * @return Non-zero if the handle is integer shaped, zero otherwise.
133 */
134#define REDUCT_HANDLE_IS_INT_SHAPED(_handle) \
135 ((REDUCT_HANDLE_IS_INT(_handle) || (REDUCT_HANDLE_GET_FLAGS(_handle) & REDUCT_ITEM_FLAG_INT_SHAPED)) && \
136 !(REDUCT_HANDLE_GET_FLAGS(_handle) & REDUCT_ITEM_FLAG_QUOTED))
137
138/**
139 * @brief Check if a handle is a float or references a float shaped item.
140 *
141 * @param _handle Pointer to the handle.
142 * @return Non-zero if the handle is float shaped, zero otherwise.
143 */
144#define REDUCT_HANDLE_IS_FLOAT_SHAPED(_handle) \
145 ((REDUCT_HANDLE_IS_FLOAT(_handle) || (REDUCT_HANDLE_GET_FLAGS(_handle) & REDUCT_ITEM_FLAG_FLOAT_SHAPED)) && \
146 !(REDUCT_HANDLE_GET_FLAGS(_handle) & REDUCT_ITEM_FLAG_QUOTED))
147
148/**
149 * @brief Get the type of the item referenced by the handle, or `REDUCT_ITEM_TYPE_ATOM` if not an item.
150 *
151 * @param _handle Pointer to the handle.
152 */
153#define REDUCT_HANDLE_GET_TYPE(_handle) \
154 (REDUCT_HANDLE_IS_ITEM(_handle) ? REDUCT_HANDLE_TO_ITEM(_handle)->type : REDUCT_ITEM_TYPE_ATOM)
155
156/**
157 * @brief Check if a handle is a number or references a number shaped item.
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_SHAPED(_handle) \
163 (REDUCT_HANDLE_IS_INT_SHAPED(_handle) || REDUCT_HANDLE_IS_FLOAT_SHAPED(_handle))
164
165/**
166 * @brief Check if a handle is an item.
167 *
168 * @param _handle Pointer to the handle.
169 * @return Non-zero if the handle is an item, zero otherwise.
170 */
171#define REDUCT_HANDLE_IS_ITEM(_handle) (((*(_handle)) & REDUCT_HANDLE_MASK_TAG) == REDUCT_HANDLE_TAG_ITEM)
172
173/**
174 * @brief Check if a handle is an atom.
175 *
176 * @param _handle Pointer to the handle.
177 * @return Non-zero if the handle is an atom, zero otherwise.
178 */
179#define REDUCT_HANDLE_IS_ATOM(_handle) (REDUCT_HANDLE_GET_TYPE(_handle) == REDUCT_ITEM_TYPE_ATOM)
180
181/**
182 * @brief Check if a handle is a list.
183 *
184 * @param _handle Pointer to the handle.
185 * @return Non-zero if the handle is a list, zero otherwise.
186 */
187#define REDUCT_HANDLE_IS_LIST(_handle) (REDUCT_HANDLE_GET_TYPE(_handle) == REDUCT_ITEM_TYPE_LIST)
188
189/**
190 * @brief Check if a handle is a function.
191 *
192 * @param _handle Pointer to the handle.
193 * @return Non-zero if the handle is a function, zero otherwise.
194 */
195#define REDUCT_HANDLE_IS_FUNCTION(_handle) (REDUCT_HANDLE_GET_TYPE(_handle) == REDUCT_ITEM_TYPE_FUNCTION)
196
197/**
198 * @brief Check if a handle is a closure.
199 *
200 * @param _handle Pointer to the handle.
201 * @return Non-zero if the handle is a closure, zero otherwise.
202 */
203#define REDUCT_HANDLE_IS_CLOSURE(_handle) (REDUCT_HANDLE_GET_TYPE(_handle) == REDUCT_ITEM_TYPE_CLOSURE)
204
205/**
206 * @brief Check if a handle is a lambda.
207 *
208 * @param _handle Pointer to the handle.
209 * @return Non-zero if the handle is a lambda, zero otherwise.
210 */
211#define REDUCT_HANDLE_IS_LAMBDA(_handle) (REDUCT_HANDLE_IS_FUNCTION(_handle) || REDUCT_HANDLE_IS_CLOSURE(_handle))
212
213/**
214 * @brief Check if a handle is a native function.
215 *
216 * @param _handle Pointer to the handle.
217 * @return Non-zero if the handle is a native function, zero otherwise.
218 */
219#define REDUCT_HANDLE_IS_NATIVE(_handle) \
220 (REDUCT_HANDLE_IS_ITEM(_handle) && (REDUCT_HANDLE_GET_FLAGS(_handle) & REDUCT_ITEM_FLAG_NATIVE))
221
222/**
223 * @brief Check if a handle is callable.
224 *
225 * @param _handle Pointer to the handle.
226 * @return Non-zero if the handle is callable, zero otherwise.
227 */
228#define REDUCT_HANDLE_IS_CALLABLE(_handle) (REDUCT_HANDLE_IS_LAMBDA(_handle) || REDUCT_HANDLE_IS_NATIVE(_handle))
229
230/**
231 * @brief Get the integer value of a handle.
232 *
233 * @param _handle Pointer to the handle.
234 * @return The integer value.
235 */
236#define REDUCT_HANDLE_TO_INT(_handle) (((reduct_int64_t)((*(_handle)) << 16)) >> 16)
237
238/**
239 * @brief Get the float value of a handle.
240 *
241 * @param _handle Pointer to the handle.
242 * @return The float value.
243 */
244#define REDUCT_HANDLE_TO_FLOAT(_handle) \
245 (((union { \
246 reduct_handle_t u; \
247 double d; \
248 }){.u = (*(_handle)) - REDUCT_HANDLE_OFFSET_FLOAT}) \
249 .d)
250
251/**
252 * @brief Get the item pointer of a handle.
253 *
254 * @param _handle Pointer to the handle.
255 * @return The item pointer.
256 */
257#define REDUCT_HANDLE_TO_ITEM(_handle) ((reduct_item_t*)(void*)((*(_handle)) & REDUCT_HANDLE_MASK_PTR))
258
259/**
260 * @brief Get flags from an item handle.
261 *
262 * @param _handle Pointer to the handle.
263 * @return The flags stored in the handle.
264 */
265#define REDUCT_HANDLE_GET_FLAGS(_handle) (REDUCT_HANDLE_IS_ITEM(_handle) ? REDUCT_HANDLE_TO_ITEM(_handle)->flags : 0)
266
267#define REDUCT_HANDLE_FALSE() REDUCT_HANDLE_FROM_INT(0) ///< Constant false handle.
268
269#define REDUCT_HANDLE_TRUE() REDUCT_HANDLE_FROM_INT(1) ///< Constant true handle.
270
271/**
272 * @brief Create a boolean handle from a C condition.
273 *
274 * @param _cond The condition to evaluate.
275 */
276#define REDUCT_HANDLE_FROM_BOOL(_cond) ((_cond) ? REDUCT_HANDLE_TRUE() : REDUCT_HANDLE_FALSE())
277
278/**
279 * @brief Compare two handles using a given operator with a fast path for integers and floats.
280 *
281 * @param _reduct The Reduct structure.
282 * @param _a The first handle.
283 * @param _b The second handle.
284 * @param _op The comparison operator (e.g., <, >, <=, >=, etc.).
285 * @return The result of the comparison.
286 */
287#define REDUCT_HANDLE_COMPARE_FAST(_reduct, _a, _b, _op) \
288 (((((*(_a)) ^ REDUCT_HANDLE_TAG_INT) | ((*(_b)) ^ REDUCT_HANDLE_TAG_INT)) & REDUCT_HANDLE_MASK_TAG) == 0 \
289 ? (REDUCT_HANDLE_TO_INT(_a) _op REDUCT_HANDLE_TO_INT(_b)) \
290 : (((*(_a)) >= REDUCT_HANDLE_OFFSET_FLOAT && (*(_b)) >= REDUCT_HANDLE_OFFSET_FLOAT) \
291 ? (REDUCT_HANDLE_TO_FLOAT(_a) _op REDUCT_HANDLE_TO_FLOAT(_b)) \
292 : (reduct_handle_compare(_reduct, _a, _b) _op 0)))
293
294/**
295 * @brief Perform a arithmetic operation on two handles with a fast path for integers and floats.
296 *
297 * @param _reduct The Reduct structure.
298 * @param _a The target handle.
299 * @param _b The first handle.
300 * @param _c The second handle
301 * @param _op The arithmetic operator, (e.g., +, -, *, etc.)
302 */
303#define REDUCT_HANDLE_ARITHMETIC_FAST(_reduct, _a, _b, _c, _op) \
304 do \
305 { \
306 reduct_handle_t _bVal = *(_b); \
307 reduct_handle_t _cVal = *(_c); \
308 if (REDUCT_LIKELY( \
309 (((_bVal ^ REDUCT_HANDLE_TAG_INT) | (_cVal ^ REDUCT_HANDLE_TAG_INT)) & REDUCT_HANDLE_MASK_TAG) == 0)) \
310 { \
311 *(_a) = REDUCT_HANDLE_FROM_INT(REDUCT_HANDLE_TO_INT(&_bVal) _op REDUCT_HANDLE_TO_INT(&_cVal)); \
312 } \
313 else if (REDUCT_HANDLE_IS_FLOAT(&_bVal) && REDUCT_HANDLE_IS_FLOAT(&_cVal)) \
314 { \
315 *(_a) = REDUCT_HANDLE_FROM_FLOAT(REDUCT_HANDLE_TO_FLOAT(&_bVal) _op REDUCT_HANDLE_TO_FLOAT(&_cVal)); \
316 } \
317 else \
318 { \
319 reduct_promotion_t prom; \
320 reduct_handle_promote(_reduct, _b, _c, &prom); \
321 if (prom.type == REDUCT_PROMOTION_TYPE_INT) \
322 { \
323 *(_a) = REDUCT_HANDLE_FROM_INT(prom.a.intVal _op prom.b.intVal); \
324 } \
325 else \
326 { \
327 *(_a) = REDUCT_HANDLE_FROM_FLOAT(prom.a.floatVal _op prom.b.floatVal); \
328 } \
329 } \
330 } while (0)
331
332/**
333 * @brief Check if a handle is truthy.
334 *
335 * @param _handle Pointer to the handle.
336 * @return `REDUCT_TRUE` if the handle is truthy, `REDUCT_FALSE` otherwise.
337 */
338#define REDUCT_HANDLE_IS_TRUTHY(_handle) \
339 (REDUCT_HANDLE_IS_INT(_handle) \
340 ? (REDUCT_HANDLE_TO_INT(_handle) != 0) \
341 : (REDUCT_HANDLE_IS_FLOAT(_handle) \
342 ? (REDUCT_HANDLE_TO_FLOAT(_handle) != 0.0) \
343 : (REDUCT_HANDLE_IS_ITEM(_handle) \
344 ? ((*(_handle)) != REDUCT_HANDLE_NONE && \
345 !(REDUCT_HANDLE_TO_ITEM(_handle)->flags & REDUCT_ITEM_FLAG_FALSY)) \
346 : REDUCT_FALSE)))
347
348/**
349 * @brief Ensure that a handle is an item handle.
350 *
351 * If the handle is an integer or float, it will be upgraded to an item handle by looking up a corresponding atom.
352 *
353 * @param reduct The Reduct structure.
354 * @param handle The handle to ensure.
355 */
356REDUCT_API void reduct_handle_ensure_item(struct reduct* reduct, reduct_handle_t* handle);
357
358/**
359 * @brief Ensure that a handle is an item and return the pointer.
360 *
361 * @param reduct The Reduct structure.
362 * @param handle The handle.
363 * @return The item pointer.
364 */
365REDUCT_API struct reduct_item* reduct_handle_item(struct reduct* reduct, reduct_handle_t* handle);
366
367/**
368 * @brief Promotion types for numeric operations.
369 * @enum reduct_promotion_type_t
370 */
377
378/**
379 * @brief Promotion result for numeric operations.
380 * @struct reduct_promotion_t
381 */
382typedef struct
383{
385 union {
388 } a;
389 union {
390 reduct_int64_t intVal;
391 reduct_float_t floatVal;
392 } b;
394
395/**
396 * @brief Promote two handles to a common numeric type.
397 *
398 * If both handles are numeric, they are promoted to the highest precision type (float if either is a float, otherwise
399 * integer).
400 *
401 * @param reduct The Reduct structure.
402 * @param a The first handle.
403 * @param b The second handle.
404 * @param out The promotion result structure.
405 */
406REDUCT_API void reduct_handle_promote(struct reduct* reduct, reduct_handle_t* a, reduct_handle_t* b,
407 reduct_promotion_t* out);
408
409/**
410 * @brief Check if two items are exactly equal string-wise or structurally.
411 *
412 * @param reduct The Reduct structure.
413 * @param a The first handle, will be upgraded.
414 * @param b The second handle, will be upgraded.
415 * @return `REDUCT_TRUE` if the items are strictly equal, `REDUCT_FALSE` otherwise.
416 */
418
419/**
420 * @brief Compare two items for ordering (less than, equal, or greater than).
421 *
422 * Useful for sorting or range checks.
423 *
424 * @param reduct The Reduct structure.
425 * @param a The first handle.
426 * @param b The second handle.
427 * @return A negative value if a < b, zero if a == b, and a positive value if a > b.
428 */
430
431/**
432 * @brief Get the constant nil handle.
433 *
434 * @param reduct Pointer to the Reduct structure.
435 * @return The nil handle.
436 */
438
439/**
440 * @brief Get the constant PI handle.
441 *
442 * @param reduct Pointer to the Reduct structure.
443 * @return The PI handle.
444 */
446
447/**
448 * @brief Get the constant E handle.
449 *
450 * @param reduct Pointer to the Reduct structure.
451 * @return The E handle.
452 */
454
455/**
456 * @brief Get the string pointer and length from an atom handle.
457 *
458 * @param reduct The Reduct structure.
459 * @param handle The handle to the atom.
460 * @param outStr Pointer to store the string pointer.
461 * @param outLen Pointer to store the string length.
462 */
463REDUCT_API void reduct_handle_get_string_params(struct reduct* reduct, reduct_handle_t* handle, char** outStr,
464 reduct_size_t* outLen);
465
466/** @} */
467
468#endif
size_t reduct_size_t
Definition defs.h:100
reduct_bool_t
Boolean type.
Definition defs.h:135
int64_t reduct_int64_t
Definition defs.h:92
reduct_uint64_t reduct_handle_t
Handle type.
Definition defs.h:189
double reduct_float_t
Definition defs.h:102
#define REDUCT_API
Definition defs.h:7
REDUCT_API reduct_handle_t reduct_handle_e(struct reduct *reduct)
Get the constant E handle.
REDUCT_API reduct_handle_t reduct_handle_pi(struct reduct *reduct)
Get the constant PI handle.
REDUCT_API void reduct_handle_promote(struct reduct *reduct, reduct_handle_t *a, reduct_handle_t *b, reduct_promotion_t *out)
Promote two handles to a common numeric type.
Definition handle_impl.h:54
REDUCT_API reduct_handle_t reduct_handle_nil(struct reduct *reduct)
Get the constant nil handle.
REDUCT_API void reduct_handle_ensure_item(struct reduct *reduct, reduct_handle_t *handle)
Ensure that a handle is an item handle.
REDUCT_API reduct_bool_t 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.
reduct_promotion_type_t
Promotion types for numeric operations.
Definition handle.h:372
REDUCT_API struct reduct_item * reduct_handle_item(struct reduct *reduct, reduct_handle_t *handle)
Ensure that a handle is an item and return the pointer.
REDUCT_API void reduct_handle_get_string_params(struct reduct *reduct, reduct_handle_t *handle, char **outStr, reduct_size_t *outLen)
Get the string pointer and length from an atom handle.
REDUCT_API reduct_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_PROMOTION_TYPE_NONE
Definition handle.h:373
@ REDUCT_PROMOTION_TYPE_INT
Definition handle.h:374
@ REDUCT_PROMOTION_TYPE_FLOAT
Definition handle.h:375
Item management.
Promotion result for numeric operations.
Definition handle.h:383
reduct_int64_t intVal
Definition handle.h:386
reduct_float_t floatVal
Definition handle.h:387
reduct_promotion_type_t type
Definition handle.h:384