infix
A JIT-Powered FFI Library for C
Loading...
Searching...
No Matches
types.c
Go to the documentation of this file.
1
39#include "common/utility.h"
40#include <limits.h>
41#include <stdio.h>
42#include <stdlib.h>
43#include <string.h>
44
45// Static Descriptors for Primitive and Built-in Types
46
60#define INFIX_TYPE_INIT(id, T) \
61 {.name = nullptr, \
62 .category = INFIX_TYPE_PRIMITIVE, \
63 .size = sizeof(T), \
64 .alignment = _Alignof(T), \
65 .is_arena_allocated = false, \
66 .arena = nullptr, \
67 .meta.primitive_id = id}
68
74static infix_type _infix_type_void = {.name = nullptr,
75 .category = INFIX_TYPE_VOID,
76 .size = 0,
77 .alignment = 0,
78 .is_arena_allocated = false,
79 .arena = nullptr,
80 .meta = {0}};
86static infix_type _infix_type_pointer = {.name = nullptr,
87 .category = INFIX_TYPE_POINTER,
88 .size = sizeof(void *),
89 .alignment = _Alignof(void *),
90 .is_arena_allocated = false,
91 .arena = nullptr,
92 .meta.pointer_info = {.pointee_type = &_infix_type_void}};
93
112#if !defined(INFIX_COMPILER_MSVC)
117#endif
122#if defined(INFIX_COMPILER_MSVC) || (defined(INFIX_OS_WINDOWS) && defined(INFIX_COMPILER_CLANG)) || \
123 defined(INFIX_OS_MACOS)
124// On these platforms, long double is just an alias for double, so no separate singleton is needed.
125#else
128#endif
129
130// Public API: Type Creation Functions
131
139 switch (id) {
141 return &_infix_type_bool;
143 return &_infix_type_uint8;
145 return &_infix_type_sint8;
147 return &_infix_type_uint16;
149 return &_infix_type_sint16;
151 return &_infix_type_uint32;
153 return &_infix_type_sint32;
155 return &_infix_type_uint64;
157 return &_infix_type_sint64;
158#if !defined(INFIX_COMPILER_MSVC)
160 return &_infix_type_uint128;
162 return &_infix_type_sint128;
163#endif
165 return &_infix_type_float;
167 return &_infix_type_double;
169#if defined(INFIX_COMPILER_MSVC) || (defined(INFIX_OS_WINDOWS) && defined(INFIX_COMPILER_CLANG)) || \
170 defined(INFIX_OS_MACOS)
171 // On platforms where long double is just an alias for double, return the double singleton
172 // to maintain consistent type representation.
173 return &_infix_type_double;
174#else
176#endif
177 default:
178 // Return null for any invalid primitive ID.
179 return nullptr;
180 }
181}
182
188
194
202infix_struct_member infix_type_create_member(const char * name, infix_type * type, size_t offset) {
203 return (infix_struct_member){name, type, offset};
204}
205
224 infix_type ** out_type,
225 infix_struct_member ** out_arena_members,
227 size_t num_members) {
228 if (out_type == nullptr)
230 // Pre-flight check: ensure all provided member types are valid.
231 for (size_t i = 0; i < num_members; ++i) {
232 if (members[i].type == nullptr) {
233 *out_type = nullptr;
236 }
237 }
238 infix_type * type = infix_arena_calloc(arena, 1, sizeof(infix_type), _Alignof(infix_type));
239 if (type == nullptr) {
240 *out_type = nullptr;
243 }
244
245 infix_struct_member * arena_members = nullptr;
246 if (num_members > 0) {
247 arena_members =
248 infix_arena_alloc(arena, sizeof(infix_struct_member) * num_members, _Alignof(infix_struct_member));
249 if (arena_members == nullptr) {
250 *out_type = nullptr;
253 }
254 infix_memcpy(arena_members, members, sizeof(infix_struct_member) * num_members);
255 }
256 *out_type = type;
257 *out_arena_members = arena_members;
258 return INFIX_SUCCESS;
259}
260
269 infix_type ** out_type,
270 infix_type * pointee_type) {
271 if (!out_type || !pointee_type) {
274 }
275 infix_type * type = infix_arena_calloc(arena, 1, sizeof(infix_type), _Alignof(infix_type));
276 if (type == nullptr) {
277 *out_type = nullptr;
280 }
281 // Start by copying the layout of a generic pointer.
282 *type = *infix_type_create_pointer();
283 // Mark it as arena-allocated so it can be deep-copied and freed correctly.
284 type->is_arena_allocated = true;
285 // Set the specific pointee type.
286 type->meta.pointer_info.pointee_type = pointee_type;
287 *out_type = type;
288 return INFIX_SUCCESS;
289}
290
300 infix_type ** out_type,
301 infix_type * element_type,
302 size_t num_elements) {
303 if (out_type == nullptr || element_type == nullptr) {
306 }
307 if (element_type->size > 0 && num_elements > SIZE_MAX / element_type->size) {
308 *out_type = nullptr;
311 }
312 infix_type * type = infix_arena_calloc(arena, 1, sizeof(infix_type), _Alignof(infix_type));
313 if (type == nullptr) {
314 *out_type = nullptr;
317 }
318 type->is_arena_allocated = true;
320 type->meta.array_info.element_type = element_type;
321 type->meta.array_info.num_elements = num_elements;
322 // An array's alignment is the same as its element's alignment.
323 type->alignment = element_type->alignment;
324 type->size = element_type->size * num_elements;
325 *out_type = type;
326 return INFIX_SUCCESS;
327}
328
338 infix_type ** out_type,
339 infix_type * underlying_type) {
340 if (out_type == nullptr || underlying_type == nullptr) {
343 }
344 if (underlying_type->category != INFIX_TYPE_PRIMITIVE ||
345 underlying_type->meta.primitive_id > INFIX_PRIMITIVE_SINT128) {
348 }
349 infix_type * type = infix_arena_calloc(arena, 1, sizeof(infix_type), _Alignof(infix_type));
350 if (type == nullptr) {
351 *out_type = nullptr;
354 }
355 type->is_arena_allocated = true;
357 // An enum has the same memory layout as its underlying integer type.
358 type->size = underlying_type->size;
359 type->alignment = underlying_type->alignment;
360 type->meta.enum_info.underlying_type = underlying_type;
361 *out_type = type;
362 return INFIX_SUCCESS;
363}
364
373 infix_type ** out_type,
374 infix_type * base_type) {
375 if (out_type == nullptr || base_type == nullptr || (!is_float(base_type) && !is_double(base_type))) {
378 }
379 infix_type * type = infix_arena_calloc(arena, 1, sizeof(infix_type), _Alignof(infix_type));
380 if (type == nullptr) {
381 *out_type = nullptr;
384 }
385 type->is_arena_allocated = true;
387 // A complex number is simply two floating-point numbers back-to-back.
388 type->size = base_type->size * 2;
389 type->alignment = base_type->alignment;
390 type->meta.complex_info.base_type = base_type;
391 *out_type = type;
392 return INFIX_SUCCESS;
393}
394
404 infix_type ** out_type,
405 infix_type * element_type,
406 size_t num_elements) {
407 if (out_type == nullptr || element_type == nullptr || element_type->category != INFIX_TYPE_PRIMITIVE) {
410 }
411 if (element_type->size > 0 && num_elements > SIZE_MAX / element_type->size) {
412 *out_type = nullptr;
415 }
416 infix_type * type = infix_arena_calloc(arena, 1, sizeof(infix_type), _Alignof(infix_type));
417 if (type == nullptr) {
418 *out_type = nullptr;
421 }
422 type->is_arena_allocated = true;
424 type->meta.vector_info.element_type = element_type;
425 type->meta.vector_info.num_elements = num_elements;
426 type->size = element_type->size * num_elements;
427 // Vector alignment is typically its total size, up to a platform-specific maximum (e.g., 16 on x64).
428 // This is a simplification; the ABI-specific classifiers will handle the true alignment rules.
429 type->alignment = type->size > 8 ? 16 : type->size;
430 *out_type = type;
431 return INFIX_SUCCESS;
432}
433
443 infix_type ** out_type,
445 size_t num_members) {
446 infix_type * type = nullptr;
447 infix_struct_member * arena_members = nullptr;
448 infix_status status = _create_aggregate_setup(arena, &type, &arena_members, members, num_members);
449 if (status != INFIX_SUCCESS) {
450 *out_type = nullptr;
451 return status;
452 }
453 type->is_arena_allocated = true;
455 type->meta.aggregate_info.members = arena_members;
456 type->meta.aggregate_info.num_members = num_members;
457
458 // A union's size is the size of its largest member, and its alignment is the
459 // alignment of its most-aligned member.
460 size_t max_size = 0;
461 size_t max_alignment = 1;
462 for (size_t i = 0; i < num_members; ++i) {
463 arena_members[i].offset = 0; // All union members have an offset of 0.
464 if (arena_members[i].type->size > max_size)
465 max_size = arena_members[i].type->size;
466 if (arena_members[i].type->alignment > max_alignment)
467 max_alignment = arena_members[i].type->alignment;
468 }
469 type->alignment = max_alignment;
470 // The total size is the size of the largest member, padded up to the required alignment.
471 type->size = _infix_align_up(max_size, max_alignment);
472 // Overflow check
473 if (type->size < max_size) {
474 *out_type = nullptr;
477 }
478 *out_type = type;
479 return INFIX_SUCCESS;
480}
481
491 infix_type ** out_type,
493 size_t num_members) {
495 infix_type * type = nullptr;
496 infix_struct_member * arena_members = nullptr;
497 infix_status status = _create_aggregate_setup(arena, &type, &arena_members, members, num_members);
498 if (status != INFIX_SUCCESS) {
499 *out_type = nullptr;
500 return status;
501 }
502 type->is_arena_allocated = true;
504 type->meta.aggregate_info.members = arena_members;
505 type->meta.aggregate_info.num_members = num_members;
506
507 // This performs a preliminary layout calculation based on standard C packing rules.
508 // Note: This layout may be incomplete if it contains unresolved named references.
509 // The final, correct layout will be computed by `_infix_type_recalculate_layout`.
510 size_t current_offset = 0;
511 size_t max_alignment = 1;
512 for (size_t i = 0; i < num_members; ++i) {
513 infix_struct_member * member = &arena_members[i];
514 size_t member_align = member->type->alignment;
515
516 // An unresolved named reference will have alignment 0 or 1. If it's 0, we treat it as 1 for
517 // this preliminary pass to avoid division by zero. The real alignment will be fixed later.
518 if (member_align == 0) {
519 if (member->type->category != INFIX_TYPE_NAMED_REFERENCE) {
520 // A zero-alignment type that isn't a named reference is invalid (e.g., a struct with a void member).
521 *out_type = nullptr;
524 }
525 member_align = 1;
526 }
527
528 // Align the current offset up to the boundary required by the current member.
529 size_t aligned_offset = _infix_align_up(current_offset, member_align);
530 if (aligned_offset < current_offset) { // Overflow check
531 *out_type = nullptr;
534 }
535 current_offset = aligned_offset;
536 member->offset = current_offset;
537
538 // Add the member's size to the current offset.
539 if (current_offset > SIZE_MAX - member->type->size) { // Overflow check
540 *out_type = nullptr;
543 }
544 current_offset += member->type->size;
545 // Keep track of the largest alignment requirement.
546 if (member_align > max_alignment)
547 max_alignment = member_align;
548 }
549 // A struct's alignment is the alignment of its most-aligned member.
550 type->alignment = max_alignment;
551 // The struct's total size is its occupied space, padded up to its alignment.
552 type->size = _infix_align_up(current_offset, max_alignment);
553 if (type->size < current_offset) { // Overflow check
554 *out_type = nullptr;
557 }
558 *out_type = type;
559 return INFIX_SUCCESS;
560}
561
573 infix_type ** out_type,
574 size_t total_size,
575 size_t alignment,
577 size_t num_members) {
578 if (out_type == nullptr || (num_members > 0 && members == nullptr) || alignment == 0) {
581 }
582 infix_type * type = infix_arena_calloc(arena, 1, sizeof(infix_type), _Alignof(infix_type));
583 if (type == nullptr) {
584 *out_type = nullptr;
587 }
588 infix_struct_member * arena_members = nullptr;
589 if (num_members > 0) {
590 arena_members =
591 infix_arena_alloc(arena, sizeof(infix_struct_member) * num_members, _Alignof(infix_struct_member));
592 if (arena_members == nullptr) {
593 *out_type = nullptr;
596 }
597 infix_memcpy(arena_members, members, sizeof(infix_struct_member) * num_members);
598 }
599 type->is_arena_allocated = true;
600 type->size = total_size;
601 type->alignment = alignment;
602 type->category = INFIX_TYPE_STRUCT; // Packed structs are still fundamentally structs.
603 type->meta.aggregate_info.members = arena_members;
604 type->meta.aggregate_info.num_members = num_members;
605 *out_type = type;
606 return INFIX_SUCCESS;
607}
608
621 infix_type ** out_type,
622 const char * name,
624 if (out_type == nullptr || name == nullptr) {
627 }
628 infix_type * type = infix_arena_calloc(arena, 1, sizeof(infix_type), _Alignof(infix_type));
629 if (type == nullptr) {
630 *out_type = nullptr;
633 }
634 // The name must be copied into the arena to ensure its lifetime matches the type's.
635 size_t name_len = strlen(name) + 1;
636 char * arena_name = infix_arena_alloc(arena, name_len, 1);
637 if (arena_name == nullptr) {
638 *out_type = nullptr;
641 }
642 infix_memcpy(arena_name, name, name_len);
643 type->is_arena_allocated = true;
645 type->size = 0; // Size and alignment are unknown until resolution.
646 type->alignment = 1; // Default to 1 to be safe in preliminary layout calculations.
647 type->meta.named_reference.name = arena_name;
649 *out_type = type;
650 return INFIX_SUCCESS;
651}
652
653// Internal Type Graph Management
654
671
696 recalc_visited_node_t ** visited_head) {
697 if (!type || !type->is_arena_allocated)
698 return; // Base case: Don't modify static singleton types.
699
700 // Cycle detection: If we have already visited this node in the current recursion
701 // path, we are in a cycle. Return immediately to break the loop. The layout of
702 // this node will be calculated when the recursion unwinds to its first visit.
703 for (recalc_visited_node_t * v = *visited_head; v != nullptr; v = v->next)
704 if (v->type == type)
705 return;
706
707 // Allocate the memoization node from a stable temporary arena.
708 recalc_visited_node_t * visited_node =
709 infix_arena_alloc(temp_arena, sizeof(recalc_visited_node_t), _Alignof(recalc_visited_node_t));
710 if (!visited_node)
711 return; // Cannot proceed without memory.
712 visited_node->type = type;
713 visited_node->next = *visited_head;
714 *visited_head = visited_node;
715
716 // Recurse into child types first (post-order traversal).
717 switch (type->category) {
720 break;
721 case INFIX_TYPE_ARRAY:
723 break;
725 case INFIX_TYPE_UNION:
726 for (size_t i = 0; i < type->meta.aggregate_info.num_members; ++i) {
728 temp_arena, type->meta.aggregate_info.members[i].type, visited_head);
729 }
730 break;
731 default:
732 break; // Other types have no child types to recurse into.
733 }
734
735 // After children are updated, recalculate this type's layout.
737 size_t current_offset = 0;
738 size_t max_alignment = 1;
739 for (size_t i = 0; i < type->meta.aggregate_info.num_members; ++i) {
741 size_t member_align = member->type->alignment;
742 if (member_align > max_alignment)
743 max_alignment = member_align;
744 current_offset = _infix_align_up(current_offset, member_align);
745 member->offset = current_offset;
746 current_offset += member->type->size;
747 }
748 type->alignment = max_alignment;
749 type->size = _infix_align_up(current_offset, max_alignment);
750 }
751 else if (type->category == INFIX_TYPE_UNION) {
752 size_t max_size = 0;
753 size_t max_alignment = 1;
754 for (size_t i = 0; i < type->meta.aggregate_info.num_members; ++i) {
755 infix_type * member_type = type->meta.aggregate_info.members[i].type;
756 if (member_type->size > max_size)
757 max_size = member_type->size;
758 if (member_type->alignment > max_alignment)
759 max_alignment = member_type->alignment;
760 }
761 type->alignment = max_alignment;
762 type->size = _infix_align_up(max_size, max_alignment);
763 }
764 else if (type->category == INFIX_TYPE_ARRAY) {
765 // Recalculate array size based on the (potentially updated) element size.
768 }
769}
770
781 // Create a temporary arena solely for the visited list's lifetime.
782 infix_arena_t * temp_arena = infix_arena_create(1024);
783 if (!temp_arena)
784 return;
785
786 recalc_visited_node_t * visited_head = nullptr;
787 _infix_type_recalculate_layout_recursive(temp_arena, type, &visited_head);
788
789 infix_arena_destroy(temp_arena);
790}
791
805
822 const infix_type * src_type,
823 memo_node_t ** memo_head) {
824 if (src_type == nullptr)
825 return nullptr;
826
827 // If the source type lives in the same arena as our destination, we can safely share the pointer instead of
828 // performing a deep copy.
829 if (src_type->arena == dest_arena)
830 return (infix_type *)src_type;
831
832 // Base case: Static types don't need to be copied; return the singleton pointer.
833 if (!src_type->is_arena_allocated)
834 return (infix_type *)src_type;
835
836 // Check memoization table: if we've already copied this node, return the existing copy.
837 // This correctly handles cycles and shared sub-graphs.
838 for (memo_node_t * node = *memo_head; node != NULL; node = node->next)
839 if (node->src == src_type)
840 return node->dest;
841
842 // Allocate the new type object in the destination arena.
843 infix_type * dest_type = infix_arena_calloc(dest_arena, 1, sizeof(infix_type), _Alignof(infix_type));
844 if (dest_type == nullptr)
845 return nullptr;
846
847 // Add this new pair to the memoization table BEFORE recursing. This is crucial
848 // for handling cycles: the recursive call will find this entry and return `dest_type`.
849 memo_node_t * new_memo_node = infix_arena_alloc(dest_arena, sizeof(memo_node_t), _Alignof(memo_node_t));
850 if (!new_memo_node)
851 return nullptr;
852 new_memo_node->src = src_type;
853 new_memo_node->dest = dest_type;
854 new_memo_node->next = *memo_head;
855 *memo_head = new_memo_node;
856
857 // Perform a shallow copy of the main struct, then recurse to deep copy child pointers.
858 *dest_type = *src_type;
859 dest_type->is_arena_allocated = true;
860 dest_type->arena = dest_arena; // The new type now belongs to the destination arena.
861
862 // Deep copy the semantic name string, if it exists.
863 if (src_type->name) {
864 size_t name_len = strlen(src_type->name) + 1;
865 char * dest_name = infix_arena_alloc(dest_arena, name_len, 1);
866 if (!dest_name)
867 return nullptr; // Allocation failed
868 infix_memcpy((void *)dest_name, src_type->name, name_len);
869 dest_type->name = dest_name;
870 }
871
872 switch (src_type->category) {
874 dest_type->meta.pointer_info.pointee_type =
875 _copy_type_graph_to_arena_recursive(dest_arena, src_type->meta.pointer_info.pointee_type, memo_head);
876 break;
877 case INFIX_TYPE_ARRAY:
878 dest_type->meta.array_info.element_type =
879 _copy_type_graph_to_arena_recursive(dest_arena, src_type->meta.array_info.element_type, memo_head);
880 break;
882 case INFIX_TYPE_UNION:
883 if (src_type->meta.aggregate_info.num_members > 0) {
884 // Copy the members array itself.
885 size_t members_size = sizeof(infix_struct_member) * src_type->meta.aggregate_info.num_members;
886 dest_type->meta.aggregate_info.members =
887 infix_arena_alloc(dest_arena, members_size, _Alignof(infix_struct_member));
888 if (dest_type->meta.aggregate_info.members == nullptr)
889 return nullptr;
890 // Now, recurse for each member's type and copy its name.
891 for (size_t i = 0; i < src_type->meta.aggregate_info.num_members; ++i) {
892 dest_type->meta.aggregate_info.members[i] = src_type->meta.aggregate_info.members[i];
894 dest_arena, src_type->meta.aggregate_info.members[i].type, memo_head);
895 const char * src_name = src_type->meta.aggregate_info.members[i].name;
896 if (src_name) {
897 size_t name_len = strlen(src_name) + 1;
898 char * dest_name = infix_arena_alloc(dest_arena, name_len, 1);
899 if (!dest_name)
900 return nullptr;
901 infix_memcpy((void *)dest_name, src_name, name_len);
902 dest_type->meta.aggregate_info.members[i].name = dest_name;
903 }
904 }
905 }
906 break;
908 {
909 const char * src_name = src_type->meta.named_reference.name;
910 if (src_name) {
911 size_t name_len = strlen(src_name) + 1;
912 char * dest_name = infix_arena_alloc(dest_arena, name_len, 1);
913 if (!dest_name)
914 return nullptr;
915 infix_memcpy((void *)dest_name, src_name, name_len);
916 dest_type->meta.named_reference.name = dest_name;
917 }
918 break;
919 }
921 dest_type->meta.func_ptr_info.return_type =
922 _copy_type_graph_to_arena_recursive(dest_arena, src_type->meta.func_ptr_info.return_type, memo_head);
923 if (src_type->meta.func_ptr_info.num_args > 0) {
924 size_t args_size = sizeof(infix_function_argument) * src_type->meta.func_ptr_info.num_args;
925 dest_type->meta.func_ptr_info.args =
926 infix_arena_alloc(dest_arena, args_size, _Alignof(infix_function_argument));
927 if (dest_type->meta.func_ptr_info.args == nullptr)
928 return nullptr;
929 for (size_t i = 0; i < src_type->meta.func_ptr_info.num_args; ++i) {
930 dest_type->meta.func_ptr_info.args[i] = src_type->meta.func_ptr_info.args[i];
932 dest_arena, src_type->meta.func_ptr_info.args[i].type, memo_head);
933 const char * src_name = src_type->meta.func_ptr_info.args[i].name;
934 if (src_name) {
935 size_t name_len = strlen(src_name) + 1;
936 char * dest_name = infix_arena_alloc(dest_arena, name_len, 1);
937 if (!dest_name)
938 return nullptr;
939 infix_memcpy((void *)dest_name, src_name, name_len);
940 dest_type->meta.func_ptr_info.args[i].name = dest_name;
941 }
942 }
943 }
944 break;
945 case INFIX_TYPE_ENUM:
946 dest_type->meta.enum_info.underlying_type =
947 _copy_type_graph_to_arena_recursive(dest_arena, src_type->meta.enum_info.underlying_type, memo_head);
948 break;
950 dest_type->meta.complex_info.base_type =
951 _copy_type_graph_to_arena_recursive(dest_arena, src_type->meta.complex_info.base_type, memo_head);
952 break;
954 dest_type->meta.vector_info.element_type =
955 _copy_type_graph_to_arena_recursive(dest_arena, src_type->meta.vector_info.element_type, memo_head);
956 break;
957 default:
958 // Other types like primitives have no child pointers to copy.
959 break;
960 }
961 return dest_type;
962}
963
972 memo_node_t * memo_head = nullptr;
973 return _copy_type_graph_to_arena_recursive(dest_arena, src_type, &memo_head);
974}
975
985
999 const infix_type * type,
1000 estimate_visited_node_t ** visited_head) {
1001 if (!type || !type->is_arena_allocated)
1002 return 0;
1003
1004 // Cycle detection: if we've seen this node, it's already accounted for.
1005 for (estimate_visited_node_t * v = *visited_head; v != NULL; v = v->next)
1006 if (v->type == type)
1007 return 0;
1008
1009 // Add this node to the visited list before recursing.
1010 estimate_visited_node_t * visited_node =
1012 if (!visited_node) {
1013 // On allocation failure, we can't proceed with estimation. Return a large
1014 // number to ensure the caller allocates a fallback-sized arena.
1015 return 65536;
1016 }
1017 visited_node->type = type;
1018 visited_node->next = *visited_head;
1019 *visited_head = visited_node;
1020
1021 // The size includes the type object itself, a memoization node, and the name string if it exists.
1022 size_t total_size = sizeof(infix_type) + sizeof(memo_node_t);
1023 if (type->name)
1024 total_size += strlen(type->name) + 1;
1025
1026 switch (type->category) {
1027 case INFIX_TYPE_POINTER:
1028 total_size += _estimate_graph_size_recursive(temp_arena, type->meta.pointer_info.pointee_type, visited_head);
1029 break;
1030 case INFIX_TYPE_ARRAY:
1031 total_size += _estimate_graph_size_recursive(temp_arena, type->meta.array_info.element_type, visited_head);
1032 break;
1033 case INFIX_TYPE_STRUCT:
1034 case INFIX_TYPE_UNION:
1036 total_size += sizeof(infix_struct_member) * type->meta.aggregate_info.num_members;
1037 for (size_t i = 0; i < type->meta.aggregate_info.num_members; ++i) {
1038 const infix_struct_member * member = &type->meta.aggregate_info.members[i];
1039 if (member->name)
1040 total_size += strlen(member->name) + 1;
1041 total_size += _estimate_graph_size_recursive(temp_arena, member->type, visited_head);
1042 }
1043 }
1044 break;
1047 total_size += strlen(type->meta.named_reference.name) + 1;
1048 break;
1050 total_size += _estimate_graph_size_recursive(temp_arena, type->meta.func_ptr_info.return_type, visited_head);
1051 if (type->meta.func_ptr_info.num_args > 0) {
1052 total_size += sizeof(infix_function_argument) * type->meta.func_ptr_info.num_args;
1053 for (size_t i = 0; i < type->meta.func_ptr_info.num_args; ++i) {
1055 if (arg->name)
1056 total_size += strlen(arg->name) + 1;
1057 total_size += _estimate_graph_size_recursive(temp_arena, arg->type, visited_head);
1058 }
1059 }
1060 break;
1061 case INFIX_TYPE_ENUM:
1062 total_size += _estimate_graph_size_recursive(temp_arena, type->meta.enum_info.underlying_type, visited_head);
1063 break;
1064 case INFIX_TYPE_COMPLEX:
1065 total_size += _estimate_graph_size_recursive(temp_arena, type->meta.complex_info.base_type, visited_head);
1066 break;
1067 case INFIX_TYPE_VECTOR:
1068 total_size += _estimate_graph_size_recursive(temp_arena, type->meta.vector_info.element_type, visited_head);
1069 break;
1070 default:
1071 break;
1072 }
1073
1074 return total_size;
1075}
1076
1085 if (!temp_arena || !type)
1086 return 0;
1087
1088 estimate_visited_node_t * visited_head = NULL;
1089 return _estimate_graph_size_recursive(temp_arena, type, &visited_head);
1090}
1091
1092// Public API: Introspection Functions
1093
1101 if (type == nullptr)
1102 return nullptr;
1103 return type->name;
1104}
1105
1114
1121
1128
1140
1150 return nullptr;
1151 return &type->meta.aggregate_info.members[index];
1152}
1153
1161c23_nodiscard const char * infix_type_get_arg_name(const infix_type * func_type, size_t index) {
1162 if (!func_type || func_type->category != INFIX_TYPE_REVERSE_TRAMPOLINE ||
1163 index >= func_type->meta.func_ptr_info.num_args)
1164 return nullptr;
1165 return func_type->meta.func_ptr_info.args[index].name;
1166}
1167
1174c23_nodiscard const infix_type * infix_type_get_arg_type(const infix_type * func_type, size_t index) {
1175 if (!func_type || func_type->category != INFIX_TYPE_REVERSE_TRAMPOLINE ||
1176 index >= func_type->meta.func_ptr_info.num_args)
1177 return nullptr;
1178 return func_type->meta.func_ptr_info.args[index].type;
1179}
1180
1187 return trampoline ? trampoline->num_args : 0;
1188}
1189
1196 return trampoline ? trampoline->num_fixed_args : 0;
1197}
1198
1205 return trampoline ? trampoline->return_type : nullptr;
1206}
1207
1214c23_nodiscard const infix_type * infix_forward_get_arg_type(const infix_forward_t * trampoline, size_t index) {
1215 if (!trampoline || index >= trampoline->num_args)
1216 return nullptr;
1217 return trampoline->arg_types[index];
1218}
1219
1226 return trampoline ? trampoline->num_args : 0;
1227}
1228
1235 return trampoline ? trampoline->num_fixed_args : 0;
1236}
1237
1244 return trampoline ? trampoline->return_type : nullptr;
1245}
1246
1253c23_nodiscard const infix_type * infix_reverse_get_arg_type(const infix_reverse_t * trampoline, size_t index) {
1254 if (!trampoline || index >= trampoline->num_args)
1255 return nullptr;
1256 return trampoline->arg_types[index];
1257}
infix_arena_t * arena
Definition 005_layouts.c:68
infix_status status
Definition 103_unions.c:66
infix_struct_member * members
Definition 103_unions.c:60
#define c23_nodiscard
A compatibility macro for the C23 [[nodiscard]] attribute.
Definition compat_c23.h:113
@ INFIX_CODE_INVALID_MEMBER_TYPE
Definition infix.h:1347
@ INFIX_CODE_INTEGER_OVERFLOW
Definition infix.h:1339
@ INFIX_CODE_UNKNOWN
Definition infix.h:1327
@ INFIX_CODE_OUT_OF_MEMORY
Definition infix.h:1330
@ INFIX_CATEGORY_ALLOCATION
Definition infix.h:1316
@ INFIX_CATEGORY_GENERAL
Definition infix.h:1315
@ INFIX_CATEGORY_PARSER
Definition infix.h:1317
struct infix_type_t::@0::@1 pointer_info
Metadata for INFIX_TYPE_POINTER.
union infix_type_t::@0 meta
A union containing metadata specific to the type's category.
struct infix_type_t::@0::@7 vector_info
Metadata for INFIX_TYPE_VECTOR.
infix_type * type
Definition infix.h:289
struct infix_type_t::@0::@4 func_ptr_info
Metadata for INFIX_TYPE_REVERSE_TRAMPOLINE.
size_t num_elements
Definition infix.h:238
infix_arena_t * arena
Definition infix.h:217
size_t size
Definition infix.h:214
size_t alignment
Definition infix.h:215
infix_struct_member * members
Definition infix.h:231
struct infix_type_t::@0::@6 complex_info
Metadata for INFIX_TYPE_COMPLEX.
const char * name
Definition infix.h:212
infix_function_argument * args
Definition infix.h:244
infix_aggregate_category_t aggregate_category
Definition infix.h:268
infix_status
Enumerates the possible status codes returned by infix API functions.
Definition infix.h:389
const char * name
Definition infix.h:288
const char * name
Definition infix.h:278
infix_type_category category
Definition infix.h:213
struct infix_type_t::@0::@2 aggregate_info
Metadata for INFIX_TYPE_STRUCT and INFIX_TYPE_UNION.
struct infix_type_t::@0::@3 array_info
Metadata for INFIX_TYPE_ARRAY.
struct infix_type_t * pointee_type
Definition infix.h:226
infix_type * type
Definition infix.h:279
struct infix_type_t * element_type
Definition infix.h:237
struct infix_type_t * return_type
Definition infix.h:243
size_t offset
Definition infix.h:280
struct infix_type_t::@0::@5 enum_info
Metadata for INFIX_TYPE_ENUM.
struct infix_type_t * base_type
Definition infix.h:256
size_t num_members
Definition infix.h:232
struct infix_type_t * underlying_type
Definition infix.h:251
struct infix_type_t::@0::@8 named_reference
Metadata for INFIX_TYPE_NAMED_REFERENCE.
infix_primitive_type_id primitive_id
Metadata for INFIX_TYPE_PRIMITIVE.
Definition infix.h:222
size_t num_args
Definition infix.h:245
bool is_arena_allocated
Definition infix.h:216
@ INFIX_ERROR_ALLOCATION_FAILED
Definition infix.h:391
@ INFIX_SUCCESS
Definition infix.h:390
@ INFIX_ERROR_INVALID_ARGUMENT
Definition infix.h:392
c23_nodiscard size_t infix_forward_get_num_args(const infix_forward_t *trampoline)
Gets the total number of arguments for a forward trampoline.
Definition types.c:1186
void infix_arena_destroy(infix_arena_t *)
Destroys an arena and frees all memory allocated from it.
Definition arena.c:90
#define infix_memcpy
A macro that can be defined to override the default memcpy function.
Definition infix.h:335
c23_nodiscard void * infix_arena_calloc(infix_arena_t *, size_t, size_t, size_t)
Allocates and zero-initializes a block of memory from an arena.
Definition arena.c:198
c23_nodiscard void * infix_arena_alloc(infix_arena_t *, size_t, size_t)
Allocates a block of memory from an arena.
Definition arena.c:126
c23_nodiscard infix_arena_t * infix_arena_create(size_t)
Creates a new memory arena.
Definition arena.c:55
c23_nodiscard infix_status infix_type_create_packed_struct(infix_arena_t *arena, infix_type **out_type, size_t total_size, size_t alignment, infix_struct_member *members, size_t num_members)
Creates a new packed struct type with a user-specified layout.
Definition types.c:572
struct infix_type_t infix_type
A semi-opaque object describing a C type's memory layout and calling convention. See infix_type_t for...
Definition infix.h:133
c23_nodiscard size_t infix_type_get_size(const infix_type *type)
Gets the size of a type in bytes.
Definition types.c:1120
c23_nodiscard const infix_type * infix_type_get_arg_type(const infix_type *func_type, size_t index)
Gets the type of a specific argument from a function type.
Definition types.c:1174
c23_nodiscard infix_type * infix_type_create_void(void)
Creates a static descriptor for the void type.
Definition types.c:193
c23_nodiscard size_t infix_type_get_alignment(const infix_type *type)
Gets the alignment requirement of a type in bytes.
Definition types.c:1127
c23_nodiscard size_t infix_forward_get_num_fixed_args(const infix_forward_t *trampoline)
Gets the number of fixed (non-variadic) arguments for a forward trampoline.
Definition types.c:1195
c23_nodiscard const char * infix_type_get_name(const infix_type *type)
Gets the semantic alias of a type, if one exists.
Definition types.c:1100
c23_nodiscard const infix_type * infix_forward_get_return_type(const infix_forward_t *trampoline)
Gets the return type for a forward trampoline.
Definition types.c:1204
infix_primitive_type_id
Enumerates the supported primitive C types.
Definition infix.h:179
c23_nodiscard const infix_type * infix_forward_get_arg_type(const infix_forward_t *trampoline, size_t index)
Gets the type of a specific argument for a forward trampoline.
Definition types.c:1214
c23_nodiscard infix_status infix_type_create_union(infix_arena_t *arena, infix_type **out_type, infix_struct_member *members, size_t num_members)
Creates a new union type from an array of members.
Definition types.c:442
c23_nodiscard infix_status infix_type_create_enum(infix_arena_t *arena, infix_type **out_type, infix_type *underlying_type)
Creates a new enum type with a specified underlying integer type.
Definition types.c:337
c23_nodiscard infix_status infix_type_create_vector(infix_arena_t *arena, infix_type **out_type, infix_type *element_type, size_t num_elements)
Creates a new SIMD vector type.
Definition types.c:403
c23_nodiscard const infix_type * infix_reverse_get_return_type(const infix_reverse_t *trampoline)
Gets the return type for a reverse trampoline.
Definition types.c:1243
struct infix_struct_member_t infix_struct_member
A semi-opaque object describing a member of a C struct or union. See infix_struct_member_t for detail...
Definition infix.h:136
c23_nodiscard infix_type * infix_type_create_pointer(void)
Creates a static descriptor for a generic pointer (void*).
Definition types.c:187
c23_nodiscard infix_status infix_type_create_complex(infix_arena_t *arena, infix_type **out_type, infix_type *base_type)
Creates a new _Complex number type.
Definition types.c:372
c23_nodiscard size_t infix_reverse_get_num_args(const infix_reverse_t *trampoline)
Gets the total number of arguments for a reverse trampoline.
Definition types.c:1225
c23_nodiscard size_t infix_type_get_member_count(const infix_type *type)
Gets the number of members in a struct or union type.
Definition types.c:1135
struct infix_function_argument_t infix_function_argument
A semi-opaque object describing an argument to a C function. See infix_function_argument_t for detail...
Definition infix.h:139
c23_nodiscard const char * infix_type_get_arg_name(const infix_type *func_type, size_t index)
Gets the name of a specific argument from a function type.
Definition types.c:1161
infix_type_category
Enumerates the fundamental categories of types that infix can represent.
Definition infix.h:162
c23_nodiscard infix_type_category infix_type_get_category(const infix_type *type)
Gets the fundamental category of a type.
Definition types.c:1111
c23_nodiscard infix_status infix_type_create_array(infix_arena_t *arena, infix_type **out_type, infix_type *element_type, size_t num_elements)
Creates a new fixed-size array type.
Definition types.c:299
c23_nodiscard infix_status infix_type_create_pointer_to(infix_arena_t *arena, infix_type **out_type, infix_type *pointee_type)
Creates a new pointer type that points to a specific type.
Definition types.c:268
infix_aggregate_category_t
Specifies whether a named type reference refers to a struct or a union.
Definition infix.h:200
c23_nodiscard infix_status infix_type_create_struct(infix_arena_t *arena, infix_type **out_type, infix_struct_member *members, size_t num_members)
Creates a new struct type from an array of members, calculating layout automatically.
Definition types.c:490
c23_nodiscard infix_status infix_type_create_named_reference(infix_arena_t *arena, infix_type **out_type, const char *name, infix_aggregate_category_t agg_cat)
Creates a placeholder for a named type that will be resolved later by a type registry.
Definition types.c:620
c23_nodiscard const infix_type * infix_reverse_get_arg_type(const infix_reverse_t *trampoline, size_t index)
Gets the type of a specific argument for a reverse trampoline.
Definition types.c:1253
c23_nodiscard size_t infix_reverse_get_num_fixed_args(const infix_reverse_t *trampoline)
Gets the number of fixed (non-variadic) arguments for a reverse trampoline.
Definition types.c:1234
c23_nodiscard infix_type * infix_type_create_primitive(infix_primitive_type_id id)
Creates a static descriptor for a primitive C type.
Definition types.c:138
infix_struct_member infix_type_create_member(const char *name, infix_type *type, size_t offset)
A factory function to create an infix_struct_member.
Definition types.c:202
c23_nodiscard const infix_struct_member * infix_type_get_member(const infix_type *type, size_t index)
Gets a specific member from a struct or union type.
Definition types.c:1147
@ INFIX_PRIMITIVE_UINT16
Definition infix.h:183
@ INFIX_PRIMITIVE_UINT32
Definition infix.h:185
@ INFIX_PRIMITIVE_LONG_DOUBLE
Definition infix.h:193
@ INFIX_PRIMITIVE_FLOAT
Definition infix.h:191
@ INFIX_PRIMITIVE_DOUBLE
Definition infix.h:192
@ INFIX_PRIMITIVE_SINT16
Definition infix.h:184
@ INFIX_PRIMITIVE_SINT64
Definition infix.h:188
@ INFIX_PRIMITIVE_SINT32
Definition infix.h:186
@ INFIX_PRIMITIVE_UINT8
Definition infix.h:181
@ INFIX_PRIMITIVE_UINT128
Definition infix.h:189
@ INFIX_PRIMITIVE_BOOL
Definition infix.h:180
@ INFIX_PRIMITIVE_UINT64
Definition infix.h:187
@ INFIX_PRIMITIVE_SINT128
Definition infix.h:190
@ INFIX_PRIMITIVE_SINT8
Definition infix.h:182
@ INFIX_TYPE_UNION
Definition infix.h:166
@ INFIX_TYPE_PRIMITIVE
Definition infix.h:163
@ INFIX_TYPE_COMPLEX
Definition infix.h:170
@ INFIX_TYPE_ARRAY
Definition infix.h:167
@ INFIX_TYPE_VECTOR
Definition infix.h:171
@ INFIX_TYPE_VOID
Definition infix.h:173
@ INFIX_TYPE_POINTER
Definition infix.h:164
@ INFIX_TYPE_NAMED_REFERENCE
Definition infix.h:172
@ INFIX_TYPE_REVERSE_TRAMPOLINE
Definition infix.h:168
@ INFIX_TYPE_ENUM
Definition infix.h:169
@ INFIX_TYPE_STRUCT
Definition infix.h:165
Internal data structures, function prototypes, and constants.
void _infix_set_error(infix_error_category_t category, infix_error_code_t code, size_t position)
Sets the thread-local error state with detailed information.
Definition error.c:155
static size_t _infix_align_up(size_t value, size_t alignment)
Aligns a value up to the next multiple of a power-of-two alignment.
Definition infix_internals.h:703
static bool is_double(const infix_type *type)
A fast inline check to determine if an infix_type is a double.
Definition infix_internals.h:719
void _infix_clear_error(void)
Clears the thread-local error state.
Definition error.c:257
static bool is_float(const infix_type *type)
A fast inline check to determine if an infix_type is a float.
Definition infix_internals.h:711
Definition types.c:981
struct estimate_visited_node_t * next
Definition types.c:983
const infix_type * type
Definition types.c:982
Internal definition of a memory arena.
Definition infix_internals.h:146
Internal definition of a forward trampoline handle.
Definition infix_internals.h:94
size_t num_args
Definition infix_internals.h:101
size_t num_fixed_args
Definition infix_internals.h:102
infix_type ** arg_types
Definition infix_internals.h:100
infix_type * return_type
Definition infix_internals.h:99
Describes a single argument to a C function.
Definition infix.h:287
Internal definition of a reverse trampoline (callback/closure) handle.
Definition infix_internals.h:121
infix_type * return_type
Definition infix_internals.h:125
size_t num_args
Definition infix_internals.h:127
size_t num_fixed_args
Definition infix_internals.h:128
infix_type ** arg_types
Definition infix_internals.h:126
Describes a single member of a C struct or union.
Definition infix.h:277
A semi-opaque structure that describes a C type.
Definition infix.h:211
Definition types.c:800
infix_type * dest
Definition types.c:802
struct memo_node_t * next
Definition types.c:803
const infix_type * src
Definition types.c:801
Definition types.c:667
struct recalc_visited_node_t * next
Definition types.c:669
infix_type * type
Definition types.c:668
static size_t _estimate_graph_size_recursive(infix_arena_t *temp_arena, const infix_type *type, estimate_visited_node_t **visited_head)
Definition types.c:998
static infix_type _infix_type_sint128
Definition types.c:116
void _infix_type_recalculate_layout(infix_type *type)
Recalculates the layout of a fully resolved type graph.
Definition types.c:780
static infix_type _infix_type_double
Definition types.c:121
static infix_type _infix_type_uint32
Definition types.c:105
static infix_type _infix_type_bool
Definition types.c:95
static infix_type _infix_type_float
Definition types.c:119
infix_type * _copy_type_graph_to_arena(infix_arena_t *dest_arena, const infix_type *src_type)
Performs a deep copy of a type graph into a destination arena.
Definition types.c:971
static infix_type _infix_type_sint64
Definition types.c:111
#define INFIX_TYPE_INIT(id, T)
Definition types.c:60
size_t _infix_estimate_graph_size(infix_arena_t *temp_arena, const infix_type *type)
Estimates the total memory required to deep-copy a complete type graph.
Definition types.c:1084
static infix_type _infix_type_sint16
Definition types.c:103
static infix_type _infix_type_uint16
Definition types.c:101
static infix_type _infix_type_long_double
Definition types.c:127
static infix_type _infix_type_pointer
Definition types.c:86
static infix_type _infix_type_uint128
Definition types.c:114
static infix_type _infix_type_void
Definition types.c:74
static infix_type _infix_type_sint32
Definition types.c:107
static infix_type * _copy_type_graph_to_arena_recursive(infix_arena_t *dest_arena, const infix_type *src_type, memo_node_t **memo_head)
Definition types.c:821
static infix_type _infix_type_uint64
Definition types.c:109
static infix_status _create_aggregate_setup(infix_arena_t *arena, infix_type **out_type, infix_struct_member **out_arena_members, infix_struct_member *members, size_t num_members)
Definition types.c:223
static void _infix_type_recalculate_layout_recursive(infix_arena_t *temp_arena, infix_type *type, recalc_visited_node_t **visited_head)
Definition types.c:694
static infix_type _infix_type_uint8
Definition types.c:97
static infix_type _infix_type_sint8
Definition types.c:99
A header for conditionally compiled debugging utilities.