infix
A JIT-Powered FFI Library for C
Loading...
Searching...
No Matches
type_registry.c
Go to the documentation of this file.
1
39#include <ctype.h>
40#include <string.h>
49#define INITIAL_REGISTRY_BUCKETS 61
64// Hash Table Implementation
72static uint64_t _registry_hash_string(const char * str) {
73 uint64_t hash = 5381;
74 int c;
75 while ((c = *str++))
76 hash = ((hash << 5) + hash) + c; // hash * 33 + c
77 return hash;
78}
87 if (!registry || !name)
88 return nullptr;
89 size_t index = _registry_hash_string(name) % registry->num_buckets;
90 // Traverse the linked list (chain) at the computed bucket index.
91 for (_infix_registry_entry_t * current = registry->buckets[index]; current; current = current->next)
92 if (strcmp(current->name, name) == 0)
93 return current;
94 return nullptr;
95}
96
104 // Roughly double the size. Keep it odd to slightly help with distribution.
105 size_t new_num_buckets = registry->num_buckets * 2 + 1;
106
107 // Allocate new buckets from the arena.
108 // Note: The old bucket array remains allocated in the arena (leak within arena),
109 // but this is an acceptable trade-off for the simplicity of arena management
110 // and the fact that registries usually grow during initialization and persist.
112 registry->arena, new_num_buckets, sizeof(_infix_registry_entry_t *), _Alignof(_infix_registry_entry_t *));
113
114 if (!new_buckets) {
115 // If allocation fails, we simply return and continue using the existing buckets.
116 // Performance will degrade, but correctness is preserved.
117 return;
118 }
119
120 // Rehash all existing entries.
121 for (size_t i = 0; i < registry->num_buckets; ++i) {
123 while (entry) {
124 _infix_registry_entry_t * next_entry = entry->next; // Save next pointer
125
126 // Calculate new index
127 uint64_t hash = _registry_hash_string(entry->name);
128 size_t new_index = hash % new_num_buckets;
129
130 // Insert into new bucket (prepend)
131 entry->next = new_buckets[new_index];
132 new_buckets[new_index] = entry;
133
134 entry = next_entry;
135 }
136 }
137
138 // Update the registry to use the new table.
139 registry->buckets = new_buckets;
140 registry->num_buckets = new_num_buckets;
141}
142
157 // Check load factor. If num_items > num_buckets * 0.75, resize.
158 // Equivalent integer math: num_items * 4 > num_buckets * 3
159 if (registry->num_items * 4 > registry->num_buckets * 3)
161
162 size_t index = _registry_hash_string(name) % registry->num_buckets;
163 _infix_registry_entry_t * new_entry =
165 if (!new_entry) {
167 return nullptr;
168 }
169 size_t name_len = strlen(name) + 1;
170 char * name_copy = infix_arena_alloc(registry->arena, name_len, 1);
171 if (!name_copy) {
173 return nullptr;
174 }
175 infix_memcpy((void *)name_copy, name, name_len);
176 new_entry->name = name_copy;
177 new_entry->type = nullptr;
178 new_entry->is_forward_declaration = false;
179 // Prepend to the linked list in the bucket.
180 new_entry->next = registry->buckets[index];
181 registry->buckets[index] = new_entry;
183 return new_entry;
184}
185// Public API: Registry Lifecycle
265 if (!src)
266 return nullptr;
267
269 if (!dest)
270 return nullptr;
271
272 // Iterate over all buckets in the source registry
273 for (size_t i = 0; i < src->num_buckets; ++i) {
274 _infix_registry_entry_t * entry = src->buckets[i];
275 while (entry) {
276 // Create a new entry in the destination registry.
277 // _registry_insert handles allocating the entry and copying the name string.
278 _infix_registry_entry_t * new_entry = _registry_insert(dest, entry->name);
279 if (!new_entry) {
281 return nullptr;
282 }
283
284 // Copy flags
286
287 // Deep copy the type graph into the new registry's arena
288 if (entry->type) {
289 new_entry->type = _copy_type_graph_to_arena(dest->arena, entry->type);
290 if (!new_entry->type) {
292 return nullptr;
293 }
294 }
295
296 entry = entry->next;
297 }
298 }
299 return dest;
300}
311 if (!registry)
312 return;
313 // Only destroy the arena if it was created internally by `infix_registry_create`.
316 // Always free the registry struct itself.
318}
319// Internal Type Graph Resolution
339 infix_type ** type_ptr,
341 resolve_memo_node_t ** memo_head) {
342 if (!type_ptr || !*type_ptr || !(*type_ptr)->is_arena_allocated)
343 return INFIX_SUCCESS;
344 infix_type * type = *type_ptr;
345 // Cycle detection: If we've seen this node before, we're in a cycle.
346 // Return success to break the loop.
347 for (resolve_memo_node_t * node = *memo_head; node != nullptr; node = node->next)
348 if (node->src == type)
349 return INFIX_SUCCESS;
350 // Allocate the memoization node from the stable temporary arena.
351 resolve_memo_node_t * memo_node =
352 infix_arena_alloc(temp_arena, sizeof(resolve_memo_node_t), _Alignof(resolve_memo_node_t));
353 if (!memo_node) {
356 }
357 memo_node->src = type;
358 memo_node->next = *memo_head;
359 *memo_head = memo_node;
361 if (!registry) {
364 }
365 const char * name = type->meta.named_reference.name;
367 if (!entry || !entry->type) {
370 }
371 *type_ptr = entry->type;
372 return INFIX_SUCCESS;
373 }
375 switch (type->category) {
378 temp_arena, &type->meta.pointer_info.pointee_type, registry, memo_head);
379 break;
380 case INFIX_TYPE_ARRAY:
381 status =
383 break;
385 case INFIX_TYPE_UNION:
386 for (size_t i = 0; i < type->meta.aggregate_info.num_members; ++i) {
388 temp_arena, &type->meta.aggregate_info.members[i].type, registry, memo_head);
389 if (status != INFIX_SUCCESS)
390 break;
391 }
392 break;
395 temp_arena, &type->meta.func_ptr_info.return_type, registry, memo_head);
396 if (status != INFIX_SUCCESS)
397 break;
398 for (size_t i = 0; i < type->meta.func_ptr_info.num_args; ++i) {
400 temp_arena, &type->meta.func_ptr_info.args[i].type, registry, memo_head);
401 if (status != INFIX_SUCCESS)
402 break;
403 }
404 break;
405 case INFIX_TYPE_ENUM:
407 temp_arena, &type->meta.enum_info.underlying_type, registry, memo_head);
408 break;
410 status =
412 break;
415 temp_arena, &type->meta.vector_info.element_type, registry, memo_head);
416 break;
417 default:
418 break;
419 }
420 return status;
421}
430 // Create a temporary arena solely for the visited list's lifetime.
431 infix_arena_t * temp_arena = infix_arena_create(1024);
432 if (!temp_arena) {
435 }
436 resolve_memo_node_t * memo_head = nullptr;
437 infix_status status = _resolve_type_graph_inplace_recursive(temp_arena, type_ptr, registry, &memo_head);
438 infix_arena_destroy(temp_arena);
439 return status;
440}
441// Public API: Type Registration
450typedef struct {
451 const char * p;
452 const char * start;
460 while (1) {
461 while (isspace((unsigned char)*state->p))
462 state->p++;
463 if (*state->p == '#') // Skip comments
464 while (*state->p != '\n' && *state->p != '\0')
465 state->p++;
466 else
467 break;
468 }
469}
478static char * _registry_parser_parse_name(_registry_parser_state_t * state, char * buffer, size_t buf_size) {
480 const char * name_start = state->p;
481 while (isalnum((unsigned char)*state->p) || *state->p == '_' || *state->p == ':') {
482 if (*state->p == ':' && state->p[1] != ':')
483 break; // Handle single colon as non-identifier char.
484 if (*state->p == ':')
485 state->p++; // Skip the first ':' of '::'
486 state->p++;
487 }
488 size_t len = state->p - name_start;
489 if (len == 0 || len >= buf_size)
490 return nullptr;
491 infix_memcpy(buffer, name_start, len);
492 buffer[len] = '\0';
493 return buffer;
494}
524 if (!registry || !definitions) {
527 }
528 _registry_parser_state_t state = {.p = definitions, .start = definitions};
530 // A temporary structure to hold information about each definition found in Pass 1.
531 struct def_info {
533 const char * def_body_start;
534 size_t def_body_len;
535 };
536 size_t defs_capacity = 64; // Start with an initial capacity.
537 struct def_info * defs_found = infix_malloc(sizeof(struct def_info) * defs_capacity);
538 if (!defs_found) {
541 }
542 size_t num_defs_found = 0;
543 infix_status final_status = INFIX_SUCCESS;
544
545 // Pass 1: Scan & Index all names and their definition bodies.
546 while (*state.p != '\0') {
548 if (*state.p == '\0')
549 break;
550 if (*state.p != '@') {
552 final_status = INFIX_ERROR_INVALID_ARGUMENT;
553 goto cleanup;
554 }
555 state.p++;
556 char name_buffer[256];
557 if (!_registry_parser_parse_name(&state, name_buffer, sizeof(name_buffer))) {
559 final_status = INFIX_ERROR_INVALID_ARGUMENT;
560 goto cleanup;
561 }
562 _infix_registry_entry_t * entry = _registry_lookup(registry, name_buffer);
564 if (*state.p == '=') { // This is a full definition.
565 state.p++;
567 // It's an error to redefine a type that wasn't a forward declaration.
568 if (entry && !entry->is_forward_declaration) {
570 final_status = INFIX_ERROR_INVALID_ARGUMENT;
571 goto cleanup;
572 }
573 if (!entry) { // If it doesn't exist, create it.
574 entry = _registry_insert(registry, name_buffer);
575 if (!entry) {
576 final_status = INFIX_ERROR_ALLOCATION_FAILED;
577 goto cleanup;
578 }
579 }
580 if (num_defs_found >= defs_capacity) {
581 size_t new_capacity = defs_capacity * 2;
582 struct def_info * new_defs = infix_realloc(defs_found, sizeof(struct def_info) * new_capacity);
583 if (!new_defs) {
585 final_status = INFIX_ERROR_ALLOCATION_FAILED;
586 goto cleanup;
587 }
588 defs_found = new_defs;
589 defs_capacity = new_capacity;
590 }
591 // Find the end of the type definition body (the next top-level ';').
592 defs_found[num_defs_found].entry = entry;
593 defs_found[num_defs_found].def_body_start = state.p;
594 int nest_level = 0;
595 const char * body_end = state.p;
596 while (*body_end != '\0' &&
597 !(*body_end == ';' &&
598 nest_level == 0)) { // Explicitly check for and skip over the '->' token as a single unit.
599 if (*body_end == '-' && body_end[1] == '>') {
600 body_end += 2; // Advance the pointer past the entire token.
601 continue; // Continue to the next character in the loop.
602 }
603 if (*body_end == '{' || *body_end == '<' || *body_end == '(' || *body_end == '[')
604 nest_level++;
605 if (*body_end == '}' || *body_end == '>' || *body_end == ')' || *body_end == ']')
606 nest_level--;
607 body_end++;
608 }
609 defs_found[num_defs_found].def_body_len = body_end - state.p;
610 state.p = body_end;
611 num_defs_found++;
612 }
613 else if (*state.p == ';') { // This is a forward declaration.
614 if (entry) {
615 // If the type is already fully defined, re-declaring it as a forward decl is an error.
616 if (!entry->is_forward_declaration) {
618 final_status = INFIX_ERROR_INVALID_ARGUMENT;
619 goto cleanup;
620 }
621 // If it's already a forward declaration, this is a no-op.
622 }
623 else {
624 entry = _registry_insert(registry, name_buffer);
625 if (!entry) {
626 final_status = INFIX_ERROR_ALLOCATION_FAILED;
627 goto cleanup;
628 }
629 }
630 // Ensure a placeholder type exists so other types can reference it immediately.
631 // We create an opaque struct (size 0) as the placeholder and mark it incomplete.
632 if (!entry->type) {
633 entry->type = infix_arena_calloc(registry->arena, 1, sizeof(infix_type), _Alignof(infix_type));
634 if (!entry->type) {
635 final_status = INFIX_ERROR_ALLOCATION_FAILED;
636 goto cleanup;
637 }
638 entry->type->is_arena_allocated = true;
639 entry->type->is_incomplete = true; // Mark as incomplete
640 entry->type->arena = registry->arena;
642 entry->type->size = 0;
643 entry->type->alignment = 1; // Minimal alignment to pass basic validation
644 entry->type->name = entry->name;
645 }
646 entry->is_forward_declaration = true;
647 }
648 else {
650 final_status = INFIX_ERROR_INVALID_ARGUMENT;
651 goto cleanup;
652 }
653 if (*state.p == ';')
654 state.p++;
655 }
656 // Pass 2: Parse the bodies of all found definitions into the registry.
657 for (size_t i = 0; i < num_defs_found; ++i) {
658 _infix_registry_entry_t * entry = defs_found[i].entry;
659 // Make a temporary, null-terminated copy of the definition body substring.
660 char * body_copy = infix_malloc(defs_found[i].def_body_len + 1);
661 if (!body_copy) {
663 final_status = INFIX_ERROR_ALLOCATION_FAILED;
664 goto cleanup;
665 }
666 infix_memcpy(body_copy, defs_found[i].def_body_start, defs_found[i].def_body_len);
667 body_copy[defs_found[i].def_body_len] = '\0';
668 // "Parse" step: parse into a temporary arena.
669 infix_type * raw_type = nullptr;
670 infix_arena_t * parser_arena = nullptr;
671 infix_status status = _infix_parse_type_internal(&raw_type, &parser_arena, body_copy);
672 infix_free(body_copy);
673 if (status != INFIX_SUCCESS) {
674 // Adjust the error position to be relative to the full definition string.
676 _infix_set_error(err.category, err.code, (defs_found[i].def_body_start - definitions) + err.position);
677 final_status = INFIX_ERROR_INVALID_ARGUMENT;
678 infix_arena_destroy(parser_arena);
679 goto cleanup;
680 }
681 const infix_type * type_to_alias = raw_type;
682 // If the RHS is another named type (e.g., @MyAlias = @ExistingType),
683 // we need to resolve it first to get the actual type we're aliasing.
684 if (raw_type->category == INFIX_TYPE_NAMED_REFERENCE) {
686 if (existing_entry && existing_entry->type)
687 type_to_alias = existing_entry->type;
688 else {
689 size_t relative_pos = raw_type->source_offset;
692 (size_t)(defs_found[i].def_body_start - definitions) + relative_pos);
693 final_status = INFIX_ERROR_INVALID_ARGUMENT;
694 infix_arena_destroy(parser_arena);
695 goto cleanup;
696 }
697 }
698 // Prepare the new definition.
699 infix_type * new_def = nullptr;
700 if (!type_to_alias->is_arena_allocated) {
701 // This is a static type (e.g., primitive). We MUST create a mutable
702 // copy in the registry's arena before we can attach a name to it.
703 // This prevents corrupting the global static singletons.
704 new_def = infix_arena_alloc(registry->arena, sizeof(infix_type), _Alignof(infix_type));
705 if (new_def) {
706 *new_def = *type_to_alias;
707 new_def->is_arena_allocated = true;
708 new_def->arena = registry->arena;
709 }
710 }
711 else // Dynamic type: deep copy.
712 new_def = _copy_type_graph_to_arena(registry->arena, type_to_alias);
713
714 infix_arena_destroy(parser_arena); // The temporary raw_type is no longer needed.
715
716 if (!new_def) {
718 final_status = INFIX_ERROR_ALLOCATION_FAILED;
719 goto cleanup;
720 }
721
722 // Update the entry. If a placeholder already exists (from forward decl), we MUST update it in-place
723 // to preserve pointers from other types that have already resolved to it.
724 if (entry->type) {
725 // Struct-copy the new definition into the existing placeholder memory.
726 *entry->type = *new_def;
727 // Restore the self-reference if the copy logic pointed the arena elsewhere.
728 entry->type->arena = registry->arena;
729 // The new definition is complete, so ensure the flag is cleared.
730 entry->type->is_incomplete = false;
731 }
732 else {
733 entry->type = new_def;
734 entry->type->is_incomplete = false;
735 }
736
737 // Ensure the name is attached and the flag is cleared.
738 entry->type->name = entry->name;
739 entry->is_forward_declaration = false;
740 }
741 // Pass 3: Resolve and layout all the newly defined types.
742 for (size_t i = 0; i < num_defs_found; ++i) {
743 _infix_registry_entry_t * entry = defs_found[i].entry;
744 if (entry->type) {
745 // "Resolve" and "Layout" steps.
747 // The error was set inside resolve (relative to body).
748 // We need to re-base it to the full definitions string.
750 size_t body_offset = defs_found[i].def_body_start - definitions;
751 _infix_set_error(err.category, err.code, body_offset + err.position);
752 final_status = INFIX_ERROR_INVALID_ARGUMENT;
753 goto cleanup;
754 }
756 }
757 }
758cleanup:
759 infix_free(defs_found);
760 return final_status;
761}
762// Registry Introspection API Implementation
783 // Return an iterator positioned before the first element.
784 // The first call to next() will advance it to the first valid element.
786 it.registry = registry;
787 it._bucket_index = 0;
788 it._current_entry = nullptr;
789 return it;
790}
791
800 if (!iter || !iter->registry)
801 return false;
802
803 // Cast the opaque void* back to the internal entry type
805
806 // If we have a current entry, start from the next one in the chain.
807 if (entry)
808 entry = entry->next;
809 // Otherwise, if we are starting (or moved buckets), begin with the head of the current bucket.
810 else if (iter->_bucket_index < iter->registry->num_buckets)
811 entry = iter->registry->buckets[iter->_bucket_index];
812
813 while (true) {
814 // Traverse the current chain looking for a valid entry.
815 while (entry) {
816 if (entry->type && !entry->is_forward_declaration) {
817 // Found one. Update the iterator and return successfully.
818 iter->_current_entry = (void *)entry;
819 return true;
820 }
821 entry = entry->next;
822 }
823 // If we're here, the current chain is exhausted. Move to the next bucket.
824 iter->_bucket_index++;
825 // If there are no more buckets, we're done.
826 if (iter->_bucket_index >= iter->registry->num_buckets) {
827 iter->_current_entry = nullptr;
828 return false;
829 }
830 // Start the search from the head of the new bucket.
831 entry = iter->registry->buckets[iter->_bucket_index];
832 }
833}
843 if (!iter || !iter->_current_entry)
844 return nullptr;
846 return entry->name;
847}
857 if (!iter || !iter->_current_entry)
858 return nullptr;
860 return entry->type;
861}
873 if (!registry || !name)
874 return false;
876 // It's defined if an entry exists, it has a type, and it's not a lingering forward declaration.
877 return entry != nullptr && entry->type != nullptr && !entry->is_forward_declaration;
878}
889 const char * name) {
890 if (!registry || !name)
891 return nullptr;
893 if (entry && entry->type && !entry->is_forward_declaration)
894 return entry->type;
895 return nullptr;
896}
infix_arena_t * arena
Definition 005_layouts.c:62
const char * definitions
Definition 008_registry_introspection.c:36
infix_registry_t * registry
Definition 008_registry_introspection.c:33
infix_status status
Definition 103_unions.c:61
#define c23_nodiscard
Internal alias for the public INFIX_NODISCARD macro.
Definition compat_c23.h:91
#define INFIX_TLS
Definition error.c:68
INFIX_API infix_error_details_t infix_get_last_error(void)
Retrieves detailed information about the last error that occurred on the current thread.
Definition error.c:279
@ INFIX_CODE_UNRESOLVED_NAMED_TYPE
Definition infix.h:1368
@ INFIX_CODE_UNEXPECTED_TOKEN
Definition infix.h:1356
@ INFIX_CODE_NULL_POINTER
Definition infix.h:1346
@ INFIX_CODE_OUT_OF_MEMORY
Definition infix.h:1350
@ INFIX_CATEGORY_ALLOCATION
Definition infix.h:1335
@ INFIX_CATEGORY_GENERAL
Definition infix.h:1334
@ INFIX_CATEGORY_PARSER
Definition infix.h:1336
size_t source_offset
Definition infix.h:281
void * _current_entry
Definition infix.h:519
struct infix_type_t::@0::@1 pointer_info
Metadata for INFIX_TYPE_POINTER.
size_t position
Definition infix.h:1384
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_error_category_t category
Definition infix.h:1382
const infix_registry_t * registry
Definition infix.h:517
bool is_incomplete
Definition infix.h:279
infix_type * type
Definition infix.h:347
struct infix_type_t::@0::@4 func_ptr_info
Metadata for INFIX_TYPE_REVERSE_TRAMPOLINE.
infix_arena_t * arena
Definition infix.h:280
size_t size
Definition infix.h:276
size_t alignment
Definition infix.h:277
infix_struct_member * members
Definition infix.h:292
struct infix_type_t::@0::@6 complex_info
Metadata for INFIX_TYPE_COMPLEX.
const char * name
Definition infix.h:274
infix_function_argument * args
Definition infix.h:305
infix_status
Enumerates the possible status codes returned by infix API functions.
Definition infix.h:433
infix_type_category category
Definition infix.h:275
size_t _bucket_index
Definition infix.h:518
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:288
infix_type * type
Definition infix.h:335
struct infix_type_t * element_type
Definition infix.h:298
struct infix_type_t * return_type
Definition infix.h:304
struct infix_type_t::@0::@5 enum_info
Metadata for INFIX_TYPE_ENUM.
struct infix_type_t * base_type
Definition infix.h:315
infix_error_code_t code
Definition infix.h:1383
size_t num_members
Definition infix.h:293
struct infix_type_t * underlying_type
Definition infix.h:311
struct infix_type_t::@0::@8 named_reference
Metadata for INFIX_TYPE_NAMED_REFERENCE.
size_t num_args
Definition infix.h:306
bool is_arena_allocated
Definition infix.h:278
@ INFIX_ERROR_ALLOCATION_FAILED
Definition infix.h:435
@ INFIX_SUCCESS
Definition infix.h:434
@ INFIX_ERROR_INVALID_ARGUMENT
Definition infix.h:436
#define infix_free
A macro that can be defined to override the default free function.
Definition infix.h:382
INFIX_API INFIX_NODISCARD void * infix_arena_alloc(infix_arena_t *, size_t, size_t)
Allocates a block of memory from an arena.
Definition arena.c:117
#define infix_memcpy
A macro that can be defined to override the default memcpy function.
Definition infix.h:386
#define infix_realloc
A macro that can be defined to override the default realloc function.
Definition infix.h:378
INFIX_API INFIX_NODISCARD infix_arena_t * infix_arena_create(size_t)
Creates a new memory arena.
Definition arena.c:52
INFIX_API INFIX_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:188
#define infix_malloc
A macro that can be defined to override the default malloc function.
Definition infix.h:370
INFIX_API void infix_arena_destroy(infix_arena_t *)
Destroys an arena and frees all memory allocated from it.
Definition arena.c:83
INFIX_API void infix_registry_destroy(infix_registry_t *registry)
Destroys a type registry and frees all associated memory.
Definition type_registry.c:310
INFIX_API c23_nodiscard infix_status infix_register_types(infix_registry_t *registry, const char *definitions)
Parses a string of type definitions and adds them to a registry.
Definition type_registry.c:522
INFIX_API c23_nodiscard infix_registry_t * infix_registry_create(void)
Creates a new, empty named type registry.
Definition type_registry.c:197
INFIX_API c23_nodiscard infix_registry_t * infix_registry_clone(const infix_registry_t *src)
Creates a deep copy of an existing registry.
Definition type_registry.c:264
INFIX_API c23_nodiscard const infix_type * infix_registry_lookup_type(const infix_registry_t *registry, const char *name)
Retrieves the canonical infix_type object for a given name from the registry.
Definition type_registry.c:888
INFIX_API c23_nodiscard infix_registry_t * infix_registry_create_in_arena(infix_arena_t *arena)
Creates a new, empty named type registry that allocates from a user-provided arena.
Definition type_registry.c:235
INFIX_API c23_nodiscard bool infix_registry_iterator_next(infix_registry_iterator_t *iter)
Advances the iterator to the next defined type in the registry.
Definition type_registry.c:799
INFIX_API c23_nodiscard infix_registry_iterator_t infix_registry_iterator_begin(const infix_registry_t *registry)
Initializes an iterator for traversing the types in a registry.
Definition type_registry.c:782
INFIX_API c23_nodiscard const infix_type * infix_registry_iterator_get_type(const infix_registry_iterator_t *iter)
Gets the infix_type object of the type at the iterator's current position.
Definition type_registry.c:856
INFIX_API c23_nodiscard bool infix_registry_is_defined(const infix_registry_t *registry, const char *name)
Checks if a type with the given name is fully defined in the registry.
Definition type_registry.c:872
INFIX_API c23_nodiscard const char * infix_registry_iterator_get_name(const infix_registry_iterator_t *iter)
Gets the name of the type at the iterator's current position.
Definition type_registry.c:842
@ INFIX_TYPE_UNION
Definition infix.h:231
@ INFIX_TYPE_COMPLEX
Definition infix.h:235
@ INFIX_TYPE_ARRAY
Definition infix.h:232
@ INFIX_TYPE_VECTOR
Definition infix.h:236
@ INFIX_TYPE_POINTER
Definition infix.h:229
@ INFIX_TYPE_NAMED_REFERENCE
Definition infix.h:237
@ INFIX_TYPE_REVERSE_TRAMPOLINE
Definition infix.h:233
@ INFIX_TYPE_ENUM
Definition infix.h:234
@ INFIX_TYPE_STRUCT
Definition infix.h:230
#define INFIX_API
Symbol visibility macro.
Definition infix.h:114
Internal data structures, function prototypes, and constants.
INFIX_INTERNAL c23_nodiscard infix_status _infix_parse_type_internal(infix_type **, infix_arena_t **, const char *)
The internal core of the signature parser.
Definition signature.c:978
INFIX_INTERNAL infix_type * _copy_type_graph_to_arena(infix_arena_t *, const infix_type *)
Performs a deep copy of a type graph into a destination arena.
Definition types.c:1141
INFIX_INTERNAL void _infix_type_recalculate_layout(infix_type *type)
Recalculates the layout of a fully resolved type graph.
Definition types.c:953
INFIX_INTERNAL void _infix_clear_error(void)
Clears the thread-local error state.
Definition error.c:266
INFIX_INTERNAL 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:173
A single entry in the registry's hash table.
Definition infix_internals.h:152
bool is_forward_declaration
Definition infix_internals.h:155
const char * name
Definition infix_internals.h:153
infix_type * type
Definition infix_internals.h:154
struct _infix_registry_entry_t * next
Definition infix_internals.h:156
Definition type_registry.c:450
const char * start
Definition type_registry.c:452
const char * p
Definition type_registry.c:451
Internal definition of a memory arena.
Definition infix_internals.h:138
Provides detailed, thread-local information about the last error that occurred.
Definition infix.h:1381
An iterator for traversing a type registry.
Definition infix.h:516
Internal definition of a named type registry.
Definition infix_internals.h:165
size_t num_items
Definition infix_internals.h:169
bool is_external_arena
Definition infix_internals.h:167
infix_arena_t * arena
Definition infix_internals.h:166
_infix_registry_entry_t ** buckets
Definition infix_internals.h:170
size_t num_buckets
Definition infix_internals.h:168
A semi-opaque structure that describes a C type.
Definition infix.h:273
Definition type_registry.c:60
struct resolve_memo_node_t * next
Definition type_registry.c:62
infix_type * src
Definition type_registry.c:61
static uint64_t _registry_hash_string(const char *str)
Definition type_registry.c:72
#define INITIAL_REGISTRY_BUCKETS
Definition type_registry.c:49
c23_nodiscard infix_status _infix_resolve_type_graph_inplace(infix_type **type_ptr, infix_registry_t *registry)
Resolves all named type references in a type graph in-place.
Definition type_registry.c:429
static void _registry_rehash(infix_registry_t *registry)
Definition type_registry.c:103
static _infix_registry_entry_t * _registry_lookup(infix_registry_t *registry, const char *name)
Definition type_registry.c:86
static _infix_registry_entry_t * _registry_insert(infix_registry_t *registry, const char *name)
Definition type_registry.c:156
static char * _registry_parser_parse_name(_registry_parser_state_t *state, char *buffer, size_t buf_size)
Definition type_registry.c:478
static void _registry_parser_skip_whitespace(_registry_parser_state_t *state)
Definition type_registry.c:459
static infix_status _resolve_type_graph_inplace_recursive(infix_arena_t *temp_arena, infix_type **type_ptr, infix_registry_t *registry, resolve_memo_node_t **memo_head)
Definition type_registry.c:338
INFIX_TLS const char * g_infix_last_signature_context
A thread-local pointer to the full signature string being parsed.
Definition error.c:99