#include #include #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 自動留在了下一個節點上,不需額外處理 }