1#pragma once
2
3#include <errno.h>
4#include <stddef.h>
5#include <stdint.h>
6#include <stdio.h>
7#include <string.h>
8#include <uchar.h>
9
10#include <libpussy/allocator.h>
11
12#include <pw_assert.h>
13#include <pw_branch_optimization.h>
14#include <pw_helper_macros.h>
15#include <pw_interfaces_base.h>
16
17#ifdef __cplusplus
18extern "C" {
19#endif
20
21// automatically cleaned value
22#define _PW_VALUE_CLEANUP [[ gnu::cleanup(pw_destroy) ]]
23#define PwValue _PW_VALUE_CLEANUP _PwValue
24
25// Built-in types
26#define PwTypeId_Null 0
27#define PwTypeId_Bool 1U
28#define PwTypeId_Int 2U // abstract integer
29#define PwTypeId_Signed 3U // subtype of int, signed integer
30#define PwTypeId_Unsigned 4U // subtype of int, unsigned integer
31#define PwTypeId_Float 5U
32#define PwTypeId_DateTime 6U
33#define PwTypeId_Timestamp 7U
34#define PwTypeId_Ptr 8U // container for void*
35#define PwTypeId_Status 9U
36
37#define PW_NUM_INTEGRAL_TYPES 10 // integral types have no allocated data so they do not have destructor, and are immutable
38
39#define PwTypeId_String 10U
40
41#define PW_NUM_IMMUTABLE_TYPES 11 // all integral types and String type are immutable;
42 // other types must implement `is_immutable` method to prove that
43
44#define PwTypeId_Struct 11U // base type for reference counted allocated data
45#define PwTypeId_Compound 12U // mixin for values that may contain circular references
46#define PwTypeId_Exception 13U
47#define PwTypeId_BasicArray 14U
48#define PwTypeId_Array 15U
49#define PwTypeId_BasicSet 16U
50#define PwTypeId_Set 17U
51#define PwTypeId_BasicMap 18U
52#define PwTypeId_Map 19U
53#define PwTypeId_Sync 20U // abstract base type for all synchronization objects
54#define PwTypeId_Task 21U // awaitable task
55#define PwTypeId_ChldTasks 22U // awaitable children tasks
56#define PwTypeId_Mutex 23U
57#define PwTypeId_CV 24U // condition variable
58
59#define PW_NUM_BUILTIN_TYPES 25
60
61// limits
62#define PW_SIGNED_MAX 0x7fff'ffff'ffff'ffffLL
63#define PW_UNSIGNED_MAX 0xffff'ffff'ffff'ffffULL
64
65// type checking
66
67// Note: there's no type checking functions for basic array, set, and map.
68// Having such separate macros is error-prone.
69#define pw_is_null(value) pw_is_subtype((value), PwTypeId_Null)
70#define pw_is_bool(value) pw_is_subtype((value), PwTypeId_Bool)
71#define pw_is_int(value) pw_is_subtype((value), PwTypeId_Int)
72#define pw_is_signed(value) pw_is_subtype((value), PwTypeId_Signed)
73#define pw_is_unsigned(value) pw_is_subtype((value), PwTypeId_Unsigned)
74#define pw_is_float(value) pw_is_subtype((value), PwTypeId_Float)
75#define pw_is_datetime(value) pw_is_subtype((value), PwTypeId_DateTime)
76#define pw_is_timestamp(value) pw_is_subtype((value), PwTypeId_Timestamp)
77#define pw_is_ptr(value) pw_is_subtype((value), PwTypeId_Ptr)
78#define pw_is_status(value) pw_is_subtype((value), PwTypeId_Status)
79#define pw_is_string(value) pw_is_subtype((value), PwTypeId_String)
80#define pw_is_struct(value) pw_is_subtype((value), PwTypeId_Struct)
81#define pw_is_compound(value) pw_is_subtype((value), PwTypeId_Compound)
82#define pw_is_exception(value) pw_is_subtype((value), PwTypeId_Exception)
83#define pw_is_array(value) pw_is_subtype((value), PwTypeId_BasicArray)
84#define pw_is_set(value) pw_is_subtype((value), PwTypeId_BasicSet)
85#define pw_is_map(value) pw_is_subtype((value), PwTypeId_BasicMap)
86#define pw_is_code(value) pw_is_subtype((value), PwTypeId_Code)
87
88// Integral types
89typedef nullptr_t PwType_Null;
90typedef bool PwType_Bool;
91typedef int64_t PwType_Signed;
92typedef uint64_t PwType_Unsigned;
93typedef double PwType_Float;
94
95PW_UNION(_PwStringParams) {
96 struct {
97 uint8_t char_size: 3,
98 integral:1,
99 allocated:1,
100 _unused_bits:3;
101 };
102 uint8_t as_byte;
103};
104
105PW_STRUCT(_PwStringData) {
106 // allocated string data for fixed char size strings
107 atomic_uint refcount;
108 uint32_t capacity; // in characters
109 uint8_t data[];
110};
111
112typedef struct { uint8_t v[3]; } uint24_t; // three bytes wide characters, always little-endian
113
114PW_STRUCT(_PwStructData) {
115 atomic_uint refcount;
116 atomic_uint itercount; // XXX not sure atomic is necessary here, using it just for overflow/underflow checking
117 // performed by _pw_atomic_add/_pw_atomic_sub macros
118};
119
120// forward declarations
121PW_STRUCT(_PwExceptionData);
122PW_STRUCT(PwTask);
123
124// make sure largest C type fits into 64 bits
125static_assert( sizeof(long long) <= sizeof(uint64_t) );
126
127// check UTF-32 char size
128static_assert( sizeof(char32_t) == 4 );
129
130PW_UNION(_PwValue) {
131 /*
132 * 128-bit value
133 */
134
135 uint16_t type_id;
136
137 uint64_t u64[2];
138
139 struct {
140 uint16_t _string_type_id;
141 _PwStringParams str_params;
142 };
143
144 struct {
145 // integral types
146 uint16_t _integral_type_id;
147 uint8_t carry; // for integer arithmetic
148 uint8_t _integral_pagging_1;
149 uint32_t _integral_pagging_2;
150 union {
151 // Integral types
152 PwType_Bool bool_value;
153 PwType_Signed signed_value;
154 PwType_Unsigned unsigned_value;
155 PwType_Float float_value;
156 };
157 };
158
159 struct {
160 // ptr
161 uint16_t _ptr_type_id;
162 uint16_t _ptr_padding_1;
163 uint32_t _ptr_pagging_2;
164 // ISO C forbids conversion of object pointer to function pointer type, so define both
165 union {
166 void* ptr;
167 void (*func_ptr)();
168 };
169 };
170
171 struct {
172 // struct
173 uint16_t _struct_type_id;
174 uint16_t _struct_padding;
175 uint32_t struct_offset; // data offset for this type id
176 uint8_t* struct_data; // pointer to the allocated data block
177 };
178
179 struct {
180 // status
181 uint16_t _status_type_id;
182 union {
183 // this field is zero if success and nonzero on error;
184 // for exception it contains PweException code
185 uint16_t status_code;
186 int16_t pw_errno;
187 };
188 uint32_t kind:2,
189 line_number:30;
190 const char* file_desc; // points to __FILE__ which is followed by null character and the description
191 };
192
193 struct {
194 // integral string
195 uint16_t _i_string_type_id;
196 _PwStringParams _i_str_params;
197 uint8_t integral_length;
198 union {
199 uint8_t str_1[12];
200 uint16_t str_2[6];
201 uint24_t str_3[4];
202 uint32_t str_4[3];
203 };
204 };
205
206 struct {
207 // allocated string
208 uint16_t _a_string_type_id;
209 _PwStringParams _a_str_params;
210 uint8_t _a_padding;
211 uint32_t length;
212 _PwStringData* string_data;
213 };
214
215 struct {
216 // static 0-terminated string
217 uint16_t _s_string_type_id;
218 _PwStringParams _s_str_params;
219 uint8_t _s_padding;
220 uint32_t _s_length;
221 void* char_ptr;
222 };
223
224 struct {
225 // date/time
226 uint16_t _datetime_type_id;
227 int16_t year; // negative value may refer to B.C.
228 // -- 32 bits
229 uint8_t month; // 1-12
230 uint8_t day; // 1-31
231 uint8_t hour; // 0-23
232 uint8_t minute; // 0-59
233 // -- 64 bits
234 uint32_t nanosecond;
235 int16_t gmt_offset; // in minutes
236 uint8_t second; // 0-59
237
238 uint8_t tzindex;
239 /* Index in the zone info cache.
240 * zero for UTC
241 */
242 };
243
244 struct {
245 // timestamp
246 uint16_t _timestamp_type_id;
247 uint16_t ts_userdata; // for arbitrary use
248 uint32_t ts_nanoseconds;
249 uint64_t ts_seconds;
250 };
251
252 struct {
253 // task and children tasks (special case of task list)
254 uint16_t _task_type_id;
255 uint16_t _task_padding_1;
256 uint32_t _task_padding_2;
257 PwTask* task;
258 };
259};
260
261typedef _PwValue* PwValuePtr;
262
263// make sure _PwValue structure is correct
264static_assert( offsetof(_PwValue, bool_value) == 8 );
265static_assert( offsetof(_PwValue, ptr) == 8 );
266static_assert( offsetof(_PwValue, func_ptr) == 8 );
267static_assert( offsetof(_PwValue, struct_data) == 8 );
268static_assert( offsetof(_PwValue, string_data) == 8 );
269
270static_assert( offsetof(_PwValue, integral_length) == 3 );
271static_assert( offsetof(_PwValue, str_1) == 4 );
272static_assert( offsetof(_PwValue, str_2) == 4 );
273static_assert( offsetof(_PwValue, str_3) == 4 );
274static_assert( offsetof(_PwValue, str_4) == 4 );
275
276static_assert( sizeof(_PwValue) == 16 );
277
278
279/****************************************************************
280 * PwType structure
281 */
282
283PW_STRUCT(PwType) {
284 /*
285 * PW type
286 */
287 uint16_t id;
288 uint16_t num_parents;
289 uint16_t num_base_types;
290 uint16_t num_interface_definitions; // the number of interfaces provided to pw_add_type
291
292 // Struct type specific data.
293 unsigned data_size; // size of data for particular mixin
294 unsigned data_alignment;
295 unsigned total_struct_size; // used to allocate memory for values of this particular type
296 // cannot be used in calculations for subtypes
297 // because the order of base types can be different in case of multiple inheritance
298
299 uint16_t num_other_interfaces;
300
301 char* name; // type name
302
303 PwType** parents; // direct parents
304 PwType** base_types; // linear list of all ancestors in the order of method resolution
305
306 PwInterface_Generic** interface_definitions; // interfaces defined for this type, as provided to pw_add_type
307 // i.e. with only id and method functions are set
308 // all interfaces for this type both defined and inherited, with all MRO chains
309 PwInterface_Generic* builtin_interfaces[PW_NUM_BUILTIN_INTERFACES]; // interfaces by id for fast access
310 PwInterface_Generic** other_interfaces; // lookup table
311
312 Allocator* allocator; // this applies only to the final type, not for mixins
313
314 /* offsets of all mixin structures that make up the type;
315 * the size equals to the number of base types plus one (self);
316 * the first element is self, the order of other elements is the same as for base_types
317 */
318 unsigned* struct_offsets;
319};
320
321
322void _pw_init_types();
323/*
324 * Initialize types.
325 * Declared with [[gnu::constructor]] attribute and automatically called
326 * before main().
327 *
328 * However, the order of initialization is undefined and other modules
329 * that must call it explicitly from their constructors.
330 *
331 * This function is idempotent.
332 */
333
334extern PwType** _pw_types;
335/*
336 * Global list of types initialized with built-in types.
337 */
338
339#define pw_typeof(value) (_pw_types[(value)->type_id])
340
341[[nodiscard]] static inline bool _pw_is_subtype_t(PwType* subtype, uint16_t type_id)
342/*
343 * Return true if subtype is really a subtype of type_id.
344 * Caveat: this function does not check if subtype has the same type_id; the caller must do this.
345 */
346{
347 PwType** base_type = subtype->base_types;
348 if (base_type) {
349 PwType** base_types_end = base_type + subtype->num_base_types;
350 while (base_type < base_types_end) {
351 if (type_id == (*base_type)->id) {
352 return true;
353 }
354 base_type++;
355 }
356 }
357 return false;
358}
359
360[[nodiscard]] static inline bool _pw_is_subtype_n(uint16_t subtype_id, uint16_t type_id)
361/*
362 * Return true if subtype_id is really a subtype of type_id.
363 */
364{
365 if (_pw_likely(subtype_id == type_id)) {
366 return true;
367 } else {
368 return _pw_is_subtype_t(_pw_types[subtype_id], type_id);
369 }
370}
371
372[[nodiscard]] static inline bool pw_is_subtype(PwValuePtr value, uint16_t type_id)
373{
374 return _pw_is_subtype_n(value->type_id, type_id);
375}
376
377#define pw_this_data(value) \
378 ( (void*)( ((uint8_t*) (value)->struct_data) + mthis->struct_offset ) )
379
380void* _pw_get_subtype_struct_ptr(PwValuePtr value, uint16_t type_id);
381
382static inline void* _pw_get_struct_ptr(PwValuePtr value, uint16_t type_id)
383/*
384 * Get pointer to the particular mixin structure of the value.
385 */
386{
387 uint8_t* ptr = value->struct_data;
388 if (_pw_likely(ptr)) {
389 if (_pw_likely(value->type_id == type_id)) {
390 ptr += value->struct_offset;
391 } else {
392 ptr = _pw_get_subtype_struct_ptr(value, type_id);
393 }
394 }
395 return ptr;
396}
397
398[[nodiscard]] bool _pw_iteration_in_progress(PwValuePtr value);
399
400#define pw_iteration_in_progress(value) \
401 __extension__ \
402 ({ \
403 bool ret = _pw_iteration_in_progress((value)); \
404 if (ret) { \
405 pw_set_status(PwStatus(PweIterationInProgress)); \
406 } \
407 ret; \
408 })
409
410
411#define PW_PARENTS 0x70B5ACE5 // parents delimiter for _pw_add_type
412#define PW_INTERFACES 0x1DEAFACE // interfaces delimiter for _pw_add_type
413
414[[nodiscard]] uint16_t _pw_add_type(char* name, unsigned data_size, unsigned data_alignment, ...);
415/*
416 * Add type to the first available position in the global list.
417 *
418 * `name` should be a static string.
419 *
420 * Variadic arguments must start from either PW_PARENTS or PW_INTERFACES delimiters.
421 * In case of PW_PARENTS, it must be followed by ids of parent types.
422 * Then goes PW_INTERFACES, followed by pairs of interface id and interface pointer.
423 * The final interface id must be -1 (`pw_add_type` wrappers add this).
424 *
425 * Interfaces override parent methods only if they are not nullptr.
426 * If the type has no parents, all interface methods must be defined.
427 * The only exception is optional methods in the basic interface.
428 *
429 * Return new type id.
430 * Allocator field is initialized with the default one.
431 *
432 * All errors in this function are considered as critical and cause program abort.
433 */
434
435#define pw_add_type(name, ...) \
436 _pw_add_type((name), 0, 0 __VA_OPT__(,) __VA_ARGS__, -1)
437
438#define pw_add_type2(name, data_type, ...) \
439 _pw_add_type((name), sizeof(data_type), alignof(data_type) __VA_OPT__(,) __VA_ARGS__, -1)
440
441#define pw_get_type_name(v) _Generic((v), \
442 char: _pw_get_type_name_by_id, \
443 unsigned char: _pw_get_type_name_by_id, \
444 short: _pw_get_type_name_by_id, \
445 unsigned short: _pw_get_type_name_by_id, \
446 int: _pw_get_type_name_by_id, \
447 unsigned int: _pw_get_type_name_by_id, \
448 long: _pw_get_type_name_by_id, \
449 unsigned long: _pw_get_type_name_by_id, \
450 long long: _pw_get_type_name_by_id, \
451 unsigned long long: _pw_get_type_name_by_id, \
452 PwValuePtr: _pw_get_type_name_from_value \
453 )(v)
454
455[[nodiscard]] static inline char* _pw_get_type_name_by_id (uint16_t type_id) { return _pw_types[type_id]->name; }
456[[nodiscard]] static inline char* _pw_get_type_name_from_value(PwValuePtr value) { return _pw_types[value->type_id]->name; }
457
458void pw_dump_types(FILE* fp);
459
460
461/****************************************************************
462 * Initializers and rvalues
463 */
464
465#define PW_NULL {.type_id = PwTypeId_Null}
466
467#define PwNull() \
468 /* make Bool rvalue */ \
469 __extension__ \
470 ({ \
471 _PwValue __v = PW_NULL; \
472 __v; \
473 })
474
475#define PW_BOOL(initializer) \
476 { \
477 ._integral_type_id = PwTypeId_Bool, \
478 .bool_value = (initializer) \
479 }
480
481#define PwBool(initializer) \
482 /* make Bool rvalue */ \
483 __extension__ \
484 ({ \
485 _PwValue __v = PW_BOOL(initializer); \
486 __v; \
487 })
488
489#define PW_SIGNED(initializer) \
490 { \
491 ._integral_type_id = PwTypeId_Signed, \
492 .signed_value = (initializer), \
493 }
494
495#define PwSigned(initializer) \
496 /* make Signed rvalue */ \
497 __extension__ \
498 ({ \
499 _PwValue __v = PW_SIGNED(initializer); \
500 __v; \
501 })
502
503#define PW_UNSIGNED(initializer) \
504 { \
505 ._integral_type_id = PwTypeId_Unsigned, \
506 .unsigned_value = (initializer) \
507 }
508
509#define PwUnsigned(initializer) \
510 /* make Unsigned rvalue */ \
511 __extension__ \
512 ({ \
513 _PwValue __v = PW_UNSIGNED(initializer); \
514 __v; \
515 })
516
517#define PW_FLOAT(initializer) \
518 { \
519 ._integral_type_id = PwTypeId_Float, \
520 .float_value = (initializer) \
521 }
522
523#define PwFloat(initializer) \
524 /* make Float rvalue */ \
525 __extension__ \
526 ({ \
527 _PwValue __v = PW_FLOAT(initializer); \
528 __v; \
529 })
530
531#define PW_STRING(...) \
532 /* Integral string, character size 1 byte, up to 12 chars; initializer is optional */ \
533 { \
534 ._i_string_type_id = PwTypeId_String, \
535 ._i_str_params = { \
536 .integral = 1, \
537 .char_size = 1 \
538 } \
539 __VA_OPT__( , \
540 .integral_length = sizeof(__VA_ARGS__ "\0") - 2, \
541 .str_1 = __VA_ARGS__ \
542 ) \
543 }
544
545#define PwString(...) \
546 /* make String rvalue, character size 1 byte, up to 12 chars; initializer is optional */ \
547 __extension__ \
548 ({ \
549 _PwValue __s = PW_STRING(__VA_ARGS__); \
550 __s; \
551 })
552
553#define PW_STRING_UTF32(...) \
554 /* Integral string, character size 4 bytes, up to 3 chars; initializer is optional */ \
555 { \
556 ._i_string_type_id = PwTypeId_String, \
557 ._i_str_params = { \
558 .integral = 1, \
559 .char_size = 4 \
560 } \
561 __VA_OPT__( , \
562 .integral_length = (sizeof(__VA_ARGS__ "\0") / 4) - 2, \
563 .str_4 = __VA_ARGS__ \
564 ) \
565 }
566
567#define PwStringUtf32(...) \
568 /* make String rvalue, character size 4 bytes, up to 3 chars; initializer is optional */ \
569 __extension__ \
570 ({ \
571 _PwValue __s = PW_STRING_UTF32(__VA_ARGS__); \
572 __s; \
573 })
574
575#define PW_STATIC_STRING(initializer) \
576 /* Static string, character size 1 byte */ \
577 { \
578 ._s_string_type_id = PwTypeId_String, \
579 ._s_str_params = { \
580 .char_size = 1 \
581 }, \
582 ._s_length = sizeof(initializer "\0") - 2, \
583 .char_ptr = initializer \
584 }
585
586#define PwStaticString(initializer) \
587 /* make static String rvalue, character size 1 byte */ \
588 __extension__ \
589 ({ \
590 _PwValue __s = { \
591 ._s_string_type_id = PwTypeId_String, \
592 ._s_str_params = { \
593 .char_size = 1 \
594 }, \
595 .char_ptr = initializer \
596 }; \
597 __s.length = strlen(initializer); \
598 __s; \
599 })
600
601#define PW_STATIC_STRING_UTF32(initializer) \
602 /* Static UTF-32 string */ \
603 { \
604 ._s_string_type_id = PwTypeId_String, \
605 ._s_str_params = { \
606 .char_size = 4 \
607 }, \
608 ._s_length = (sizeof(initializer "\0") / 4) - 2, \
609 .char_ptr = initializer \
610 }
611
612#define PwStaticStringUtf32(initializer) \
613 /* make static String rvalue, character size 4 bytes */ \
614 __extension__ \
615 ({ \
616 _PwValue __s = { \
617 ._s_string_type_id = PwTypeId_String, \
618 ._s_str_params = { \
619 .char_size = 4 \
620 }, \
621 .char_ptr = initializer \
622 }; \
623 __s.length = utf32_strlen(initializer); \
624 __s; \
625 })
626
627#define PW_DATETIME(_year, _month, _day, _hour, _minute, _second) \
628 { \
629 ._datetime_type_id = PwTypeId_DateTime, \
630 .year = _year, \
631 .month = _month, \
632 .day = _day, \
633 .hour = _hour, \
634 .minute = _minute, \
635 .second = _second \
636 }
637
638#define PwDateTime(_year, _month, _day, _hour, _minute, _second) \
639 /* make DateTime rvalue */ \
640 __extension__ \
641 ({ \
642 _PwValue __v = PW_DATETIME(_year, _month, _day, _hour, _minute, _second); \
643 __v; \
644 })
645
646#define PW_TIMESTAMP(seconds, nanoseconds) \
647 { \
648 ._timestamp_type_id = PwTypeId_Timestamp, \
649 .ts_seconds = (seconds), \
650 .ts_nanoseconds = (nanoseconds), \
651 }
652
653#define PwTimestamp(seconds, nanoseconds) \
654 /* make Timestamp rvalue */ \
655 __extension__ \
656 ({ \
657 _PwValue __v = PW_TIMESTAMP((seconds), (nanoseconds)); \
658 __v; \
659 })
660
661#define PW_PTR(initializer) \
662 { \
663 ._ptr_type_id = PwTypeId_Ptr, \
664 .ptr = (initializer) \
665 }
666
667#define PwPtr(initializer) \
668 /* make Ptr rvalue */ \
669 __extension__ \
670 ({ \
671 _PwValue __v = PW_PTR(initializer); \
672 __v; \
673 })
674
675#define PwVaEnd() \
676 /* make VA_END rvalue */ \
677 __extension__ \
678 ({ \
679 _PwValue __status = { \
680 ._status_type_id = PwTypeId_Status, \
681 .kind = PwStatusKind_VA_END \
682 }; \
683 __status; \
684 })
685
686#define PW_SUCCESS \
687 { \
688 ._status_type_id = PwTypeId_Status \
689 }
690
691#define PwSuccess() \
692 __extension__ \
693 ({ \
694 _PwValue __status = PW_SUCCESS; \
695 __status; \
696 })
697
698#define _PW_STATUS_INITIALIZER(_kind, _code, ...) \
699 { \
700 ._status_type_id = PwTypeId_Status, \
701 .kind = (_kind), \
702 .status_code = (_code), \
703 .line_number = __LINE__, \
704 .file_desc = __FILE__ "\0" __VA_ARGS__ "\0" \
705 }
706
707#define PW_STATUS(_code, ...) \
708 _PW_STATUS_INITIALIZER(PwStatusKind_Basic, (_code) __VA_OPT__(,) __VA_ARGS__)
709
710
711#define PwStatus(_code, ...) \
712 /* make Status rvalue */ \
713 __extension__ \
714 ({ \
715 _PwValue __status = PW_STATUS((_code) __VA_OPT__(,) __VA_ARGS__); \
716 __status; \
717 })
718
719#define PwErrno(_errno, ...) \
720 /* make Status rvalue */ \
721 __extension__ \
722 ({ \
723 _PwValue __status = _PW_STATUS_INITIALIZER(PwStatusKind_Errno, (_errno) __VA_OPT__(,) __VA_ARGS__); \
724 __status; \
725 })
726
727#define PwOOM(...) \
728 PwErrno(ENOMEM __VA_OPT__(,) __VA_ARGS__)
729
730
731/****************************************************************
732 * API for compound types
733 */
734
735PW_STRUCT(_PwCompoundChain) {
736 /*
737 * Compound values may contain cyclic references.
738 * This structure along with function `_pw_on_chain`
739 * helps to detect them.
740 * See dump implementation for array and map values.
741 */
742 _PwCompoundChain* prev;
743 PwValuePtr value;
744};
745
746void _pw_compound_join(PwValuePtr parent, PwValuePtr child);
747/*
748 * If `child` is a compound value, join it with `parent`.
749 */
750
751void _pw_compound_split(PwValuePtr parent, PwValuePtr child);
752/*
753 * If `child` is a compound value, split it from `parent`.
754 * This function may destroy `child` if the last reference to it is held py `parent`.
755 */
756
757[[nodiscard]] PwValuePtr _pw_value_is_on_chain(PwValuePtr value, _PwCompoundChain* tail);
758
759[[nodiscard]] static inline PwValuePtr _pw_on_chain(PwValuePtr value, _PwCompoundChain* tail)
760/*
761 * Check if value struct_data is on chain.
762 */
763{
764 if (_pw_unlikely(tail)) {
765 return _pw_value_is_on_chain(value, tail);
766 } else {
767 return nullptr;
768 }
769}
770
771
772/****************************************************************
773 * Destructor
774 */
775
776void pw_destroy_compound(PwValuePtr value, _PwCompoundChain* tail);
777/*
778 * Destroy value: call destructor (if refcount drops to zero for refcounted values) and make `value` Null.
779 */
780
781static inline void pw_destroy(PwValuePtr value)
782{
783 if (_pw_likely(value->type_id < PW_NUM_INTEGRAL_TYPES
784 || (value->type_id == PwTypeId_String && !value->str_params.allocated))) {
785 *value = PwNull();
786 return;
787 }
788 pw_destroy_compound(value, nullptr);
789}
790
791
792/****************************************************************
793 * Move
794 */
795
796static inline void pw_move(PwValuePtr result, PwValuePtr v)
797/*
798 * "Move" value to another variable or out of the function
799 * (i.e. return a value and reset autocleaned variable)
800 * `result` is destroyed before moving.
801 */
802{
803 pw_destroy(result);
804 *result = *v;
805 *v = PwNull();
806}
807
808#ifdef __cplusplus
809}
810#endif