#include #include /** * 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; }