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}
110 size_t index = _registry_hash_string(name) % registry->num_buckets;
111 _infix_registry_entry_t * new_entry =
113 if (!new_entry) {
115 return nullptr;
116 }
117 size_t name_len = strlen(name) + 1;
118 char * name_copy = infix_arena_alloc(registry->arena, name_len, 1);
119 if (!name_copy) {
121 return nullptr;
122 }
123 infix_memcpy((void *)name_copy, name, name_len);
124 new_entry->name = name_copy;
125 new_entry->type = nullptr;
126 new_entry->is_forward_declaration = false;
127 // Prepend to the linked list in the bucket.
128 new_entry->next = registry->buckets[index];
129 registry->buckets[index] = new_entry;
131 return new_entry;
132}
133// Public API: Registry Lifecycle
217 if (!registry)
218 return;
219 // Only destroy the arena if it was created internally by `infix_registry_create`.
222 // Always free the registry struct itself.
224}
225// Internal Type Graph Resolution
245 infix_type ** type_ptr,
247 resolve_memo_node_t ** memo_head) {
248 if (!type_ptr || !*type_ptr || !(*type_ptr)->is_arena_allocated)
249 return INFIX_SUCCESS;
250 infix_type * type = *type_ptr;
251 // Cycle detection: If we've seen this node before, we're in a cycle.
252 // Return success to break the loop.
253 for (resolve_memo_node_t * node = *memo_head; node != nullptr; node = node->next)
254 if (node->src == type)
255 return INFIX_SUCCESS;
256 // Allocate the memoization node from the stable temporary arena.
257 resolve_memo_node_t * memo_node =
258 infix_arena_alloc(temp_arena, sizeof(resolve_memo_node_t), _Alignof(resolve_memo_node_t));
259 if (!memo_node) {
262 }
263 memo_node->src = type;
264 memo_node->next = *memo_head;
265 *memo_head = memo_node;
267 if (!registry) {
270 }
271 const char * name = type->meta.named_reference.name;
273 if (!entry || !entry->type) {
276 }
277 *type_ptr = entry->type;
278 return INFIX_SUCCESS;
279 }
281 switch (type->category) {
284 temp_arena, &type->meta.pointer_info.pointee_type, registry, memo_head);
285 break;
286 case INFIX_TYPE_ARRAY:
287 status =
289 break;
291 case INFIX_TYPE_UNION:
292 for (size_t i = 0; i < type->meta.aggregate_info.num_members; ++i) {
294 temp_arena, &type->meta.aggregate_info.members[i].type, registry, memo_head);
295 if (status != INFIX_SUCCESS)
296 break;
297 }
298 break;
301 temp_arena, &type->meta.func_ptr_info.return_type, registry, memo_head);
302 if (status != INFIX_SUCCESS)
303 break;
304 for (size_t i = 0; i < type->meta.func_ptr_info.num_args; ++i) {
306 temp_arena, &type->meta.func_ptr_info.args[i].type, registry, memo_head);
307 if (status != INFIX_SUCCESS)
308 break;
309 }
310 break;
311 case INFIX_TYPE_ENUM:
313 temp_arena, &type->meta.enum_info.underlying_type, registry, memo_head);
314 break;
316 status =
318 break;
321 temp_arena, &type->meta.vector_info.element_type, registry, memo_head);
322 break;
323 default:
324 break;
325 }
326 return status;
327}
336 // Create a temporary arena solely for the visited list's lifetime.
337 infix_arena_t * temp_arena = infix_arena_create(1024);
338 if (!temp_arena) {
341 }
342 resolve_memo_node_t * memo_head = nullptr;
343 infix_status status = _resolve_type_graph_inplace_recursive(temp_arena, type_ptr, registry, &memo_head);
344 infix_arena_destroy(temp_arena);
345 return status;
346}
347// Public API: Type Registration
356typedef struct {
357 const char * p;
358 const char * start;
366 while (1) {
367 while (isspace((unsigned char)*state->p))
368 state->p++;
369 if (*state->p == '#') // Skip comments
370 while (*state->p != '\n' && *state->p != '\0')
371 state->p++;
372 else
373 break;
374 }
375}
384static char * _registry_parser_parse_name(_registry_parser_state_t * state, char * buffer, size_t buf_size) {
386 const char * name_start = state->p;
387 while (isalnum((unsigned char)*state->p) || *state->p == '_' || *state->p == ':') {
388 if (*state->p == ':' && state->p[1] != ':')
389 break; // Handle single colon as non-identifier char.
390 if (*state->p == ':')
391 state->p++; // Skip the first ':' of '::'
392 state->p++;
393 }
394 size_t len = state->p - name_start;
395 if (len == 0 || len >= buf_size)
396 return nullptr;
397 infix_memcpy(buffer, name_start, len);
398 buffer[len] = '\0';
399 return buffer;
400}
430 if (!registry || !definitions) {
433 }
434 _registry_parser_state_t state = {.p = definitions, .start = definitions};
436 // A temporary structure to hold information about each definition found in Pass 1.
437 struct def_info {
439 const char * def_body_start;
440 size_t def_body_len;
441 };
442 size_t defs_capacity = 64; // Start with an initial capacity.
443 struct def_info * defs_found = infix_malloc(sizeof(struct def_info) * defs_capacity);
444 if (!defs_found) {
447 }
448 size_t num_defs_found = 0;
449 infix_status final_status = INFIX_SUCCESS;
450
451 // Pass 1: Scan & Index all names and their definition bodies.
452 while (*state.p != '\0') {
454 if (*state.p == '\0')
455 break;
456 if (*state.p != '@') {
458 final_status = INFIX_ERROR_INVALID_ARGUMENT;
459 goto cleanup;
460 }
461 state.p++;
462 char name_buffer[256];
463 if (!_registry_parser_parse_name(&state, name_buffer, sizeof(name_buffer))) {
465 final_status = INFIX_ERROR_INVALID_ARGUMENT;
466 goto cleanup;
467 }
468 _infix_registry_entry_t * entry = _registry_lookup(registry, name_buffer);
470 if (*state.p == '=') { // This is a full definition.
471 state.p++;
473 // It's an error to redefine a type that wasn't a forward declaration.
474 if (entry && !entry->is_forward_declaration) {
476 final_status = INFIX_ERROR_INVALID_ARGUMENT;
477 goto cleanup;
478 }
479 if (!entry) { // If it doesn't exist, create it.
480 entry = _registry_insert(registry, name_buffer);
481 if (!entry) {
482 final_status = INFIX_ERROR_ALLOCATION_FAILED;
483 goto cleanup;
484 }
485 }
486 if (num_defs_found >= defs_capacity) {
487 size_t new_capacity = defs_capacity * 2;
488 struct def_info * new_defs = infix_realloc(defs_found, sizeof(struct def_info) * new_capacity);
489 if (!new_defs) {
491 final_status = INFIX_ERROR_ALLOCATION_FAILED;
492 goto cleanup;
493 }
494 defs_found = new_defs;
495 defs_capacity = new_capacity;
496 }
497 // Find the end of the type definition body (the next top-level ';').
498 defs_found[num_defs_found].entry = entry;
499 defs_found[num_defs_found].def_body_start = state.p;
500 int nest_level = 0;
501 const char * body_end = state.p;
502 while (*body_end != '\0' &&
503 !(*body_end == ';' &&
504 nest_level == 0)) { // Explicitly check for and skip over the '->' token as a single unit.
505 if (*body_end == '-' && body_end[1] == '>') {
506 body_end += 2; // Advance the pointer past the entire token.
507 continue; // Continue to the next character in the loop.
508 }
509 if (*body_end == '{' || *body_end == '<' || *body_end == '(' || *body_end == '[')
510 nest_level++;
511 if (*body_end == '}' || *body_end == '>' || *body_end == ')' || *body_end == ']')
512 nest_level--;
513 body_end++;
514 }
515 defs_found[num_defs_found].def_body_len = body_end - state.p;
516 state.p = body_end;
517 num_defs_found++;
518 }
519 else if (*state.p == ';') { // This is a forward declaration.
520 if (entry) {
521 // If the type is already fully defined, re-declaring it as a forward decl is an error.
522 if (!entry->is_forward_declaration) {
524 final_status = INFIX_ERROR_INVALID_ARGUMENT;
525 goto cleanup;
526 }
527 // If it's already a forward declaration, this is a no-op.
528 }
529 else {
530 entry = _registry_insert(registry, name_buffer);
531 if (!entry) {
532 final_status = INFIX_ERROR_ALLOCATION_FAILED;
533 goto cleanup;
534 }
535 }
536 // Ensure a placeholder type exists so other types can reference it immediately.
537 // We create an opaque struct (size 0) as the placeholder and mark it incomplete.
538 if (!entry->type) {
539 entry->type = infix_arena_calloc(registry->arena, 1, sizeof(infix_type), _Alignof(infix_type));
540 if (!entry->type) {
541 final_status = INFIX_ERROR_ALLOCATION_FAILED;
542 goto cleanup;
543 }
544 entry->type->is_arena_allocated = true;
545 entry->type->is_incomplete = true; // Mark as incomplete
546 entry->type->arena = registry->arena;
548 entry->type->size = 0;
549 entry->type->alignment = 1; // Minimal alignment to pass basic validation
550 entry->type->name = entry->name;
551 }
552 entry->is_forward_declaration = true;
553 }
554 else {
556 final_status = INFIX_ERROR_INVALID_ARGUMENT;
557 goto cleanup;
558 }
559 if (*state.p == ';')
560 state.p++;
561 }
562 // Pass 2: Parse the bodies of all found definitions into the registry.
563 for (size_t i = 0; i < num_defs_found; ++i) {
564 _infix_registry_entry_t * entry = defs_found[i].entry;
565 // Make a temporary, null-terminated copy of the definition body substring.
566 char * body_copy = infix_malloc(defs_found[i].def_body_len + 1);
567 if (!body_copy) {
569 final_status = INFIX_ERROR_ALLOCATION_FAILED;
570 goto cleanup;
571 }
572 infix_memcpy(body_copy, defs_found[i].def_body_start, defs_found[i].def_body_len);
573 body_copy[defs_found[i].def_body_len] = '\0';
574 // "Parse" step: parse into a temporary arena.
575 infix_type * raw_type = nullptr;
576 infix_arena_t * parser_arena = nullptr;
577 infix_status status = _infix_parse_type_internal(&raw_type, &parser_arena, body_copy);
578 infix_free(body_copy);
579 if (status != INFIX_SUCCESS) {
580 // Adjust the error position to be relative to the full definition string.
582 _infix_set_error(err.category, err.code, (defs_found[i].def_body_start - definitions) + err.position);
583 final_status = INFIX_ERROR_INVALID_ARGUMENT;
584 infix_arena_destroy(parser_arena);
585 goto cleanup;
586 }
587 const infix_type * type_to_alias = raw_type;
588 // If the RHS is another named type (e.g., @MyAlias = @ExistingType),
589 // we need to resolve it first to get the actual type we're aliasing.
590 if (raw_type->category == INFIX_TYPE_NAMED_REFERENCE) {
592 if (existing_entry && existing_entry->type)
593 type_to_alias = existing_entry->type;
594 else {
595 size_t relative_pos = raw_type->source_offset;
598 (size_t)(defs_found[i].def_body_start - definitions) + relative_pos);
599 final_status = INFIX_ERROR_INVALID_ARGUMENT;
600 infix_arena_destroy(parser_arena);
601 goto cleanup;
602 }
603 }
604 // Prepare the new definition.
605 infix_type * new_def = nullptr;
606 if (!type_to_alias->is_arena_allocated) {
607 // This is a static type (e.g., primitive). We MUST create a mutable
608 // copy in the registry's arena before we can attach a name to it.
609 // This prevents corrupting the global static singletons.
610 new_def = infix_arena_alloc(registry->arena, sizeof(infix_type), _Alignof(infix_type));
611 if (new_def) {
612 *new_def = *type_to_alias;
613 new_def->is_arena_allocated = true;
614 new_def->arena = registry->arena;
615 }
616 }
617 else // Dynamic type: deep copy.
618 new_def = _copy_type_graph_to_arena(registry->arena, type_to_alias);
619
620 infix_arena_destroy(parser_arena); // The temporary raw_type is no longer needed.
621
622 if (!new_def) {
624 final_status = INFIX_ERROR_ALLOCATION_FAILED;
625 goto cleanup;
626 }
627
628 // Update the entry. If a placeholder already exists (from forward decl), we MUST update it in-place
629 // to preserve pointers from other types that have already resolved to it.
630 if (entry->type) {
631 // Struct-copy the new definition into the existing placeholder memory.
632 *entry->type = *new_def;
633 // Restore the self-reference if the copy logic pointed the arena elsewhere.
634 entry->type->arena = registry->arena;
635 // The new definition is complete, so ensure the flag is cleared.
636 entry->type->is_incomplete = false;
637 }
638 else {
639 entry->type = new_def;
640 entry->type->is_incomplete = false;
641 }
642
643 // Ensure the name is attached and the flag is cleared.
644 entry->type->name = entry->name;
645 entry->is_forward_declaration = false;
646 }
647 // Pass 3: Resolve and layout all the newly defined types.
648 for (size_t i = 0; i < num_defs_found; ++i) {
649 _infix_registry_entry_t * entry = defs_found[i].entry;
650 if (entry->type) {
651 // "Resolve" and "Layout" steps.
653 // The error was set inside resolve (relative to body).
654 // We need to re-base it to the full definitions string.
656 size_t body_offset = defs_found[i].def_body_start - definitions;
657 _infix_set_error(err.category, err.code, body_offset + err.position);
658 final_status = INFIX_ERROR_INVALID_ARGUMENT;
659 goto cleanup;
660 }
662 }
663 }
664cleanup:
665 infix_free(defs_found);
666 return final_status;
667}
668// Registry Introspection API Implementation
689 // Return an iterator positioned before the first element.
690 // The first call to next() will advance it to the first valid element.
691 return (infix_registry_iterator_t){registry, 0, nullptr};
692}
701 if (!iter || !iter->registry)
702 return false;
703 const _infix_registry_entry_t * entry = iter->current_entry;
704 // If we have a current entry, start from the next one in the chain.
705 if (iter->current_entry)
706 entry = entry->next;
707 // Otherwise, if we are starting, begin with the head of the current bucket.
708 else if (iter->current_bucket < iter->registry->num_buckets)
709 entry = iter->registry->buckets[iter->current_bucket];
710 while (true) {
711 // Traverse the current chain looking for a valid entry.
712 while (entry) {
713 if (entry->type && !entry->is_forward_declaration) {
714 // Found one. Update the iterator and return successfully.
715 iter->current_entry = entry;
716 return true;
717 }
718 entry = entry->next;
719 }
720 // If we're here, the current chain is exhausted. Move to the next bucket.
721 iter->current_bucket++;
722 // If there are no more buckets, we're done.
723 if (iter->current_bucket >= iter->registry->num_buckets) {
724 iter->current_entry = nullptr;
725 return false;
726 }
727 // Start the search from the head of the new bucket.
728 entry = iter->registry->buckets[iter->current_bucket];
729 }
730}
740 if (!iter || !iter->current_entry)
741 return nullptr;
742 return iter->current_entry->name;
743}
753 if (!iter || !iter->current_entry)
754 return nullptr;
755 return iter->current_entry->type;
756}
768 if (!registry || !name)
769 return false;
771 // It's defined if an entry exists, it has a type, and it's not a lingering forward declaration.
772 return entry != nullptr && entry->type != nullptr && !entry->is_forward_declaration;
773}
784 if (!registry || !name)
785 return nullptr;
787 if (entry && entry->type && !entry->is_forward_declaration)
788 return entry->type;
789 return nullptr;
790}
infix_arena_t * arena
Definition 005_layouts.c:60
const char * definitions
Definition 008_registry_introspection.c:34
infix_registry_t * registry
Definition 008_registry_introspection.c:31
infix_status status
Definition 103_unions.c:59
#define c23_nodiscard
A compatibility macro for the C23 [[nodiscard]] attribute.
Definition compat_c23.h:106
#define INFIX_TLS
Definition error.c:68
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:1251
@ INFIX_CODE_UNEXPECTED_TOKEN
Definition infix.h:1239
@ INFIX_CODE_NULL_POINTER
Definition infix.h:1229
@ INFIX_CODE_OUT_OF_MEMORY
Definition infix.h:1233
@ INFIX_CATEGORY_ALLOCATION
Definition infix.h:1218
@ INFIX_CATEGORY_GENERAL
Definition infix.h:1217
@ INFIX_CATEGORY_PARSER
Definition infix.h:1219
size_t source_offset
Definition infix.h:202
struct infix_type_t::@0::@1 pointer_info
Metadata for INFIX_TYPE_POINTER.
size_t position
Definition infix.h:1267
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:1265
bool is_incomplete
Definition infix.h:200
infix_type * type
Definition infix.h:268
struct infix_type_t::@0::@4 func_ptr_info
Metadata for INFIX_TYPE_REVERSE_TRAMPOLINE.
infix_arena_t * arena
Definition infix.h:201
size_t size
Definition infix.h:197
size_t alignment
Definition infix.h:198
infix_struct_member * members
Definition infix.h:213
struct infix_type_t::@0::@6 complex_info
Metadata for INFIX_TYPE_COMPLEX.
const char * name
Definition infix.h:195
infix_function_argument * args
Definition infix.h:226
infix_status
Enumerates the possible status codes returned by infix API functions.
Definition infix.h:354
infix_type_category category
Definition infix.h:196
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:209
infix_type * type
Definition infix.h:256
struct infix_type_t * element_type
Definition infix.h:219
struct infix_type_t * return_type
Definition infix.h:225
struct infix_type_t::@0::@5 enum_info
Metadata for INFIX_TYPE_ENUM.
struct infix_type_t * base_type
Definition infix.h:236
infix_error_code_t code
Definition infix.h:1266
size_t num_members
Definition infix.h:214
struct infix_type_t * underlying_type
Definition infix.h:232
struct infix_type_t::@0::@8 named_reference
Metadata for INFIX_TYPE_NAMED_REFERENCE.
size_t num_args
Definition infix.h:227
bool is_arena_allocated
Definition infix.h:199
@ INFIX_ERROR_ALLOCATION_FAILED
Definition infix.h:356
@ INFIX_SUCCESS
Definition infix.h:355
@ INFIX_ERROR_INVALID_ARGUMENT
Definition infix.h:357
#define infix_free
A macro that can be defined to override the default free function.
Definition infix.h:303
void infix_arena_destroy(infix_arena_t *)
Destroys an arena and frees all memory allocated from it.
Definition arena.c:83
#define infix_memcpy
A macro that can be defined to override the default memcpy function.
Definition infix.h:307
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:179
#define infix_realloc
A macro that can be defined to override the default realloc function.
Definition infix.h:299
c23_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_malloc
A macro that can be defined to override the default malloc function.
Definition infix.h:291
c23_nodiscard infix_arena_t * infix_arena_create(size_t)
Creates a new memory arena.
Definition arena.c:52
void infix_registry_destroy(infix_registry_t *registry)
Destroys a type registry and frees all associated memory.
Definition type_registry.c:216
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:428
c23_nodiscard infix_registry_t * infix_registry_create(void)
Creates a new, empty named type registry.
Definition type_registry.c:145
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:783
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:183
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:752
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:688
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:700
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:739
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:767
@ INFIX_TYPE_UNION
Definition infix.h:152
@ INFIX_TYPE_COMPLEX
Definition infix.h:156
@ INFIX_TYPE_ARRAY
Definition infix.h:153
@ INFIX_TYPE_VECTOR
Definition infix.h:157
@ INFIX_TYPE_POINTER
Definition infix.h:150
@ INFIX_TYPE_NAMED_REFERENCE
Definition infix.h:158
@ INFIX_TYPE_REVERSE_TRAMPOLINE
Definition infix.h:154
@ INFIX_TYPE_ENUM
Definition infix.h:155
@ INFIX_TYPE_STRUCT
Definition infix.h:151
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:173
void _infix_type_recalculate_layout(infix_type *type)
Recalculates the layout of a fully resolved type graph.
Definition types.c:945
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:968
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:1133
void _infix_clear_error(void)
Clears the thread-local error state.
Definition error.c:266
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:356
const char * start
Definition type_registry.c:358
const char * p
Definition type_registry.c:357
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:1264
Internal definition of a registry iterator.
Definition infix_internals.h:179
const _infix_registry_entry_t * current_entry
Definition infix_internals.h:182
const infix_registry_t * registry
Definition infix_internals.h:180
size_t current_bucket
Definition infix_internals.h:181
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:194
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:335
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:109
static char * _registry_parser_parse_name(_registry_parser_state_t *state, char *buffer, size_t buf_size)
Definition type_registry.c:384
static void _registry_parser_skip_whitespace(_registry_parser_state_t *state)
Definition type_registry.c:365
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:244
INFIX_TLS const char * g_infix_last_signature_context
A thread-local pointer to the full signature string being parsed.
Definition error.c:99