GitHub - lcsmuller/oa-hash: A lightweight single-header open-addressing hashtable implementation in ANSI C (original) (raw)

oa_hash

A lightweight single-header open-addressing hashtable implementation in C that gives complete memory allocation control to the user.

About

This library implements a hash table using open addressing for collision resolution, where you provide the pre-allocated buckets array. This approach gives you full control over memory management while maintaining a simple and efficient API.

Key Features

Examples

Stack Allocation

struct oa_hash ht; struct oa_hash_entry buckets[64] = {0}; // pre-allocated buckets int value = 42;

// Initialize with pre-allocated buckets oa_hash_init(&ht, buckets, 64);

// Store and retrieve values oa_hash_set(&ht, "key", 3, &value); int *got = oa_hash_get(&ht, "key", 3);

printf("Value: %d\n", *got); // 42

// Cleanup (doesn't free memory - that's up to you) oa_hash_cleanup(&ht);

Dynamic Resizing

struct oa_hash ht; struct oa_hash_entry *buckets; size_t capacity = 64; int value = 42;

// Initial allocation buckets = malloc(capacity * sizeof(*buckets)); oa_hash_init(&ht, buckets, capacity);

// Add some values oa_hash_set(&ht, "key", 3, &value);

// Time to grow the table struct oa_hash_entry *new_buckets = malloc(capacity * 2 * sizeof(*buckets)); struct oa_hash_entry *old_buckets = oa_hash_rehash(&ht, new_buckets, capacity * 2); if (old_buckets) { // Rehash succeeded, free old buckets assert(old_buckets == buckets); // old_buckets will always be the same as the original buckets free(old_buckets); buckets = new_buckets; } else { // Rehash failed, free new buckets free(new_buckets); }

// Cleanup oa_hash_cleanup(&ht); free(buckets);

Embedded Hash Table

The library provides a flexible way to embed hash table fields directly into your own structures using the OA_HASH_ATTRS macro. This is useful for:

  1. Embedding hash tables inside larger structures
  2. Creating read-only views of existing hash tables
  3. Custom memory layouts while maintaining API compatibility

Example: Read-Only Hash Table View

/* Define a read-only view of a hash table / struct oa_hash_view { OA_HASH_ATTRS(const); / const qualifier for read-only access */ };

void print_hash_stats(const struct oa_hash ht) { / Cast to read-only view for safer access */ const struct oa_hash_view view = (const struct oa_hash_view)ht;

printf("Hash table stats:\n");
printf("  Entries: %zu\n", view->length);
printf("  Capacity: %zu\n", view->capacity);
printf("  Load factor: %.2f\n", (double)view->length / view->capacity);

}

Example: Custom Structure with Embedded Hash Table

/* Structure with embedded hash table / struct my_dictionary { OA_HASH_ATTRS(mut); / Mutable hash table fields, must be first attribute */ char *name; void (*on_insert)(const char *key); };

/* Initialize dictionary with embedded hash table */ void dictionary_init(struct my_dictionary *dict, const char *name, struct oa_hash_entry buckets[], size_t capacity) { dict->name = strdup(name); dict->buckets = buckets; dict->capacity = capacity; dict->length = 0; dict->on_insert = NULL;

memset(buckets, 0, sizeof(struct oa_hash_entry) * capacity);

}

/* Use regular oa_hash functions by casting */ void dictionary_insert(struct my_dictionary *dict, const char *key, size_t key_len, void *value) { struct oa_hash ht = (struct oa_hash)dict; oa_hash_set(ht, key, key_len, value);

if (dict->on_insert) {
    dict->on_insert(key);
}

}

The macro allows for seamless casting between compatible structures while maintaining type safety with the specified qualifiers.

Memory Management

Unlike most hashtable implementations, this library:

When using dynamic allocation:

Build

oa_hash is single-header-only library, so it includes additional macros for more complex uses cases. #define OA_HASH_STATIC hides all oa_hash API symbols by making them static. Also, if you want to include oa_hash.h from multiple C files, to avoid duplication of symbols you may define OA_HASH_HEADER macro.

/* In every .c file that uses oa_hash include only declarations: */ #define OA_HASH_HEADER #include "oa_hash.h"

/* Additionally, create one oa_hash.c file for oa_hash implementation: */ #include "oa_hash.h"

License

MIT License - see LICENSE file for details