开始设计

This commit is contained in:
2026-08-10 01:21:15 +08:00
commit e45398991f
228 changed files with 20827 additions and 0 deletions
+196
View File
@@ -0,0 +1,196 @@
#include <c_LinearProbingHashST.h>
#include <c_Memory.h>
/**
* FNV-1a baseline string/scalar data hash scrambling algorithm.
*/
C_STATIC_FORCE_INLINE
uint32_t c_LPHash_DefaultHash(const void* key, c_size_t key_size) {
const uint8_t* data = (const uint8_t*)key;
uint32_t hash = 0x811C9DC5;
for (c_size_t i = 0; i < key_size; i++) {
hash ^= data[i];
hash *= 0x01000193;
}
return hash;
}
/* ------------------------------------------------------------------------------------------------------------------ */
/* */
c_err_t c_LinearProbingHashST_Init(c_LinearProbingHashST_t* st, c_size_t initial_capacity,
c_size_t key_size, c_size_t val_size,
uint32_t (*hash_fn)(const void*, c_size_t),
int (*key_compar)(const void*, const void*)) {
if (st == NULL || initial_capacity == 0 || key_size == 0 || val_size == 0 || key_compar == NULL) {
return C_ERR_PARAM;
}
st->M = initial_capacity;
st->N = 0;
st->key_size = key_size;
st->val_size = val_size;
st->hash_fn = (hash_fn != NULL) ? hash_fn : c_LPHash_DefaultHash;
st->key_compar = key_compar;
st->keys = C_ALLOC(st->M * key_size);
st->vals = C_ALLOC(st->M * val_size);
st->occupied = (c_bool_t*)C_ALLOC(st->M * sizeof(c_bool_t));
if (st->keys == NULL || st->vals == NULL || st->occupied == NULL) {
C_FREE(st->keys); C_FREE(st->vals); C_FREE(st->occupied);
st->keys = NULL; st->vals = NULL; st->occupied = NULL;
return C_ERR_NOMEM;
}
memset(st->occupied, C_FALSE, st->M * sizeof(c_bool_t));
return C_ERR_OK;
}
void c_LinearProbingHashST_Destroy(c_LinearProbingHashST_t* st) {
if (st) {
C_FREE(st->keys); st->keys = NULL;
C_FREE(st->vals); st->vals = NULL;
C_FREE(st->occupied); st->occupied = NULL;
st->M = 0;
st->N = 0;
}
}
/**
* Explicit internal resizing routing handler.
* Essential for keeping the Load Factor (alpha) under 0.5 to prevent clustering.
*/
static c_err_t c_LinearProbingHashST_Resize(c_LinearProbingHashST_t* st, c_size_t capacity) {
c_LinearProbingHashST_t temp_st;
c_err_t err = c_LinearProbingHashST_Init(&temp_st, capacity, st->key_size, st->val_size, st->hash_fn, st->key_compar);
if (err != C_ERR_OK) return err;
char* keys_base = (char*)st->keys;
char* vals_base = (char*)st->vals;
c_size_t ks = st->key_size;
c_size_t vs = st->val_size;
// Rehash and insert all existing active items into the new, expanded table footprint
for (c_size_t i = 0; i < st->M; i++) {
if (st->occupied[i]) {
extern c_err_t c_LinearProbingHashST_Put(c_LinearProbingHashST_t*, const void*, const void*);
err = c_LinearProbingHashST_Put(&temp_st, keys_base + (i * ks), vals_base + (i * vs));
if (err != C_ERR_OK) {
c_LinearProbingHashST_Destroy(&temp_st);
return err;
}
}
}
// Swap parameters to apply the newly rehashed table context
C_FREE(st->keys); C_FREE(st->vals); C_FREE(st->occupied);
st->keys = temp_st.keys;
st->vals = temp_st.vals;
st->occupied = temp_st.occupied;
st->M = temp_st.M;
return C_ERR_OK;
}
c_err_t c_LinearProbingHashST_Put(c_LinearProbingHashST_t* st, const void* key, const void* val) {
if (st == NULL || key == NULL || val == NULL) return C_ERR_PARAM;
// Enforce an upper bound load factor limit of 50% to mitigate clustering degradation
if (st->N >= st->M / 2) {
c_err_t err = c_LinearProbingHashST_Resize(st, st->M * 2);
if (err != C_ERR_OK) return err;
}
char* keys_base = (char*)st->keys;
char* vals_base = (char*)st->vals;
c_size_t ks = st->key_size;
c_size_t vs = st->val_size;
c_size_t i;
for (i = st->hash_fn(key, ks) % st->M; st->occupied[i]; i = (i + 1) % st->M) {
if (st->key_compar(keys_base + (i * ks), key) == 0) {
// Found existing key match: update values block payload in place
memcpy(vals_base + (i * vs), val, vs);
return C_ERR_OK;
}
}
// Insert new item into the available open slot found by probing
memcpy(keys_base + (i * ks), key, ks);
memcpy(vals_base + (i * vs), val, vs);
st->occupied[i] = C_TRUE;
st->N++;
return C_ERR_OK;
}
void* c_LinearProbingHashST_Get(const c_LinearProbingHashST_t* st, const void* key) {
if (st == NULL || st->keys == NULL || key == NULL) return NULL;
char* keys_base = (char*)st->keys;
c_size_t ks = st->key_size;
for (c_size_t i = st->hash_fn(key, ks) % st->M; st->occupied[i]; i = (i + 1) % st->M) {
if (st->key_compar(keys_base + (i * ks), key) == 0) {
return (char*)st->vals + (i * st->val_size);
}
}
return NULL;
}
c_bool_t c_LinearProbingHashST_Contains(const c_LinearProbingHashST_t* st, const void* key) {
return c_LinearProbingHashST_Get(st, key) != NULL;
}
c_err_t c_LinearProbingHashST_Delete(c_LinearProbingHashST_t* st, const void* key) {
if (st == NULL || key == NULL) return C_ERR_PARAM;
char* keys_base = (char*)st->keys;
c_size_t ks = st->key_size;
c_size_t vs = st->val_size;
c_size_t i = st->hash_fn(key, ks) % st->M;
while (st->occupied[i]) {
if (st->key_compar(keys_base + (i * ks), key) == 0) {
break;
}
i = (i + 1) % st->M;
}
// Key to delete was not found in the hash table
if (!st->occupied[i]) return C_ERR_NOT_FOUND;
// Hard delete: Free the targeted slot index flag
st->occupied[i] = C_FALSE;
st->N--;
// CRITICAL REQUIREMENT: Rehash all subsequent cluster elements
// to bridge the open slot gap caused by deletion, preventing future search short-circuits.
i = (i + 1) % st->M;
while (st->occupied[i]) {
// Capture old keys/values payload allocations locally
void* key_to_rehash = C_ALLOC(ks);
void* val_to_rehash = C_ALLOC(vs);
memcpy(key_to_rehash, keys_base + (i * ks), ks);
memcpy(val_to_rehash, (char*)st->vals + (i * vs), vs);
// Explicitly clear the current cluster entry tracking variables
st->occupied[i] = C_FALSE;
st->N--;
// Re-insert the captured element into the table using standard routing rules
c_LinearProbingHashST_Put(st, key_to_rehash, val_to_rehash);
C_FREE(key_to_rehash);
C_FREE(val_to_rehash);
i = (i + 1) % st->M;
}
// Shrink the table capacity automatically if utilization drops below 12.5%
if (st->N > 0 && st->N <= st->M / 8) {
c_LinearProbingHashST_Resize(st, st->M / 2);
}
return C_ERR_OK;
}