#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
#include <sys/cdefs.h>
#if defined(__RCSID)
__RCSID("$NetBSD: hash.c,v 1.30 2025/05/24 07:38:59 rillig Exp $");
#endif
#include <limits.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include "lint2.h"
#define HTAB_BUCKETS 1009
static hte_t **htab;
hte_t **
htab_new(void)
{
return xcalloc(HTAB_BUCKETS, sizeof(*htab_new()));
}
static unsigned int
hash(const char *s)
{
unsigned int v;
const char *p;
v = 0;
for (p = s; *p != '\0'; p++) {
v = (v << 4) + (unsigned char)*p;
v ^= v >> 28;
}
return v % HTAB_BUCKETS;
}
hte_t *
hash_search(hte_t **table, const char *s, bool mknew)
{
unsigned int h;
hte_t *hte;
if (table == NULL)
table = htab;
h = hash(s);
for (hte = table[h]; hte != NULL; hte = hte->h_link) {
if (strcmp(hte->h_name, s) == 0)
break;
}
if (hte != NULL || !mknew)
return hte;
hte = xmalloc(sizeof(*hte));
hte->h_name = xstrdup(s);
hte->h_used = false;
hte->h_def = false;
hte->h_static = false;
hte->h_syms = NULL;
hte->h_lsym = &hte->h_syms;
hte->h_calls = NULL;
hte->h_lcall = &hte->h_calls;
hte->h_usyms = NULL;
hte->h_lusym = &hte->h_usyms;
hte->h_link = table[h];
hte->h_hte = NULL;
table[h] = hte;
return hte;
}
struct hte_list {
hte_t **items;
size_t len;
size_t cap;
};
static void
hte_list_add(struct hte_list *list, hte_t *item)
{
if (list->len >= list->cap) {
list->cap = list->cap == 0 ? 1024 : 2 * list->cap;
list->items = xrealloc(list->items,
sizeof(list->items[0]) * list->cap);
}
list->items[list->len++] = item;
}
static int
hte_by_name(const void *va, const void *vb)
{
const hte_t *a = *((const hte_t *const *)va);
const hte_t *b = *((const hte_t *const *)vb);
return strcmp(a->h_name, b->h_name);
}
void
symtab_init(void)
{
htab = htab_new();
}
void
symtab_forall(void (*action)(hte_t *))
{
int i;
hte_t *hte;
hte_t **table = htab;
for (i = 0; i < HTAB_BUCKETS; i++) {
for (hte = table[i]; hte != NULL; hte = hte->h_link)
action(hte);
}
}
void
symtab_forall_sorted(void (*action)(const hte_t *))
{
hte_t *hte;
struct hte_list sorted = { NULL, 0, 0 };
size_t i;
hte_t **table = htab;
for (i = 0; i < HTAB_BUCKETS; i++)
for (hte = table[i]; hte != NULL; hte = hte->h_link)
hte_list_add(&sorted, hte);
qsort(sorted.items, sorted.len, sizeof(sorted.items[0]), hte_by_name);
for (i = 0; i < sorted.len; i++)
action(sorted.items[i]);
free(sorted.items);
}
void
hash_free(hte_t **table)
{
int i;
hte_t *hte, *nexthte;
for (i = 0; i < HTAB_BUCKETS; i++) {
for (hte = table[i]; hte != NULL; hte = nexthte) {
free(__UNCONST(hte->h_name));
nexthte = hte->h_link;
free(hte);
}
}
free(table);
}