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