Open-addressing hash map with string keys

C
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <string.h>

#define SLOTS 64

/* Fixed-size open-addressing map: string keys, int values, no deletions. */
static struct { char *key; int value; } map[SLOTS];

/* Return the slot for key: its own slot or the next free one. */
static size_t find_slot(const char *key)
{
    size_t hash = 2166136261u; /* FNV-1a */
    for (const char *p = key; *p != '\0'; p++) hash = (hash ^ (unsigned char)*p) * 16777619u;
    for (size_t step = 0; step < SLOTS; step++) {
        size_t at = (hash + step) % SLOTS;
        if (map[at].key == NULL || strcmp(map[at].key, key) == 0) return at;
    }
    return SLOTS; /* table is full */
}

static int map_put(const char *key, int value)
{
    size_t at = find_slot(key);
    if (at == SLOTS) return -1;
    if (map[at].key == NULL && (map[at].key = strdup(key)) == NULL) return -1;
    map[at].value = value;
    return 0;
}

static int map_get(const char *key, int *out)
{
    size_t at = find_slot(key);
    if (at == SLOTS || map[at].key == NULL) return 0;
    *out = map[at].value;
    return 1;
}

/* Usage: map_put("retries", 3); int value; if (map_get("retries", &value)) ... */