#include "intern.h" #include "util.h" #include #include #include #define INITIAL_CAPACITY 1024 typedef struct intern_entry intern_entry_t; struct intern_entry { const char *str; intern_entry_t *next; }; struct intern_table { size_t capacity; intern_entry_t **buckets; }; intern_table_t *intern_table_alloc(void) { intern_table_t *table = malloc(sizeof(struct intern_table)); if (table == NULL) die("Out of memory: cannot allocate intern table."); table->capacity = INITIAL_CAPACITY; table->buckets = calloc(table->capacity, sizeof(intern_entry_t *)); if (table->buckets == NULL) die("Out of memory: cannot allocate intern table buckets."); return table; } void intern_table_free(intern_table_t *table) { for (size_t i = 0; i < table->capacity; i++) { intern_entry_t *entry = table->buckets[i]; while (entry != NULL) { intern_entry_t *next = entry->next; free((char *)entry->str); free(entry); entry = next; } } free(table->buckets); free(table); } intern_t intern(intern_table_t *table, const char *str) { return intern_prefix(table, str, strlen(str)); } intern_t intern_prefix(intern_table_t *table, const char *str, size_t len) { uint32_t h = hash_buffer(str, len); size_t index = h % table->capacity; for (intern_entry_t *entry = table->buckets[index]; entry != NULL; entry = entry->next) if (strncmp(entry->str, str, len) == 0) return entry->str; char *copy = malloc(len + 1); if (copy == NULL) die("Out of memory: cannot allocate interned string"); strncpy(copy, str, len); copy[len] = '\0'; intern_entry_t *new_entry = malloc(sizeof(intern_entry_t)); if (new_entry == NULL) die("Out of memory: cannot allocate intern table entry"); new_entry->str = copy; new_entry->next = table->buckets[index]; table->buckets[index] = new_entry; return copy; } const char * intern_exists(intern_table_t *table, const char *str) { uint32_t h = hash_string(str); size_t index = h % table->capacity; for (intern_entry_t *entry = table->buckets[index]; entry != NULL; entry = entry->next) if (strcmp(entry->str, str) == 0) return entry->str; return NULL; }