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