This commit is contained in:
2026-08-30 01:48:03 +08:00
parent 84ebd52c24
commit 7940b67827
170 changed files with 2704 additions and 21276 deletions
-269
View File
@@ -1,269 +0,0 @@
#include <c_HashMap.h>
#include <c_Memory.h>
#include "c_Macros.h"
#define C_HASHMAP_LOAD_FACTOR_THRESHOLD 0.75f
#define DEFAULT_CAPACITY 16
/* ------------------------------------------------------------------------------------------------------------------ */
/* */
// Internal Helper: Doubles bucket allocations and rehashes entries
static c_err_t hashmap_resize(c_HashMap_t* self) {
c_size_t new_capacity = self->capacity * 2;
c_HashMapEntry_t** new_buckets = (c_HashMapEntry_t**)C_CALLOC(new_capacity, sizeof(c_HashMapEntry_t*));
if (!new_buckets) return C_ERR_NOMEM;
// Migrate entries over from old buckets array
for (c_size_t i = 0; i < self->capacity; i++) {
c_HashMapEntry_t* entry = self->buckets[i];
while (entry != NULL) {
c_HashMapEntry_t* next = entry->next;
// Recompute new bucket index mapping constraints
uint32_t raw_hash = self->hash(entry->key, self->key_size);
c_size_t new_index = raw_hash % new_capacity;
// Link into the new bucket array chain head
entry->next = new_buckets[new_index];
new_buckets[new_index] = entry;
entry = next;
}
}
C_FREE(self->buckets);
self->buckets = new_buckets;
self->capacity = new_capacity;
return C_ERR_OK;
}
C_STATIC_FORCE_INLINE
void hashmap_iter_advance_to_valid(c_HashMapKeyIter_t* self) {
while (self->bucket_index < self->map->capacity) {
// 如果當前桶子有鏈結節點,繫結其指標的指標
if (self->map->buckets[self->bucket_index] != NULL) {
self->entry = &self->map->buckets[self->bucket_index];
return;
}
self->bucket_index++;
}
// 若找不到任何有效節點,重置為 NULL 象徵迭代結束
self->entry = NULL;
}
/* ------------------------------------------------------------------------------------------------------------------ */
/* */
c_err_t c_HashMap_Init(c_HashMap_t* self, int key_size, int value_size, c_size_t initial_capacity,
c_HashMap_Hash_f hash, c_HashMap_Compare_f compare) {
if (!self || key_size <= 0 || value_size <= 0 || !hash || !compare) return C_ERR_PARAM;
self->capacity = (initial_capacity > 0) ? initial_capacity : DEFAULT_CAPACITY;
self->size = 0;
self->key_size = key_size;
self->value_size = value_size;
self->hash = hash;
self->compare = compare;
self->buckets = (c_HashMapEntry_t**)C_CALLOC(self->capacity, sizeof(c_HashMapEntry_t*));
if (!self->buckets) {
self->capacity = 0;
return C_ERR_NOMEM;
}
return C_ERR_OK;
}
void c_HashMap_Destroy(c_HashMap_t* self) {
if (!self) return;
for (c_size_t i = 0; i < self->capacity; i++) {
c_HashMapEntry_t* entry = self->buckets[i];
while (entry != NULL) {
c_HashMapEntry_t* next = entry->next;
// C_FREE(entry->key);
// C_FREE(entry->value);
C_FREE(entry);
entry = next;
}
}
C_FREE(self->buckets);
self->buckets = NULL;
self->capacity = 0;
self->size = 0;
}
// Maps/Overwrites keys to value entities in O(1) average time complexity
c_err_t c_HashMap_Put(c_HashMap_t* self, const void* key, const void* value) {
if (!self || !self->buckets || !key || !value) return C_ERR_PARAM;
// Trigger dynamic scale-out adjustments if load boundaries criteria are exceeded
if ((float)(self->size + 1) / self->capacity >= C_HASHMAP_LOAD_FACTOR_THRESHOLD) {
if (hashmap_resize(self) != C_ERR_OK) return C_ERR_NOMEM;
}
uint32_t raw_hash = self->hash(key, self->key_size);
c_size_t index = raw_hash % self->capacity;
// Scan the collision chain to check if the key already exists
c_HashMapEntry_t* entry = self->buckets[index];
while (entry != NULL) {
if (self->compare(entry->key, key, self->key_size) == 0) {
// Overwrite existing value mapping using deep copy semantics
memcpy(entry->value, value, self->value_size);
return C_ERR_OK;
}
entry = entry->next;
}
// Allocate a new node entry if the key does not exist
int size = (int)sizeof(c_HashMapEntry_t) + self->key_size + self->value_size;
size = C_ALIGN_UPB(size, C_ALIGN_SIZE);
c_HashMapEntry_t* new_entry = (c_HashMapEntry_t*)C_ALLOC(size);
if (!new_entry) return C_ERR_NOMEM;
new_entry->key = new_entry+1;
new_entry->value = new_entry->key + self->key_size;
// Deep copy payload bounds properties
memcpy(new_entry->key, key, self->key_size);
memcpy(new_entry->value, value, self->value_size);
// Single-chain head link injection (O(1))
new_entry->next = self->buckets[index];
self->buckets[index] = new_entry;
self->size++;
return C_ERR_OK;
}
// Fetches value references safely into user-allocated destination spaces
c_err_t c_HashMap_Get(c_HashMap_t* self, const void* key, void* out_value) {
if (!self || !self->buckets || !key || !out_value) return C_ERR_PARAM;
uint32_t raw_hash = self->hash(key, self->key_size);
c_size_t index = raw_hash % self->capacity;
c_HashMapEntry_t* entry = self->buckets[index];
while (entry != NULL) {
if (self->compare(entry->key, key, self->key_size) == 0) {
memcpy(out_value, entry->value, self->value_size);
return C_ERR_OK;
}
entry = entry->next;
}
return C_ERR_NOTFOUND;
}
// Unlinks map items matching key contexts safely (O(1) average time complexity)
c_err_t c_HashMap_Remove(c_HashMap_t* self, const void* key) {
if (!self || !self->buckets || !key) return C_ERR_PARAM;
uint32_t raw_hash = self->hash(key, self->key_size);
c_size_t index = raw_hash % self->capacity;
c_HashMapEntry_t** curr = &self->buckets[index];
while (*curr != NULL) {
if (self->compare((*curr)->key, key, self->key_size) == 0) {
c_HashMapEntry_t* to_delete = *curr;
*curr = to_delete->next; // Unlink node entry frame properties
// free(to_delete->key);
// free(to_delete->value);
C_FREE(to_delete);
self->size--;
return C_ERR_OK;
}
curr = &(*curr)->next;
}
return C_ERR_NOTFOUND;
}
c_bool_t c_HashMap_Contains(c_HashMap_t* self, const void* key) {
if (!self || !self->buckets || !key) return C_FALSE;
uint32_t raw_hash = self->hash(key, self->key_size);
c_size_t index = raw_hash % self->capacity;
c_HashMapEntry_t* entry = self->buckets[index];
while (entry != NULL) {
if (self->compare(entry->key, key, self->key_size) == 0) return C_TRUE;
entry = entry->next;
}
return C_FALSE;
}
/* ------------------------------------------------------------------------------------------------------------------ */
/* */
void c_HashMapKeyIter_Init(c_HashMapKeyIter_t* self, c_HashMap_t* map) {
if (!self || !map) return;
self->map = map;
self->bucket_index = 0;
self->entry = NULL;
// 初始化時先定位到第一個有效節點
hashmap_iter_advance_to_valid(self);
}
// 檢查是否還有下一個元素
c_bool_t c_HashMapKeyIter_HasNext(c_HashMapKeyIter_t* self) {
if (!self || !self->entry || !*(self->entry)) return C_FALSE;
return C_TRUE;
}
// 查看目前指向的鍵(Key)指標 (不前進)
void* c_HashMapKeyIter_Get(c_HashMapKeyIter_t* self) {
if (!c_HashMapKeyIter_HasNext(self)) return NULL;
return (*(self->entry))->key;
}
// 獲取目前指向的鍵(Key)指標,並將迭代器前進到下一個有效節點
void* c_HashMapKeyIter_Next(c_HashMapKeyIter_t* self) {
if (!c_HashMapKeyIter_HasNext(self)) return NULL;
c_HashMapEntry_t* curr = *(self->entry);
void* key_ptr = curr->key;
// 如果當前衝突鏈結中還有下一個節點,直接移向 next
if (curr->next != NULL) {
self->entry = &(curr->next);
} else {
// 如果當前衝突鏈結已到底,前進到下一個桶子並搜尋有效節點
self->bucket_index++;
hashmap_iter_advance_to_valid(self);
}
return key_ptr;
}
// 迭代器安全刪除:在走訪期間以 O(1) 的平均複雜度斷開鏈結並釋放記憶體
void c_HashMapKeyIter_Remove(c_HashMapKeyIter_t* self) {
if (!c_HashMapKeyIter_HasNext(self)) return;
c_HashMapEntry_t* to_delete = *(self->entry);
// 關鍵指標斷開:讓前一個節點的 next(或是桶子的首節點指標)直接指向下一個節點
*(self->entry) = to_delete->next;
// 釋放該 Entry 的深複製記憶體
// free(to_delete->key);
// free(to_delete->value);
C_FREE(to_delete);
self->map->size--;
// 檢查斷開後當前位置是否為空(代表原本該桶子的衝突鏈結已走訪完畢)
if (*(self->entry) == NULL) {
// 前進到下一個桶子搜尋下一個有效節點
self->bucket_index++;
hashmap_iter_advance_to_valid(self);
}
// 備註:若 *(self->entry) != NULL,則 self->entry 自動留在了下一個節點上,不需額外處理
}