#include /** * @brief 核心内部操作:基于无符号安全的左闭右开二分 Rank 检索 * * @return c_size_t 返回小于指定 key 的键的总个数。该位置就是精确命中点或完美插入点 */ static c_size_t c_BinarySearchST_Rank(const c_BinarySearchST_t* self, const void* key) { c_size_t low = 0; c_size_t high = self->size; // 右边界设为 size(开区间),这样 high 永远不会因 mid-1 下溢 while (low < high) { // 🌟 开区间控制条件为 low < high,彻底杜绝死循环 c_size_t mid = low + ((high - low) >> 1); char* mid_key = self->keys + (mid * self->key_size); int cmp_res = self->cmp(key, mid_key, self->args); if (cmp_res < 0) { high = mid; // 🌟 目标比 mid 小,安全收缩右开边界,完全斩断减法下溢 } else if (cmp_res > 0) { low = mid + 1; // 目标比 mid 大,安全收缩左闭边界 } else { return mid; // 精确命中,返回对应的物理下标位置 } } return low; // 未命中,返回当前最精准的插入点插槽索引 } /* ------------------------------------------------------------------------------------------------------------------ */ /* */ c_err_t c_BinarySearchST_Init(c_BinarySearchST_t* self, c_size_t initial_capacity, c_size_t key_size, c_size_t val_size, c_SortCompare_t cmp, void* args, c_Allocator_t* allocator) { if (!self || key_size == 0 || val_size == 0 || !cmp) { return C_ERR_PARAM; } // 自适应分配器降级缺省安全播种 if (allocator) { self->allocator = *allocator; } else { self->allocator = c_DefaultAllocator; } c_size_t cap = (initial_capacity > 0) ? initial_capacity : 4; // 前置逆向除法溢出安全审计 if (((c_size_t)-1) / key_size < cap) return C_ERR_NOMEM; if (((c_size_t)-1) / val_size < cap) return C_ERR_NOMEM; self->keys = (char*)c_Allocator_Alloc(&self->allocator, cap * key_size); self->vals = (char*)c_Allocator_Alloc(&self->allocator, cap * val_size); if (!self->keys || !self->vals) { if (self->keys) c_Allocator_Free(&self->allocator, self->keys); if (self->vals) c_Allocator_Free(&self->allocator, self->vals); return C_ERR_NOMEM; } self->capacity = cap; self->size = 0; self->key_size = key_size; self->val_size = val_size; self->cmp = cmp; self->args = args; return C_ERR_OK; } /** * @brief 根据指定的 Key 检索关联的 Value 值(时间复杂度 O(log N)) */ c_err_t c_BinarySearchST_Get(const c_BinarySearchST_t* self, const void* key, void* out_val) { if (!self || !key || !out_val) return C_ERR_PARAM; if (self->size == 0) return C_ERR_EMPTY; c_size_t i = c_BinarySearchST_Rank(self, key); // 如果检索出的位置合法,且对应的键与其等价,说明精确命中 if (i < self->size && self->cmp(key, self->keys + (i * self->key_size), self->args) == 0) { memcpy(out_val, self->vals + (i * self->val_size), self->val_size); return C_ERR_OK; } return C_ERR_NOTFOUND; } /** * @brief 检查符号表内是否包含指定的 Key 键值 */ bool c_BinarySearchST_Contains(const c_BinarySearchST_t* self, const void* key) { if (!self || !key || self->size == 0) return false; c_size_t i = c_BinarySearchST_Rank(self, key); return (i < self->size && self->cmp(key, self->keys + (i * self->key_size), self->args) == 0); } /** * @brief 存入键值对。若已存在则覆写更新;若不存在则对后方数据滑窗后移,插入并维持有序性 */ c_err_t c_BinarySearchST_Put(c_BinarySearchST_t* self, const void* key, const void* val) { if (!self || !key || !val) return C_ERR_PARAM; c_size_t i = c_BinarySearchST_Rank(self, key); // 1. 如果键值已经存在,直接更新它的值(覆写语义) if (i < self->size && self->cmp(key, self->keys + (i * self->key_size), self->args) == 0) { memcpy(self->vals + (i * self->val_size), val, self->val_size); return C_ERR_OK; } // 2. 键值不存在,准备执行新元素插入。前置判定自适应弹性动态扩容 if (self->size >= self->capacity) { c_size_t old_cap = self->capacity; // 算术乘法整数溢出除法拦截防护 if (((c_size_t)-1) / self->key_size < (old_cap << 1)) return C_ERR_NOMEM; if (((c_size_t)-1) / self->val_size < (old_cap << 1)) return C_ERR_NOMEM; c_size_t new_cap = old_cap << 1; c_size_t old_key_bytes = old_cap * self->key_size; c_size_t new_key_bytes = new_cap * self->key_size; c_size_t old_val_bytes = old_cap * self->val_size; c_size_t new_val_bytes = new_cap * self->val_size; char* new_keys = (char*)c_Allocator_Realloc(&self->allocator, self->keys, old_key_bytes, new_key_bytes); char* new_vals = (char*)c_Allocator_Realloc(&self->allocator, self->vals, old_val_bytes, new_val_bytes); if (!new_keys || !new_vals) { // 部分成功安全回退 if (new_keys) self->keys = new_keys; if (new_vals) self->vals = new_vals; return C_ERR_NOMEM; } self->keys = new_keys; self->vals = new_vals; self->capacity = new_cap; } // 3. 核心数据平移:将区间 [i, size-1] 内的所有键值对数据,单向全部后移一位给新插入留出位置 // 控制条件为 j > i。即便 i 为最左侧的 0,j 最小减到 1 就会强制退出,彻底封死无符号自减下溢 for (c_size_t j = self->size; j > i; j--) { memcpy(self->keys + (j * self->key_size), self->keys + ((j - 1) * self->key_size), self->key_size); memcpy(self->vals + (j * self->val_size), self->vals + ((j - 1) * self->val_size), self->val_size); } // 4. 将新元素深拷贝写入空出来的有序安全插槽中 memcpy(self->keys + (i * self->key_size), key, self->key_size); memcpy(self->vals + (i * self->val_size), val, self->val_size); self->size++; return C_ERR_OK; } /** * @brief 根据指定 Key 彻底从有序表中斩断移出指定对,并对其后方数据滑窗前移覆盖 */ c_err_t c_BinarySearchST_Delete(c_BinarySearchST_t* self, const void* key) { if (!self || !key) return C_ERR_PARAM; if (self->size == 0) return C_ERR_EMPTY; c_size_t i = c_BinarySearchST_Rank(self, key); // 键值未找到拦截 if (i >= self->size || self->cmp(key, self->keys + (i * self->key_size), self->args) != 0) { return C_ERR_NOTFOUND; } // 核心数据平移:将区间 [i+1, size-1] 内的元素统一向前推进覆盖一位 // 纯单调递增控制,num 边界有效拦截 c_size_t limit = self->size - 1; for (c_size_t j = i; j < limit; j++) { memcpy(self->keys + (j * self->key_size), self->keys + ((j + 1) * self->key_size), self->key_size); memcpy(self->vals + (j * self->val_size), self->vals + ((j + 1) * self->val_size), self->val_size); } self->size--; return C_ERR_OK; } /** * @brief 有序表反初始化数据销毁 */ void c_BinarySearchST_Destroy(c_BinarySearchST_t* self) { if (self) { if (self->keys) c_Allocator_Free(&self->allocator, self->keys); if (self->vals) c_Allocator_Free(&self->allocator, self->vals); self->keys = NULL; self->vals = NULL; self->size = 0; self->capacity = 0; } }