Files
cAI/cKit/Search/c_BinarySearchST.c
T
2026-08-10 01:21:15 +08:00

169 lines
5.1 KiB
C

#include <c_BinarySearchST.h>
#include <c_Memory.h>
/**
* Core Rank/Binary Search operation.
* Returns the exact index if the key is found, or the insertion slot index if not found.
*/
static inline c_size_t c_BSST_Rank(const c_BinarySearchST_t* st, const void* key, c_bool_t* out_found) {
c_size_t left = 0;
c_size_t right = st->size;
char* keys_base = (char*)st->keys;
c_size_t ks = st->key_size;
while (left < right) {
c_size_t mid = left + (right - left) / 2;
int cmp = st->compar(key, keys_base + (mid * ks));
if (cmp == 0) {
if (out_found) *out_found = C_TRUE;
return mid;
} else if (cmp > 0) {
left = mid + 1;
} else {
right = mid;
}
}
if (out_found) *out_found = C_FALSE;
return left; // 'left' represents the precise index where the key *should* go
}
/* ------------------------------------------------------------------------------------------------------------------ */
/* */
c_err_t c_BinarySearchST_Init(c_BinarySearchST_t* st, c_size_t initial_capacity,
c_size_t key_size, c_size_t val_size,
int (*compar)(const void*, const void*)) {
if (st == NULL || key_size == 0 || val_size == 0 || compar == NULL) return C_ERR_PARAM;
st->capacity = (initial_capacity > 0) ? initial_capacity : 4;
st->key_size = key_size;
st->val_size = val_size;
st->size = 0;
st->compar = compar;
st->keys = C_ALLOC(st->capacity * key_size);
st->vals = C_ALLOC(st->capacity * val_size);
if (st->keys == NULL || st->vals == NULL) {
C_FREE(st->keys);
C_FREE(st->vals);
return C_ERR_NOMEM;
}
return C_ERR_OK;
}
void c_BinarySearchST_Destroy(c_BinarySearchST_t* st) {
if (st) {
C_FREE(st->keys);
C_FREE(st->vals);
st->size = 0;
st->capacity = 0;
}
}
c_err_t c_BinarySearchST_Clear(c_BinarySearchST_t* st) {
if (st == NULL) return C_ERR_PARAM;
st->size = 0; // Soft reset clears tracking variables but keeps allocated memory blocks
return C_ERR_OK;
}
c_bool_t c_BinarySearchST_Contains(const c_BinarySearchST_t* st, const void* key) {
if (st == NULL || key == NULL) return C_FALSE;
c_bool_t found = C_FALSE;
c_BSST_Rank(st, key, &found);
return found;
}
c_err_t c_BinarySearchST_Put(c_BinarySearchST_t* st, const void* key, const void* val) {
if (st == NULL || key == NULL || val == NULL) return C_ERR_PARAM;
c_bool_t found = C_FALSE;
c_size_t idx = c_BSST_Rank(st, key, &found);
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;
// Symbol Table Behavior: If the key already exists, overwrite the value
if (found) {
memcpy(vals_base + (idx * vs), val, vs);
return C_ERR_OK;
}
// Dynamic parallel array capacity expansion
if (st->size >= st->capacity) {
c_size_t new_capacity = st->capacity * 2;
void* new_keys = C_ALLOC(new_capacity * ks);
void* new_vals = C_ALLOC(new_capacity * vs);
if (new_keys == NULL || new_vals == NULL) {
C_FREE(new_keys);
C_FREE(new_vals);
return C_ERR_NOMEM;
}
if (st->size > 0) {
memcpy(new_keys, st->keys, st->size * ks);
memcpy(new_vals, st->vals, st->size * vs);
}
C_FREE(st->keys); C_FREE(st->vals);
st->keys = new_keys; st->vals = new_vals;
st->capacity = new_capacity;
keys_base = (char*)st->keys;
vals_base = (char*)st->vals;
}
// Shift memory components to create a gap for insertion
if (idx < st->size) {
memmove(keys_base + ((idx + 1) * ks), keys_base + (idx * ks), (st->size - idx) * ks);
memmove(vals_base + ((idx + 1) * vs), vals_base + (idx * vs), (st->size - idx) * vs);
}
// Drop elements directly into parallel array channels
memcpy(keys_base + (idx * ks), key, ks);
memcpy(vals_base + (idx * vs), val, vs);
st->size++;
return C_ERR_OK;
}
void* c_BinarySearchST_Get(const c_BinarySearchST_t* st, const void* key) {
if (st == NULL || key == NULL) return NULL;
c_bool_t found = C_FALSE;
c_size_t idx = c_BSST_Rank(st, key, &found);
if (found) {
return (char*)st->vals + (idx * st->val_size);
}
return NULL;
}
c_err_t c_BinarySearchST_Delete(c_BinarySearchST_t* st, const void* key) {
if (st == NULL || key == NULL) return C_ERR_PARAM;
c_bool_t found = C_FALSE;
c_size_t idx = c_BSST_Rank(st, key, &found);
if (!found) return C_ERR_NOT_FOUND;
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;
// Compress parallel entries down over the deleted item slot
if (idx < st->size - 1) {
memmove(keys_base + (idx * ks), keys_base + ((idx + 1) * ks), (st->size - 1 - idx) * ks);
memmove(vals_base + (idx * vs), vals_base + ((idx + 1) * vs), (st->size - 1 - idx) * vs);
}
st->size--;
return C_ERR_OK;
}