150 lines
4.5 KiB
C
150 lines
4.5 KiB
C
#include <c_SeqSearchST.h>
|
|
|
|
|
|
c_err_t c_SeqSearchST_Init(c_SeqSearchST_t* self, c_size_t key_size, c_size_t val_size, c_SortCompare_t key_cmp, void* args, c_Allocator_t* allocator) {
|
|
if (!self || key_size == 0 || val_size == 0 || !key_cmp) {
|
|
return C_ERR_PARAM;
|
|
}
|
|
|
|
// 自适应分配器降级缺省安全播种
|
|
if (allocator) {
|
|
self->allocator = *allocator;
|
|
} else {
|
|
self->allocator = c_DefaultAllocator;
|
|
}
|
|
|
|
self->first = NULL;
|
|
self->size = 0;
|
|
self->key_size = key_size;
|
|
self->val_size = val_size;
|
|
self->key_cmp = key_cmp;
|
|
self->args = args;
|
|
|
|
return C_ERR_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief 存入键值对。若 Key 已存在则覆写更新其 Value;若不存在则使用头插法压入新节点
|
|
*/
|
|
c_err_t c_SeqSearchST_Put(c_SeqSearchST_t* self, const void* key, const void* val) {
|
|
if (!self || !key || !val) return C_ERR_PARAM;
|
|
|
|
// 1. 前置顺序走查:如果键值已经存在,直接更新它的值(覆写语义)
|
|
for (c_SeqSearchSTNode* x = self->first; x != NULL; x = x->next) {
|
|
if (self->key_cmp(key, x->key, self->args) == 0) {
|
|
memcpy(x->val, val, self->val_size);
|
|
return C_ERR_OK;
|
|
}
|
|
}
|
|
|
|
// 2. 键值不存在,启动托管分配:开辟新节点以及键和值的独立存储块
|
|
c_SeqSearchSTNode* new_node = (c_SeqSearchSTNode*)c_Allocator_Alloc(&self->allocator, sizeof(c_SeqSearchSTNode));
|
|
void* new_key = c_Allocator_Alloc(&self->allocator, self->key_size);
|
|
void* new_val = c_Allocator_Alloc(&self->allocator, self->val_size);
|
|
|
|
if (!new_node || !new_key || !new_val) {
|
|
// 部分失败安全回收拦截,杜绝内存泄漏
|
|
if (new_node) c_Allocator_Free(&self->allocator, new_node);
|
|
if (new_key) c_Allocator_Free(&self->allocator, new_key);
|
|
if (new_val) c_Allocator_Free(&self->allocator, new_val);
|
|
return C_ERR_NOMEM;
|
|
}
|
|
|
|
// 执行内存数据安全转储
|
|
memcpy(new_key, key, self->key_size);
|
|
memcpy(new_val, val, self->val_size);
|
|
|
|
new_node->key = new_key;
|
|
new_node->val = new_val;
|
|
|
|
// 3. 头插法挂载新节点
|
|
new_node->next = self->first;
|
|
self->first = new_node;
|
|
self->size++;
|
|
|
|
return C_ERR_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief 根据指定的 Key 检索关联的 Value 值
|
|
*/
|
|
c_err_t c_SeqSearchST_Get(const c_SeqSearchST_t* self, const void* key, void* out_val) {
|
|
if (!self || !key || !out_val) return C_ERR_PARAM;
|
|
|
|
for (const c_SeqSearchSTNode* x = self->first; x != NULL; x = x->next) {
|
|
if (self->key_cmp(key, x->key, self->args) == 0) {
|
|
memcpy(out_val, x->val, self->val_size);
|
|
return C_ERR_OK;
|
|
}
|
|
}
|
|
|
|
return C_ERR_NOTFOUND;
|
|
}
|
|
|
|
/**
|
|
* @brief 检查符号表内是否包含指定的 Key 键值
|
|
*/
|
|
bool c_SeqSearchST_Contains(const c_SeqSearchST_t* self, const void* key) {
|
|
if (!self || !key) return false;
|
|
for (const c_SeqSearchSTNode* x = self->first; x != NULL; x = x->next) {
|
|
if (self->key_cmp(key, x->key, self->args) == 0) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* @brief 根据指定 Key 彻底从符号表中移出其关联的键值对节点
|
|
*/
|
|
c_err_t c_SeqSearchST_Delete(c_SeqSearchST_t* self, const void* key) {
|
|
if (!self || !key) return C_ERR_PARAM;
|
|
if (self->size == 0) return C_ERR_EMPTY;
|
|
|
|
c_SeqSearchSTNode* prev = NULL;
|
|
c_SeqSearchSTNode* curr = self->first;
|
|
|
|
while (curr != NULL) {
|
|
if (self->key_cmp(key, curr->key, self->args) == 0) {
|
|
if (prev == NULL) {
|
|
self->first = curr->next;
|
|
} else {
|
|
prev->next = curr->next;
|
|
}
|
|
|
|
// 原路回收释放单节点下深开辟的所有子内存块
|
|
c_Allocator_Free(&self->allocator, curr->key);
|
|
c_Allocator_Free(&self->allocator, curr->val);
|
|
c_Allocator_Free(&self->allocator, curr);
|
|
|
|
self->size--;
|
|
return C_ERR_OK;
|
|
}
|
|
prev = curr;
|
|
curr = curr->next;
|
|
}
|
|
|
|
return C_ERR_NOTFOUND;
|
|
}
|
|
|
|
/**
|
|
* @brief 反初始化:深度级联释放符号表内的所有节点、键和值的全部堆空间
|
|
*/
|
|
void c_SeqSearchST_Destroy(c_SeqSearchST_t* self) {
|
|
if (!self) return;
|
|
|
|
c_SeqSearchSTNode* curr = self->first;
|
|
while (curr != NULL) {
|
|
c_SeqSearchSTNode* next_tmp = curr->next;
|
|
|
|
c_Allocator_Free(&self->allocator, curr->key);
|
|
c_Allocator_Free(&self->allocator, curr->val);
|
|
c_Allocator_Free(&self->allocator, curr);
|
|
|
|
curr = next_tmp;
|
|
}
|
|
|
|
self->first = NULL;
|
|
self->size = 0;
|
|
}
|