1#include "include/pw.h"
2#include "src/pw_alloc.h"
3#include "src/pw_interfaces_internal.h"
4#include "src/types/array/array_internal.h"
5#include "src/types/compound_internal.h"
6#include "src/types/map_internal.h"
7#include "src/types/set_internal.h"
8#include "src/types/string/string_internal.h"
9#include "src/types/struct_internal.h"
10
11#include <libpussy/alignment.h>
12#include <libpussy/mmarray.h>
13
14
15PwType** _pw_types = nullptr;
16static unsigned num_pw_types = 0;
17
18/****************************************************************
19 * Null type
20 */
21
22static bool null_create(PwMethod_Basic_create* mthis, PwValuePtr result, PwCtorArgs* ctor_args)
23{
24 *result = PwNull();
25 return true;
26}
27
28static bool null_hash(PwMethod_Basic_hash* mthis, PwValuePtr self, PwHashContext* ctx, _PwCompoundChain* tail)
29{
30 _pw_hash_uint64(ctx, PwTypeId_Null);
31 return true;
32}
33
34static bool null_dump(PwMethod_Basic_dump* mthis, PwValuePtr self, FILE* fp, int indent, _PwCompoundChain* tail)
35{
36 _pw_print_indent(fp, indent);
37 _pw_print_type(fp, self);
38 fputc('\n', fp);
39 return true;
40}
41
42static bool null_equal(PwMethod_Basic_equal* mthis, PwValuePtr self, PwValuePtr other, _PwCompoundChain* tail)
43{
44 uint16_t t = other->type_id;
45 PwType** base_type = nullptr;
46 PwType** base_types_end = nullptr;
47 for (;;) {
48 if (_pw_likely(t == PwTypeId_Null)) {
49 return true;
50 }
51 if (_pw_likely(t == PwTypeId_Ptr)) {
52 return other->ptr == nullptr;
53 }
54
55 if (t == other->type_id) {
56 /* init loop through base types */
57 PwType* type = _pw_types[t];
58 base_type = type->base_types;
59 if (!base_type) {
60 break;
61 }
62 base_types_end = base_type + type->num_base_types;
63 } else {
64 /* next iteration through base types */
65 base_type++;
66 if (base_type >= base_types_end) {
67 break;
68 }
69 }
70 t = (*base_type)->id;
71 }
72 return false;
73}
74
75static bool null_to_string(PwMethod_Basic_to_string* mthis, PwValuePtr self, PwValuePtr result, _PwCompoundChain* tail)
76{
77 pw_destroy(result);
78 *result = PwString("null");
79 return true;
80}
81
82static bool null_is_true(PwMethod_Basic_is_true* mthis, PwValuePtr self, _PwCompoundChain* tail)
83{
84 return false;
85}
86
87#define null_destroy nullptr
88#define null_clone nullptr
89#define null_decref nullptr
90#define null_deepcopy nullptr
91#define null_is_immutable nullptr
92#define null_iter_children nullptr
93
94static PwInterface_Basic null_basic_interface = {
95#define X(name, ...) .name = { .func = null_##name } __VA_OPT__(,)
96 PW_BASIC_INTERFACE_METHODS
97#undef X
98};
99
100/****************************************************************
101 * Bool type
102 */
103
104static bool bool_create(PwMethod_Basic_create* mthis, PwValuePtr result, PwCtorArgs* ctor_args)
105{
106 // XXX use ctor_args for initializer?
107 *result = PwBool(false);
108 return true;
109}
110
111static bool bool_hash(PwMethod_Basic_hash* mthis, PwValuePtr self, PwHashContext* ctx, _PwCompoundChain* tail)
112{
113 // mind maps: the hash should be the same for subtypes, that's why not using self->type_id here
114 _pw_hash_uint64(ctx, PwTypeId_Bool);
115 _pw_hash_uint64(ctx, self->bool_value);
116 return true;
117}
118
119static bool bool_dump(PwMethod_Basic_dump* mthis, PwValuePtr self, FILE* fp, int indent, _PwCompoundChain* tail)
120{
121 _pw_print_indent(fp, indent);
122 _pw_print_type(fp, self);
123 fprintf(fp, ": %s\n", self->bool_value? "true" : "false");
124 return true;
125}
126
127static bool bool_equal(PwMethod_Basic_equal* mthis, PwValuePtr self, PwValuePtr other, _PwCompoundChain* tail)
128{
129 bool v = self->bool_value;
130 uint16_t t = other->type_id;
131 PwType** base_type = nullptr;
132 PwType** base_types_end = nullptr;
133 for (;;) {
134 if (_pw_likely(t == PwTypeId_Bool)) {
135 return v == other->bool_value;
136 }
137
138 if (t == other->type_id) {
139 /* init loop through base types */
140 PwType* type = _pw_types[t];
141 base_type = type->base_types;
142 if (!base_type) {
143 break;
144 }
145 base_types_end = base_type + type->num_base_types;
146 } else {
147 /* next iteration through base types */
148 base_type++;
149 if (base_type >= base_types_end) {
150 break;
151 }
152 }
153 t = (*base_type)->id;
154 }
155 return false;
156}
157
158static bool bool_to_string(PwMethod_Basic_to_string* mthis, PwValuePtr self, PwValuePtr result, _PwCompoundChain* tail)
159{
160 pw_destroy(result);
161 if (self->bool_value) {
162 *result = PwString("true");
163 } else {
164 *result = PwString("false");
165 }
166 return true;
167}
168
169static bool bool_is_true(PwMethod_Basic_is_true* mthis, PwValuePtr self, _PwCompoundChain* tail)
170{
171 return self->bool_value;
172}
173
174#define bool_destroy nullptr
175#define bool_clone nullptr
176#define bool_decref nullptr
177#define bool_deepcopy nullptr
178#define bool_is_immutable nullptr
179#define bool_iter_children nullptr
180
181static PwInterface_Basic bool_basic_interface = {
182#define X(name, ...) .name = { .func = bool_##name } __VA_OPT__(,)
183 PW_BASIC_INTERFACE_METHODS
184#undef X
185};
186
187/****************************************************************
188 * Abstract Integer type
189 */
190
191static bool int_create(PwMethod_Basic_create* mthis, PwValuePtr result, PwCtorArgs* ctor_args)
192{
193 pw_set_status(PwStatus(PweNotImplemented));
194 return false;
195}
196
197static bool int_hash(PwMethod_Basic_hash* mthis, PwValuePtr self, PwHashContext* ctx, _PwCompoundChain* tail)
198{
199 _pw_hash_uint64(ctx, PwTypeId_Int);
200 return true;
201}
202
203static bool int_dump(PwMethod_Basic_dump* mthis, PwValuePtr self, FILE* fp, int indent, _PwCompoundChain* tail)
204{
205 _pw_print_indent(fp, indent);
206 _pw_print_type(fp, self);
207 fputs(": abstract\n", fp);
208 return true;
209}
210
211static bool int_equal(PwMethod_Basic_equal* mthis, PwValuePtr self, PwValuePtr other, _PwCompoundChain* tail)
212{
213 return false;
214}
215
216static bool int_to_string(PwMethod_Basic_to_string* mthis, PwValuePtr self, PwValuePtr result, _PwCompoundChain* tail)
217{
218 pw_set_status(PwStatus(PweNotImplemented));
219 return false;
220}
221
222static bool int_is_true(PwMethod_Basic_is_true* mthis, PwValuePtr self, _PwCompoundChain* tail)
223{
224 return self->signed_value;
225}
226
227#define int_destroy nullptr
228#define int_clone nullptr
229#define int_decref nullptr
230#define int_deepcopy nullptr
231#define int_is_immutable nullptr
232#define int_iter_children nullptr
233
234static PwInterface_Basic int_basic_interface = {
235#define X(name, ...) .name = { .func = int_##name } __VA_OPT__(,)
236 PW_BASIC_INTERFACE_METHODS
237#undef X
238};
239
240/****************************************************************
241 * Signed type
242 */
243
244static bool signed_create(PwMethod_Basic_create* mthis, PwValuePtr result, PwCtorArgs* ctor_args)
245{
246 // XXX use ctor_args for initializer?
247 *result = PwSigned(0);
248 return true;
249}
250
251static bool signed_hash(PwMethod_Basic_hash* mthis, PwValuePtr self, PwHashContext* ctx, _PwCompoundChain* tail)
252{
253 // mind maps: same signed and unsigned integers must have same hash, so
254 if (self->signed_value < 0) {
255 _pw_hash_uint64(ctx, PwTypeId_Signed);
256 } else {
257 _pw_hash_uint64(ctx, PwTypeId_Unsigned);
258 }
259 _pw_hash_uint64(ctx, self->signed_value);
260 return true;
261}
262
263static bool signed_dump(PwMethod_Basic_dump* mthis, PwValuePtr self, FILE* fp, int indent, _PwCompoundChain* tail)
264{
265 _pw_print_indent(fp, indent);
266 _pw_print_type(fp, self);
267 fprintf(fp, ": %lld\n", (long long) self->signed_value);
268 return true;
269}
270
271static bool signed_to_string(PwMethod_Basic_to_string* mthis, PwValuePtr self, PwValuePtr result, _PwCompoundChain* tail)
272{
273 pw_destroy(result);
274 pw_set_status(PwStatus(PweNotImplemented));
275 return false;
276}
277
278static bool signed_is_true(PwMethod_Basic_is_true* mthis, PwValuePtr self, _PwCompoundChain* tail)
279{
280 return self->signed_value;
281}
282
283static inline bool compare_signed_unsigned(PwType_Signed self, PwType_Unsigned other)
284{
285 if (self < 0) {
286 return false;
287 } else {
288 return self == (PwType_Signed) other;
289 }
290}
291
292static bool signed_equal(PwMethod_Basic_equal* mthis, PwValuePtr self, PwValuePtr other, _PwCompoundChain* tail)
293{
294 PwType_Signed v = self->signed_value;
295 uint16_t t = other->type_id;
296 PwType** base_type = nullptr;
297 PwType** base_types_end = nullptr;
298 for (;;) {
299 if (_pw_likely(t == PwTypeId_Signed)) {
300 return v == other->signed_value;
301 }
302 if (_pw_likely(t == PwTypeId_Unsigned)) {
303 return compare_signed_unsigned(v, other->unsigned_value);
304 }
305 if (_pw_likely(t == PwTypeId_Float)) {
306 return v == other->float_value;
307 }
308
309 if (t == other->type_id) {
310 /* init loop through base types */
311 PwType* type = _pw_types[t];
312 base_type = type->base_types;
313 if (!base_type) {
314 break;
315 }
316 base_types_end = base_type + type->num_base_types;
317 } else {
318 /* next iteration through base types */
319 base_type++;
320 if (base_type >= base_types_end) {
321 break;
322 }
323 }
324 t = (*base_type)->id;
325 }
326 return false;
327}
328
329#define signed_destroy nullptr
330#define signed_clone nullptr
331#define signed_decref nullptr
332#define signed_deepcopy nullptr
333#define signed_is_immutable nullptr
334#define signed_iter_children nullptr
335
336static PwInterface_Basic signed_basic_interface = {
337#define X(name, ...) .name = { .func = signed_##name } __VA_OPT__(,)
338 PW_BASIC_INTERFACE_METHODS
339#undef X
340};
341
342/****************************************************************
343 * Unsigned type
344 */
345
346static bool unsigned_create(PwMethod_Basic_create* mthis, PwValuePtr result, PwCtorArgs* ctor_args)
347{
348 // XXX use ctor_args for initializer?
349 *result = PwUnsigned(0);
350 return true;
351}
352
353static bool unsigned_hash(PwMethod_Basic_hash* mthis, PwValuePtr self, PwHashContext* ctx, _PwCompoundChain* tail)
354{
355 // mind maps: same signed and unsigned integers must have same hash,
356 // so using PwTypeId_Unsigned, not self->type_id
357 _pw_hash_uint64(ctx, PwTypeId_Unsigned);
358 _pw_hash_uint64(ctx, self->unsigned_value);
359 return true;
360}
361
362static bool unsigned_dump(PwMethod_Basic_dump* mthis, PwValuePtr self, FILE* fp, int indent, _PwCompoundChain* tail)
363{
364 _pw_print_indent(fp, indent);
365 _pw_print_type(fp, self);
366 fprintf(fp, ": %llu\n", (unsigned long long) self->unsigned_value);
367 return true;
368}
369
370static inline bool compare_unsigned_signed(PwType_Unsigned self, PwType_Signed other)
371{
372 if (other < 0) {
373 return false;
374 } else {
375 return ((PwType_Signed) self) == other;
376 }
377}
378
379static bool unsigned_equal(PwMethod_Basic_equal* mthis, PwValuePtr self, PwValuePtr other, _PwCompoundChain* tail)
380{
381 PwType_Unsigned v = self->signed_value;
382 uint16_t t = other->type_id;
383 PwType** base_type = nullptr;
384 PwType** base_types_end = nullptr;
385 for (;;) {
386 if (_pw_likely(t == PwTypeId_Signed)) {
387 return compare_unsigned_signed(v, other->signed_value);
388 }
389 if (_pw_likely(t == PwTypeId_Unsigned)) {
390 return v == other->unsigned_value;
391 }
392 if (_pw_likely(t == PwTypeId_Float)) {
393 return v == other->float_value;
394 }
395
396 if (t == other->type_id) {
397 /* init loop through base types */
398 PwType* type = _pw_types[t];
399 base_type = type->base_types;
400 if (!base_type) {
401 break;
402 }
403 base_types_end = base_type + type->num_base_types;
404 } else {
405 /* next iteration through base types */
406 base_type++;
407 if (base_type >= base_types_end) {
408 break;
409 }
410 }
411 t = (*base_type)->id;
412 }
413 return false;
414}
415
416static bool unsigned_to_string(PwMethod_Basic_to_string* mthis, PwValuePtr self, PwValuePtr result, _PwCompoundChain* tail)
417{
418 pw_destroy(result);
419 pw_set_status(PwStatus(PweNotImplemented));
420 return false;
421}
422
423static bool unsigned_is_true(PwMethod_Basic_is_true* mthis, PwValuePtr self, _PwCompoundChain* tail)
424{
425 return self->unsigned_value;
426}
427
428#define unsigned_destroy nullptr
429#define unsigned_clone nullptr
430#define unsigned_decref nullptr
431#define unsigned_deepcopy nullptr
432#define unsigned_is_immutable nullptr
433#define unsigned_iter_children nullptr
434
435static PwInterface_Basic unsigned_basic_interface = {
436#define X(name, ...) .name = { .func = unsigned_##name } __VA_OPT__(,)
437 PW_BASIC_INTERFACE_METHODS
438#undef X
439};
440
441/****************************************************************
442 * Float type
443 */
444
445static bool float_create(PwMethod_Basic_create* mthis, PwValuePtr result, PwCtorArgs* ctor_args)
446{
447 // XXX use ctor_args for initializer?
448 *result = PwFloat(0.0);
449 return true;
450}
451
452static bool float_hash(PwMethod_Basic_hash* mthis, PwValuePtr self, PwHashContext* ctx, _PwCompoundChain* tail)
453{
454 // mind maps: the hash should be the same for subtypes, that's why not using self->type_id here
455 _pw_hash_uint64(ctx, PwTypeId_Float);
456 _pw_hash_buffer(ctx, &self->float_value, sizeof(self->float_value));
457 return true;
458}
459
460static bool float_dump(PwMethod_Basic_dump* mthis, PwValuePtr self, FILE* fp, int indent, _PwCompoundChain* tail)
461{
462 _pw_print_indent(fp, indent);
463 _pw_print_type(fp, self);
464 fprintf(fp, ": %f\n", self->float_value);
465 return true;
466}
467
468static bool float_equal(PwMethod_Basic_equal* mthis, PwValuePtr self, PwValuePtr other, _PwCompoundChain* tail)
469{
470 PwType_Float v = self->float_value;
471 uint16_t t = other->type_id;
472 PwType** base_type = nullptr;
473 PwType** base_types_end = nullptr;
474 for (;;) {
475 if (_pw_likely(t == PwTypeId_Signed)) {
476 return v == (PwType_Float) other->signed_value;
477 }
478 if (_pw_likely(t == PwTypeId_Unsigned)) {
479 return v == (PwType_Float) other->unsigned_value;
480 }
481 if (_pw_likely(t == PwTypeId_Float)) {
482 return v == other->float_value;
483 }
484
485 if (t == other->type_id) {
486 /* init loop through base types */
487 PwType* type = _pw_types[t];
488 base_type = type->base_types;
489 if (!base_type) {
490 break;
491 }
492 base_types_end = base_type + type->num_base_types;
493 } else {
494 /* next iteration through base types */
495 base_type++;
496 if (base_type >= base_types_end) {
497 break;
498 }
499 }
500 t = (*base_type)->id;
501 }
502 return false;
503}
504
505static bool float_to_string(PwMethod_Basic_to_string* mthis, PwValuePtr self, PwValuePtr result, _PwCompoundChain* tail)
506{
507 pw_destroy(result);
508 pw_set_status(PwStatus(PweNotImplemented));
509 return false;
510}
511
512static bool float_is_true(PwMethod_Basic_is_true* mthis, PwValuePtr self, _PwCompoundChain* tail)
513{
514 return self->float_value;
515}
516
517#define float_destroy nullptr
518#define float_clone nullptr
519#define float_decref nullptr
520#define float_deepcopy nullptr
521#define float_is_immutable nullptr
522#define float_iter_children nullptr
523
524static PwInterface_Basic float_basic_interface = {
525#define X(name, ...) .name = { .func = float_##name } __VA_OPT__(,)
526 PW_BASIC_INTERFACE_METHODS
527#undef X
528};
529
530/****************************************************************
531 * DateTime type
532 */
533
534static bool datetime_create(PwMethod_Basic_create* mthis, PwValuePtr result, PwCtorArgs* ctor_args)
535{
536 // XXX use ctor_args for initializer?
537 *result = PwDateTime(0, 0, 0, 0, 0, 0);
538 return true;
539}
540
541static bool datetime_hash(PwMethod_Basic_hash* mthis, PwValuePtr self, PwHashContext* ctx, _PwCompoundChain* tail)
542{
543 // mind maps: the hash should be the same for subtypes, that's why not using self->type_id here
544 _pw_hash_uint64(ctx, PwTypeId_DateTime);
545 _pw_hash_uint64(ctx, self->year);
546 _pw_hash_uint64(ctx, self->month);
547 _pw_hash_uint64(ctx, self->day);
548 _pw_hash_uint64(ctx, self->hour);
549 _pw_hash_uint64(ctx, self->minute);
550 _pw_hash_uint64(ctx, self->second);
551 _pw_hash_uint64(ctx, self->nanosecond);
552 _pw_hash_uint64(ctx, self->gmt_offset + (1L << 8 * sizeof(self->gmt_offset))); // make positive (biased)
553 return true;
554}
555
556static bool datetime_dump(PwMethod_Basic_dump* mthis, PwValuePtr self, FILE* fp, int indent, _PwCompoundChain* tail)
557{
558 _pw_print_indent(fp, indent);
559 _pw_print_type(fp, self);
560 fprintf(fp, ": %04u-%02u-%02u %02u:%02u:%02u",
561 self->year, self->month, self->day,
562 self->hour, self->minute, self->second);
563
564 if (self->nanosecond) {
565 // format fractional part and print &frac[1] later
566 char frac[12];
567 snprintf(frac, sizeof(frac), "%u", self->nanosecond + 1000'000'000);
568 fputs(&frac[1], fp);
569 }
570 if (self->gmt_offset) {
571 // gmt_offset can be negative
572 int offset_hours = self->gmt_offset / 60;
573 int offset_minutes = self->gmt_offset % 60;
574 // make sure minutes are positive
575 if (offset_minutes < 0) {
576 offset_minutes = -offset_minutes;
577 }
578 fprintf(fp, "%c%02d:%02d", (offset_hours< 0)? '-' : '+', offset_hours, offset_minutes);
579 }
580 fputc('\n', fp);
581 return true;
582}
583
584static bool datetime_to_string(PwMethod_Basic_to_string* mthis, PwValuePtr self, PwValuePtr result, _PwCompoundChain* tail)
585{
586 pw_destroy(result);
587 pw_set_status(PwStatus(PweNotImplemented));
588 return false;
589}
590
591static bool datetime_is_true(PwMethod_Basic_is_true* mthis, PwValuePtr self, _PwCompoundChain* tail)
592{
593 return self->year && self->month && self->day
594 && self->hour && self->minute && self->second && self->nanosecond;
595}
596
597static bool datetime_equal(PwMethod_Basic_equal* mthis, PwValuePtr self, PwValuePtr other, _PwCompoundChain* tail)
598{
599 uint16_t t = other->type_id;
600 PwType** base_type = nullptr;
601 PwType** base_types_end = nullptr;
602 for (;;) {
603 if (_pw_likely(t == PwTypeId_DateTime)) {
604 return self->year == other->year &&
605 self->month == other->month &&
606 self->day == other->day &&
607 self->hour == other->hour &&
608 self->minute == other->minute &&
609 self->second == other->second &&
610 self->nanosecond == other->nanosecond &&
611 self->gmt_offset == other->gmt_offset;
612 }
613
614 if (t == other->type_id) {
615 /* init loop through base types */
616 PwType* type = _pw_types[t];
617 base_type = type->base_types;
618 if (!base_type) {
619 break;
620 }
621 base_types_end = base_type + type->num_base_types;
622 } else {
623 /* next iteration through base types */
624 base_type++;
625 if (base_type >= base_types_end) {
626 break;
627 }
628 }
629 t = (*base_type)->id;
630 }
631 return false;
632}
633
634#define datetime_destroy nullptr
635#define datetime_clone nullptr
636#define datetime_decref nullptr
637#define datetime_deepcopy nullptr
638#define datetime_is_immutable nullptr
639#define datetime_iter_children nullptr
640
641static PwInterface_Basic datetime_basic_interface = {
642#define X(name, ...) .name = { .func = datetime_##name } __VA_OPT__(,)
643 PW_BASIC_INTERFACE_METHODS
644#undef X
645};
646
647/****************************************************************
648 * Timestamp type
649 */
650
651static bool timestamp_create(PwMethod_Basic_create* mthis, PwValuePtr result, PwCtorArgs* ctor_args)
652{
653 // XXX use ctor_args for initializer?
654 *result = PwTimestamp(0, 0);
655 return true;
656}
657
658static bool timestamp_hash(PwMethod_Basic_hash* mthis, PwValuePtr self, PwHashContext* ctx, _PwCompoundChain* tail)
659{
660 // mind maps: the hash should be the same for subtypes, that's why not using self->type_id here
661 _pw_hash_uint64(ctx, PwTypeId_Timestamp);
662 _pw_hash_uint64(ctx, self->ts_seconds);
663 _pw_hash_uint64(ctx, self->ts_nanoseconds);
664 return true;
665}
666
667static bool timestamp_dump(PwMethod_Basic_dump* mthis, PwValuePtr self, FILE* fp, int indent, _PwCompoundChain* tail)
668{
669 _pw_print_indent(fp, indent);
670 _pw_print_type(fp, self);
671 fprintf(fp, " %zu.%09u\n", self->ts_seconds, self->ts_nanoseconds);
672 return true;
673}
674
675static bool timestamp_equal(PwMethod_Basic_equal* mthis, PwValuePtr self, PwValuePtr other, _PwCompoundChain* tail)
676{
677 uint16_t t = other->type_id;
678 PwType** base_type = nullptr;
679 PwType** base_types_end = nullptr;
680 for (;;) {
681 if (_pw_likely(t == PwTypeId_Timestamp)) {
682 return self->ts_seconds == other->ts_seconds
683 && self->ts_nanoseconds == other->ts_nanoseconds;
684 }
685
686 if (t == other->type_id) {
687 /* init loop through base types */
688 PwType* type = _pw_types[t];
689 base_type = type->base_types;
690 if (!base_type) {
691 break;
692 }
693 base_types_end = base_type + type->num_base_types;
694 } else {
695 /* next iteration through base types */
696 base_type++;
697 if (base_type >= base_types_end) {
698 break;
699 }
700 }
701 t = (*base_type)->id;
702 }
703 return false;
704}
705
706static bool timestamp_to_string(PwMethod_Basic_to_string* mthis, PwValuePtr self, PwValuePtr result, _PwCompoundChain* tail)
707{
708 return pw_sprintf(result, "%zu.%09u", self->ts_seconds, self->ts_nanoseconds);
709}
710
711static bool timestamp_is_true(PwMethod_Basic_is_true* mthis, PwValuePtr self, _PwCompoundChain* tail)
712{
713 return self->ts_seconds && self->ts_nanoseconds;
714}
715
716#define timestamp_destroy nullptr
717#define timestamp_clone nullptr
718#define timestamp_decref nullptr
719#define timestamp_deepcopy nullptr
720#define timestamp_is_immutable nullptr
721#define timestamp_iter_children nullptr
722
723static PwInterface_Basic timestamp_basic_interface = {
724#define X(name, ...) .name = { .func = timestamp_##name } __VA_OPT__(,)
725 PW_BASIC_INTERFACE_METHODS
726#undef X
727};
728
729/****************************************************************
730 * Pointer type
731 */
732
733static bool ptr_create(PwMethod_Basic_create* mthis, PwValuePtr result, PwCtorArgs* ctor_args)
734{
735 // XXX use ctor_args for initializer?
736 *result = PwPtr(nullptr);
737 return true;
738}
739
740static bool ptr_hash(PwMethod_Basic_hash* mthis, PwValuePtr self, PwHashContext* ctx, _PwCompoundChain* tail)
741{
742 // mind maps: the hash should be the same for subtypes, that's why not using self->type_id here
743 _pw_hash_uint64(ctx, PwTypeId_Ptr);
744 _pw_hash_buffer(ctx, &self->ptr, sizeof(self->ptr));
745 return true;
746}
747
748static bool ptr_dump(PwMethod_Basic_dump* mthis, PwValuePtr self, FILE* fp, int indent, _PwCompoundChain* tail)
749{
750 _pw_print_indent(fp, indent);
751 _pw_print_type(fp, self);
752 fprintf(fp, ": %p\n", self->ptr);
753 return true;
754}
755
756static bool ptr_equal(PwMethod_Basic_equal* mthis, PwValuePtr self, PwValuePtr other, _PwCompoundChain* tail)
757{
758 uint16_t t = other->type_id;
759 PwType** base_type = nullptr;
760 PwType** base_types_end = nullptr;
761 for (;;) {
762 if (_pw_likely(t == PwTypeId_Ptr)) {
763 return self->ptr == other->ptr;
764 }
765 if (_pw_likely(t == PwTypeId_Null)) {
766 return self->ptr == nullptr;
767 }
768
769 if (t == other->type_id) {
770 /* init loop through base types */
771 PwType* type = _pw_types[t];
772 base_type = type->base_types;
773 if (!base_type) {
774 break;
775 }
776 base_types_end = base_type + type->num_base_types;
777 } else {
778 /* next iteration through base types */
779 base_type++;
780 if (base_type >= base_types_end) {
781 break;
782 }
783 }
784 t = (*base_type)->id;
785 }
786 return false;
787}
788
789static bool ptr_to_string(PwMethod_Basic_to_string* mthis, PwValuePtr self, PwValuePtr result, _PwCompoundChain* tail)
790{
791 pw_destroy(result);
792 pw_set_status(PwStatus(PweNotImplemented));
793 return false;
794}
795
796static bool ptr_is_true(PwMethod_Basic_is_true* mthis, PwValuePtr self, _PwCompoundChain* tail)
797{
798 return self->ptr;
799}
800
801#define ptr_destroy nullptr
802#define ptr_clone nullptr
803#define ptr_decref nullptr
804#define ptr_deepcopy nullptr
805#define ptr_is_immutable nullptr
806#define ptr_iter_children nullptr
807
808static PwInterface_Basic ptr_basic_interface = {
809#define X(name, ...) .name = { .func = ptr_##name } __VA_OPT__(,)
810 PW_BASIC_INTERFACE_METHODS
811#undef X
812};
813
814/****************************************************************
815 * Type system initialization.
816 */
817
818void pw_dump_types(FILE* fp);
819
820[[nodiscard]] uint16_t _pw_add_type(char* name, unsigned data_size, unsigned data_alignment, ...)
821{
822 if (num_pw_types >= 65534) { // upper limit to avoid overflow in calculations below
823 pw_panic("Too many types: %u\n", num_pw_types);
824 }
825
826 if (mmarray_grow(_pw_types, 1)) { /* no op, address not changed */ }
827
828 uint16_t type_id = (uint16_t) num_pw_types;
829
830 // reuse mmarray for temporary arrays
831 void* mmarray = mmarray_allocate(0, 0, 1);
832
833 // allocate type structure
834
835 PwType* type = _pw_arena_alloc(1, PwType);
836 bzero(type, sizeof(PwType));
837 _pw_types[type_id] = type;
838
839 // init basic fields
840
841 type->id = type_id;
842 type->name = name;
843 type->data_size = data_size;
844 type->data_alignment = data_alignment;
845 type->allocator = &default_allocator;
846
847 // start processing variadic arguments
848
849 va_list ap;
850 va_start(ap);
851
852 int separator = va_arg(ap, int);
853 if (separator == PW_PARENTS) {
854
855 // init parent and base types
856
857 uint16_t* parent_ids = (uint16_t*) mmarray;
858 mmarray_reset(mmarray, sizeof(uint16_t));
859 for (;;) {
860 int parent_id = va_arg(ap, int);
861 if (parent_id == PW_INTERFACES || parent_id == -1) {
862 separator = parent_id;
863 break;
864 }
865 if (parent_id >= (int) type_id) {
866 pw_panic("Parent %d for new type %s(id=%u) does not exist\n", parent_id, name, type_id);
867 }
868 // check if parent is duplicate
869 for (uint16_t i = 0; i < type->num_parents; i++) {
870 if (parent_id == parent_ids[i]) {
871 pw_panic("Duplicate parent %s(id=%d) for new type %s(id=%d)\n",
872 _pw_types[parent_id]->name, parent_id, name, type_id);
873 }
874 }
875 mmarray = parent_ids = mmarray_grow(parent_ids, 1);
876 parent_ids[type->num_parents++] = (uint16_t) parent_id;
877 }
878 if (type->num_parents) {
879
880 // allocate array for parent types
881 type->parents = _pw_arena_alloc(type->num_parents, PwType);
882
883 /* Type precedence lists (TPL) for each parent type used by C3 algorithm (CPL in terms of C3)
884 * TPLs are arrays of type ids. The underlying storage for all arrays is allocated on stack.
885 * TPL for a type includes the type itself plus all base types.
886 * The last TPL is the list of direct parents.
887 */
888 unsigned num_tpls = type->num_parents + 1; // if a type inherits all 65535 types, an overflow is possible
889 // that's why we limit the number of types with 65534
890 uint16_t *tpls[num_tpls]; // the underlying array will be defined after we calculate its size
891 unsigned tpl_array_size = type->num_parents;
892 uint16_t tpl_lengths[num_tpls];
893
894 unsigned max_base_types = type->num_parents; // just a sum of all base types for defining a temporary array for C3 result
895
896 // initialize parent types array and calculate TPL-related stuff
897 for (uint16_t i = 0; i < type->num_parents; i++) {
898 PwType* parent_type = _pw_types[parent_ids[i]];
899 type->parents[i] = parent_type;
900
901 uint16_t n = parent_type->num_base_types;
902 max_base_types += n;
903 tpl_array_size += 1 + n;
904 tpl_lengths[i] = 1 + n;
905 }
906 // the last TPL is the list of direct parents
907 tpl_lengths[type->num_parents] = type->num_parents;
908
909 // allocate temp arrays on the stack
910 uint16_t base_type_ids[max_base_types];
911 uint16_t tpl_array[tpl_array_size];
912
913 // init TPLs
914 uint16_t *tpl_item = tpl_array;
915 for (uint16_t i = 0; i < type->num_parents; i++) {
916 PwType* parent_type = type->parents[i];
917 tpls[i] = tpl_item;
918 // TPL of parent includes the parent type itself and grandparents
919 *tpl_item++ = parent_type->id;
920 PwType** grandparent = parent_type->base_types;
921 PwType** grandparent_end = grandparent + parent_type->num_base_types;
922 while (grandparent < grandparent_end) {
923 *tpl_item++ = (*grandparent)->id;
924 grandparent++;
925 }
926 }
927 // the last TPL is the list of direct parents
928 tpls[type->num_parents] = tpl_item;
929 for (uint16_t i = 0; i < type->num_parents; i++) {
930 *tpl_item++ = type->parents[i]->id;
931 }
932
933 // merge TPLs
934
935 for(;;) {
936 uint16_t *nonempty_tpls[num_tpls];
937 unsigned nonempty_tpl_index[num_tpls];
938 unsigned num_nonempty_tpls = 0;
939
940 for (unsigned i = 0; i < num_tpls; i++) {
941 if (tpl_lengths[i]) {
942 nonempty_tpl_index[num_nonempty_tpls] = i;
943 nonempty_tpls[num_nonempty_tpls] = tpls[i];
944 num_nonempty_tpls++;
945 }
946 }
947 if (num_nonempty_tpls == 0) {
948 // done
949 break;
950 }
951 // find merge candidate among TPL heads
952 unsigned candidate; // type_id or UINT_MAX if rejected
953 for (unsigned i = 0; i < num_nonempty_tpls; i++) {
954 candidate = nonempty_tpls[i][0];
955 for (unsigned j = 0; j < num_nonempty_tpls; j++) {
956 uint16_t *tpl = nonempty_tpls[j];
957 unsigned tpl_len = tpl_lengths[nonempty_tpl_index[j]];
958 for (unsigned k = 1; k < tpl_len; k++) {
959 if (tpl[k] == candidate) {
960 // reject
961 candidate = UINT_MAX;
962 goto reject;
963 }
964 }
965 }
966 // found
967 break;
968
969 reject:
970 }
971 if (candidate == UINT_MAX) {
972 pw_panic("Inconsistent inheritance for new type %s(id=%u)\n", name, type_id);
973 }
974 base_type_ids[type->num_base_types++] = candidate;
975
976 // remove candidate from TPLs
977
978 for (unsigned i = 0; i < num_nonempty_tpls; i++) {
979 uint16_t *tpl = nonempty_tpls[i];
980 if (tpl[0] == candidate) {
981 // remove
982 unsigned j = nonempty_tpl_index[i];
983 tpls[j]++;
984 tpl_lengths[j]--;
985 }
986 }
987 }
988 pw_hard_assert(type->num_base_types);
989
990 // make base types
991 type->base_types = _pw_arena_alloc(type->num_base_types, PwType);
992 for (unsigned i = 0; i < type->num_base_types; i++) {
993 type->base_types[i] = _pw_types[base_type_ids[i]];
994 }
995 }
996 }
997
998 // init offsets for Struct-based type in method resolution order
999
1000 if (type->num_base_types) {
1001
1002 type->struct_offsets = _pw_arena_alloc(type->num_base_types + 1, unsigned);
1003
1004 unsigned offset = 0;
1005
1006 // iterate base types backward and initialize offsets backward too
1007 unsigned i = type->num_base_types;
1008 PwType** base_type_end = type->base_types;
1009 PwType** base_type = base_type_end + i;
1010 while (base_type > base_type_end) {
1011 base_type--;
1012 PwType* t = *base_type;
1013 type->struct_offsets[i--] = offset;
1014 offset = align_unsigned(offset + t->data_size, t->data_alignment);
1015 }
1016 type->struct_offsets[0] = offset;
1017 type->total_struct_size = offset + data_size;
1018 }
1019 if (type->total_struct_size && !_pw_is_subtype_t(type, PwTypeId_Struct)) {
1020 pw_panic("New type %s(id=%u) has %u bytes of associated data but is not derived from struct\n",
1021 name, type_id, type->total_struct_size);
1022 }
1023
1024 // init interface definitions, set interface_id field
1025
1026 if (separator == PW_INTERFACES) {
1027
1028 PwInterface_Generic** idefs = (PwInterface_Generic**) mmarray;
1029 mmarray_reset(mmarray, sizeof(PwInterface_Generic*));
1030 for (;;) {
1031 int interface_id = va_arg(ap, int);
1032 if (interface_id == -1) {
1033 separator = -1;
1034 break;
1035 }
1036 if (!pw_interface_exists(interface_id)) {
1037 pw_panic("Interface %d for new type %s(id=%u) does not exist\n", interface_id, name, type_id);
1038 }
1039 for (uint16_t i = 0; i < type->num_interface_definitions; i++) {
1040 if (interface_id == idefs[i]->id) {
1041 pw_panic("Duplicate interface %s(id=%d) for new type %s(id=%u)\n",
1042 pw_get_interface_name(interface_id), interface_id, name, type_id);
1043 }
1044 }
1045 PwInterface_Generic* interface = va_arg(ap, PwInterface_Generic*);
1046 mmarray = idefs = mmarray_grow(idefs, 1);
1047 idefs[type->num_interface_definitions++] = interface;
1048 interface->id = interface_id;
1049 }
1050 if (type->num_interface_definitions) {
1051 type->interface_definitions = _pw_arena_alloc(type->num_interface_definitions, PwInterface_Generic*);
1052 memcpy(type->interface_definitions, idefs, type->num_interface_definitions * sizeof(PwInterface_Generic*));
1053 }
1054 }
1055 if (separator != -1) {
1056 pw_panic("%s: bad arguments\n", name);
1057 }
1058 va_end(ap);
1059
1060 // init interfaces
1061
1062 // collect interface ids
1063 unsigned num_interfaces = 0;
1064 uint16_t* all_interface_ids = (uint16_t*) mmarray;
1065 mmarray_reset(mmarray, sizeof(uint16_t));
1066
1067 // iterate base types backward, then process `type` itself
1068 PwType** base_type_end = type->base_types;
1069 PwType** base_type = base_type_end + type->num_base_types;
1070 for (;;) {
1071 if (base_type == &type) {
1072 break;
1073 } else if (base_type > base_type_end) {
1074 base_type--;
1075 } else if (base_type == base_type_end) {
1076 // finally, process new type
1077 base_type = &type;
1078 } else {
1079 pw_panic("oops\n");
1080 }
1081 PwType* t = *base_type;
1082
1083 PwInterface_Generic** interface = t->interface_definitions;
1084 PwInterface_Generic** interface_end = interface + t->num_interface_definitions;
1085 while (interface < interface_end) {
1086 uint16_t interface_id = (*interface)->id;
1087 bool unique = true;
1088 uint16_t* id_seen = all_interface_ids;
1089 uint16_t* id_seen_end = id_seen + num_interfaces;
1090 while (id_seen < id_seen_end) {
1091 if (interface_id == *id_seen++) {
1092 unique = false;
1093 break;
1094 }
1095 }
1096 if (unique) {
1097 mmarray = all_interface_ids = mmarray_grow(all_interface_ids, 1);
1098 all_interface_ids[num_interfaces++] = interface_id;
1099 }
1100 interface++;
1101 }
1102 }
1103
1104 // allocate array for non-builtin interfaces
1105 // count non-builtin interfaces
1106 for (unsigned i = 0; i < num_interfaces; i++) {
1107 if (all_interface_ids[i] >= PW_NUM_BUILTIN_INTERFACES) {
1108 type->num_other_interfaces++;
1109 }
1110 }
1111 if (type->num_other_interfaces) {
1112 type->other_interfaces = _pw_arena_alloc(type->num_other_interfaces, PwInterface_Generic*);
1113 }
1114
1115 // make interfaces
1116
1117 unsigned other_interface_index = 0; // for initializing type->other_interfaces
1118
1119 for (unsigned i = 0; i < num_interfaces; i++) {
1120 uint16_t interface_id = all_interface_ids[i];
1121 if (interface_id >= PW_NUM_BUILTIN_INTERFACES) {
1122 type->other_interfaces[other_interface_index++] = _pw_make_interface(type, interface_id);
1123 } else {
1124 type->builtin_interfaces[interface_id] = _pw_make_interface(type, interface_id);
1125 }
1126 }
1127
1128 mmarray_free(mmarray);
1129
1130 num_pw_types++;
1131 return type_id;
1132}
1133
1134extern PwInterface_Basic _pw_status_basic_interface;
1135extern PwInterface_Basic _pw_exception_basic_interface;
1136
1137#define builtin_type(name, ...) \
1138 pw_hard_assert(PwTypeId_##name == pw_add_type(#name, __VA_ARGS__))
1139
1140#define builtin_type2(name, ...) \
1141 pw_hard_assert(PwTypeId_##name == pw_add_type2(#name, __VA_ARGS__))
1142
1143[[gnu::constructor]]
1144void _pw_init_types()
1145{
1146 _pw_init_interfaces();
1147
1148 if (_pw_types) {
1149 return;
1150 }
1151
1152 _pw_types = mmarray_allocate(65536, 0, sizeof(PwType*));
1153
1154 builtin_type(Null, PW_INTERFACES, PwInterfaceId_Basic, &null_basic_interface );
1155 builtin_type(Bool, PW_INTERFACES, PwInterfaceId_Basic, &bool_basic_interface );
1156 builtin_type(Int, PW_INTERFACES, PwInterfaceId_Basic, &int_basic_interface );
1157 builtin_type(Signed, PW_PARENTS, PwTypeId_Int, PW_INTERFACES, PwInterfaceId_Basic, &signed_basic_interface );
1158 builtin_type(Unsigned, PW_PARENTS, PwTypeId_Int, PW_INTERFACES, PwInterfaceId_Basic, &unsigned_basic_interface );
1159 builtin_type(Float, PW_INTERFACES, PwInterfaceId_Basic, &float_basic_interface );
1160 builtin_type(DateTime, PW_INTERFACES, PwInterfaceId_Basic, &datetime_basic_interface );
1161 builtin_type(Timestamp, PW_INTERFACES, PwInterfaceId_Basic, ×tamp_basic_interface );
1162 builtin_type(Ptr, PW_INTERFACES, PwInterfaceId_Basic, &ptr_basic_interface );
1163 builtin_type(Status, PW_INTERFACES, PwInterfaceId_Basic, &_pw_status_basic_interface );
1164
1165 builtin_type2(String, _PwStringData,
1166 PW_INTERFACES,
1167 PwInterfaceId_Basic, &_pw_string_basic_interface,
1168 PwInterfaceId_Append, &_pw_string_append_interface);
1169
1170 builtin_type2(Struct, _PwStructData,
1171 PW_INTERFACES,
1172 PwInterfaceId_Basic, &_pw_struct_basic_interface);
1173
1174 builtin_type2(Compound, _PwCompoundData,
1175 PW_PARENTS,
1176 PwTypeId_Struct,
1177 PW_INTERFACES,
1178 PwInterfaceId_Basic, &_pw_compound_basic_interface);
1179
1180 builtin_type2(Exception, _PwExceptionData,
1181 PW_PARENTS,
1182 PwTypeId_Struct, PwTypeId_Status,
1183 PW_INTERFACES,
1184 PwInterfaceId_Basic, &_pw_exception_basic_interface);
1185
1186 builtin_type2(BasicArray, _PwArray,
1187 PW_PARENTS,
1188 PwTypeId_Struct,
1189 PW_INTERFACES,
1190 PwInterfaceId_Basic, &_pw_basic_array_basic_interface,
1191 PwInterfaceId_RandomAccess, &_pw_basic_array_random_access_interface,
1192 PwInterfaceId_Append, &_pw_basic_array_append_interface);
1193
1194 builtin_type(Array, PW_PARENTS, PwTypeId_BasicArray, PwTypeId_Compound);
1195
1196 builtin_type2(BasicSet, _PwSet,
1197 PW_PARENTS,
1198 PwTypeId_Struct,
1199 PW_INTERFACES,
1200 PwInterfaceId_Basic, &_pw_basic_set_basic_interface);
1201
1202 builtin_type(Set, PW_PARENTS, PwTypeId_BasicSet, PwTypeId_Compound);
1203
1204 builtin_type2(BasicMap, _PwMap,
1205 PW_PARENTS,
1206 PwTypeId_Struct,
1207 PW_INTERFACES,
1208 PwInterfaceId_Basic, &_pw_basic_map_basic_interface,
1209 PwInterfaceId_RandomAccess, &_pw_basic_map_random_access_interface);
1210
1211 builtin_type(Map, PW_PARENTS, PwTypeId_BasicMap, PwTypeId_Compound);
1212}
1213
1214/****************************************************************
1215 * Misc. helpers
1216 */
1217
1218void* _pw_get_subtype_struct_ptr(PwValuePtr value, uint16_t type_id)
1219{
1220 PwType* value_type = _pw_types[value->type_id];
1221 PwType** base_type = value_type->base_types;
1222 if (base_type) {
1223 PwType** base_types_end = base_type + value_type->num_base_types;
1224 unsigned* struct_offset = &value_type->struct_offsets[1];
1225 while (base_type < base_types_end) {
1226 if (type_id == (*base_type)->id) {
1227 return (void*)( ((uint8_t*) value->struct_data) + *struct_offset );
1228 }
1229 base_type++;
1230 struct_offset++;
1231 }
1232 }
1233 return nullptr;
1234}
1235
1236[[nodiscard]] bool _pw_iteration_in_progress(PwValuePtr value)
1237{
1238 if (pw_is_struct(value)) {
1239 _PwStructData* struct_data = (_PwStructData*) value->struct_data;
1240 return _pw_atomic_load(&struct_data->itercount) != 0;
1241 }
1242 return false;
1243}
1244
1245static void dump_interface(FILE* fp, PwInterface_Generic* interface, unsigned indent)
1246{
1247 _pw_print_indent(fp, indent);
1248 fprintf(fp, "%s; id=%u; %u methods:\n", interface->name, interface->id, interface->num_methods);
1249
1250 for (unsigned i = 0; i < interface->num_methods; i++) {
1251 PwMethod_Generic* method = &interface->methods[i];
1252 char* method_name = interface->method_names[i];
1253
1254 _pw_print_indent(fp, indent + 4);
1255
1256 void *p = (void*) &method->func; // work around lack of formatting for function pointers
1257 static_assert(sizeof(PwFunc_Generic) == sizeof(void*));
1258
1259 fprintf(fp, "%p %s %u", *((void**) p), method_name, method->struct_offset);
1260
1261 PwMethod_Generic* m = method->super;
1262 while (m) {
1263 void *p = (void*) &m->func; // work around lack of formatting for function pointers
1264 static_assert(sizeof(PwFunc_Generic) == sizeof(void*));
1265
1266 fprintf(fp, ", %p %s::%s %u", *((void**) p), m->self->type->name, method_name, m->struct_offset);
1267 m = m->super;
1268 }
1269 fputc('\n', fp);
1270 }
1271}
1272
1273void pw_dump_types(FILE* fp)
1274{
1275 fprintf(fp, "=== %u PW types (%p) ===\n", num_pw_types, (void*) _pw_types);
1276 for (uint16_t i = 0; i < num_pw_types; i++) {
1277 PwType* t = _pw_types[i];
1278 fprintf(fp, "%u: %s\n", t->id, t->name);
1279 if (t->num_parents) {
1280 fputs(" parent types: ", fp);
1281 for (unsigned j = 0; j < t->num_parents; j++) {
1282 if (j) {
1283 fputs(", ", fp);
1284 }
1285 fprintf(fp, "%s(%u)", t->parents[j]->name, t->parents[j]->id);
1286 }
1287 fputc('\n', fp);
1288 }
1289 if (t->num_base_types) {
1290 fputs(" all base types: ", fp);
1291 for (unsigned j = 0; j < t->num_base_types; j++) {
1292 if (j) {
1293 fputs(", ", fp);
1294 }
1295 fprintf(fp, "%s (%u)", t->base_types[j]->name, t->base_types[j]->id);
1296 }
1297 fputc('\n', fp);
1298 }
1299 if (t->total_struct_size) {
1300 fprintf(fp, " struct size: %u -- ", t->total_struct_size);
1301 for (unsigned j = t->num_base_types; j > 0;) {
1302 PwType* bt = t->base_types[--j];
1303 fprintf(fp, "%u: %s %u bytes@%u, ", t->struct_offsets[j + 1], bt->name, bt->data_size, bt->data_alignment);
1304 }
1305 fprintf(fp, "%u: %s %u bytes@%u\n", t->struct_offsets[0], t->name, t->data_size, t->data_alignment);
1306 }
1307 fprintf(fp, " builtin interfaces:\n");
1308 for (uint16_t interface_id = 0; interface_id < PW_NUM_BUILTIN_INTERFACES; interface_id++) {
1309 PwInterface_Generic* interface = t->builtin_interfaces[interface_id];
1310 if (interface) {
1311 dump_interface(fp, interface, 4);
1312 }
1313 }
1314 if (t->num_other_interfaces) {
1315 fprintf(fp, " other interfaces:\n");
1316 PwInterface_Generic** interface = t->other_interfaces;
1317 PwInterface_Generic** interface_end = interface + t->num_other_interfaces;
1318 while (interface < interface_end) {
1319 dump_interface(fp, *interface, 4);
1320 interface++;
1321 }
1322 }
1323 }
1324}