diff --git a/Foundation/c_Array.c b/Foundation/c_Array.c index 85ae74b..f4cea9b 100644 --- a/Foundation/c_Array.c +++ b/Foundation/c_Array.c @@ -1,114 +1,70 @@ #include -#include -c_err_t c_Array_Init(c_Array_t* array, c_size_t length, c_size_t size) { - if (!array) return C_ERR_PARAM; +c_err_t c_Array_Init(c_Array_t* self, c_size_t item_size, c_size_t size, c_Allocator_t* allocator) { + if (!self || item_size == 0 || size == 0) return C_ERR_PARAM; - array->length = length; - array->size = size; - if (length>0) { - array->array = C_CALLOC(length, size); - if (!array->array) { - return C_ERR_NOMEM; - } - }else { - array->array = NULL; + // 内部绑定:如果传入 NULL,无缝降级为系统默认分配器 + self->allocator = (allocator != NULL) ? *allocator : c_DefaultAllocator; + self->item_size = item_size; + self->size = size; + + // 通过内部绑定的分配器,一次性开辟完全密集且等长的字节存储空间 + self->array = c_Allocator_Alloc(&self->allocator, self->size * self->item_size); + if (!self->array) return C_ERR_NOMEM; + + // 默认执行干净抹零 + memset(self->array, 0, self->size * self->item_size); + return C_ERR_OK; +} + +// 销毁固定数组资源 +void c_Array_Destroy(c_Array_t* self) { + if (!self) return; + if (self->array) { + c_Allocator_Free(&self->allocator, self->array); + self->array = NULL; } + self->size = 0; +} + +// 定点安全写入 (深度值复制) +c_err_t c_Array_Write(c_Array_t* self, c_size_t index, const void* item) { + // 强御级边界防御:拦截一切非法越界或空域写入 + if (!self || !item || index >= self->size) return C_ERR_PARAM; + + // 计算精准的物理坑位物理地址并执行覆写 + char* target = (char*)self->array + (index * self->item_size); + memcpy(target, item, self->item_size); return C_ERR_OK; } -void c_Array_Destroy(c_Array_t* array) { - if (!array) return; - C_FREE(array->array); - array->size = 0; - array->length = 0; -} +// 定点安全读取 (安全拷出副本) +c_err_t c_Array_Read(const c_Array_t* self, c_size_t index, void* out_item) { + if (!self || !out_item || index >= self->size) return C_ERR_PARAM; -c_Array_t* c_Array_New(c_size_t length, c_size_t size) { - c_Array_t* array; - C_NEW(array); - if (!array) { - return NULL; - } - c_Array_Init(array, length, size); - return array; -} + const char* source = (const char*)self->array + (index * self->item_size); + memcpy(out_item, source, self->item_size); -void c_Array_Delete(c_Array_t** array) { - if (!array || !*array) return; - C_FREE((*array)->array); - C_FREE(*array); -} - -c_size_t c_Array_Size(c_Array_t* array) { - if (!array) return 0; - return array->size; -} - -c_size_t c_Array_Length(c_Array_t* array) { - if (!array) return 0; - return array->length; -} - -c_err_t c_Array_Get(c_Array_t* array, c_size_t index, void** data) { - if (!array || (index >= array->length) || !data) return C_ERR_PARAM; - *data = array->array + index * array->size; return C_ERR_OK; } -c_err_t c_Array_Put(c_Array_t* array, c_size_t index, void* value) { - if (!array || !value || (index>=array->length)) return C_ERR_PARAM; - memcpy(array->array + index * array->size, value, array->size); +// 只读原位窥探指针 (注意:因为大小固定,该指针在数组生命周期内绝对不可变、不跑飞,极度安全) +void* c_Array_Get(const c_Array_t* self, c_size_t index) { + if (!self || index >= self->size) return NULL; + return (char*)self->array + (index * self->item_size); +} + +// 全局高速批量刷值填充 (常用于初始化状态、重置音频轨等) +c_err_t c_Array_Fill(c_Array_t* self, const void* item) { + if (!self || !item) return C_ERR_PARAM; + + // 利用连续线性空间的特点,高速循环平铺拷贝 + char* target = (char*)self->array; + for (c_size_t i = 0; i < self->size; i++) { + memcpy(target, item, self->item_size); + target += self->item_size; + } + return C_ERR_OK; } - -c_err_t c_Array_Resize(c_Array_t* array, c_size_t length) { - if (!array) return C_ERR_PARAM; - if (length==0) { - C_FREE(array->array); - }else if (array->length==0) { - array->array = C_ALLOC(length*array->size); - if (!array->array) { - return C_ERR_NOMEM; - } - }else { - array->array = C_REALLOC(array->array, length*array->size); - if (!array->array) { - return C_ERR_NOMEM; - } - } - array->length = length; - return C_ERR_OK; -} - -c_Array_t* c_Array_Copy(c_Array_t* array, c_size_t length) { - if (!array || length==0) return NULL; - c_Array_t* result; - C_NEW(result); - if (!result) { - return NULL; - } - c_Array_Init(result, length, array->size); - - if (result->length >= array->length && array->length > 0) { - memcpy(result->array, array->array, array->length * array->size); - }else if (array->length > result->length && result->length > 0) { - memcpy(result->array, array->array, result->length * array->size); - } - - return result; -} - -c_err_t c_Array_CopyTo(const c_Array_t* array, c_Array_t* copy) { - if (!array || !copy) return C_ERR_PARAM; - if (copy->length >= array->length && array->length > 0) { - memcpy(copy->array, array->array, array->length * array->size); - return C_ERR_OK; - }else if (array->length > copy->length && copy->length > 0) { - memcpy(copy->array, array->array, copy->length * array->size); - return C_ERR_OK; - } - return C_ERR_FAIL; -} - diff --git a/Foundation/c_Array.h b/Foundation/c_Array.h index 3fc56ec..eac4a85 100644 --- a/Foundation/c_Array.h +++ b/Foundation/c_Array.h @@ -5,35 +5,38 @@ #include #endif /*INCLUDED_C_TYPES_H*/ +#ifndef INCLUDED_C_ALLOCATOR_H +#include +#endif /*INCLUDED_C_ALLOCATOR_H*/ + + /* ------------------------------------------------------------------------------------------------------------------ */ /* */ -typedef struct c_Array_t { - c_size_t length; - c_size_t size; - uint8_t* array; -}c_Array_t; +typedef struct { + void* array; // 连续的数据存储区(直接密集存储数据值) + c_size_t item_size; // 单个元素的字节大小(例如 sizeof(int)) + c_size_t size; // 数组的固定长度(同时也是当前的物理容量) + c_Allocator_t allocator; // 内部绑定的自主内存管理器 +} c_Array_t; -c_err_t c_Array_Init(c_Array_t* array, c_size_t length, c_size_t size); +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ -void c_Array_Destroy(c_Array_t* array); +c_err_t c_Array_Init(c_Array_t* self, c_size_t item_size, c_size_t size, c_Allocator_t* allocator); +void c_Array_Destroy(c_Array_t* self); -c_Array_t* c_Array_New(c_size_t length, c_size_t size); +// 核心固定数组操作 API (安全值复制模式) +c_err_t c_Array_Read(const c_Array_t* self, c_size_t index, void* out_item); +c_err_t c_Array_Write(c_Array_t* self, c_size_t index, const void* item); +void* c_Array_Get(const c_Array_t* self, c_size_t index); +c_err_t c_Array_Fill(c_Array_t* self, const void* item); -void c_Array_Delete(c_Array_t** array); - -c_size_t c_Array_Size(c_Array_t* array); - -c_size_t c_Array_Length(c_Array_t* array); - -c_err_t c_Array_Get(c_Array_t* array, c_size_t index, void** data); - -c_err_t c_Array_Put(c_Array_t* array, c_size_t index, void* value); - -c_err_t c_Array_Resize(c_Array_t* array, c_size_t length); - -c_Array_t* c_Array_Copy(c_Array_t* array, c_size_t length); - -c_err_t c_Array_CopyTo(const c_Array_t* array, c_Array_t* copy); +// 内联高频辅助接口 +C_STATIC_FORCE_INLINE +c_size_t c_Array_Size(const c_Array_t* self) { + if (!self) return 0; + return self->size; // O(1) 实时读取,固定不变 +} #endif /*INCLUDED_C_ARRAY_H*/ diff --git a/Foundation/c_Array.t.c b/Foundation/c_Array.t.c index 5897a2c..472bf7a 100644 --- a/Foundation/c_Array.t.c +++ b/Foundation/c_Array.t.c @@ -1,137 +1,69 @@ #include "c_Array.h" -#include -#include #include "c_Test.h" -/* ========================================================================== */ -/* TEST CASES */ -/* ========================================================================== */ +// 用于测试的密集结构体 +typedef struct { + uint8_t r; + uint8_t g; + uint8_t b; +} PixelRGB_t; +TEST_CASE(test_fixed_generic_array_flow) { + c_Array_t img_line; -// 1. Stack Initialization and Destruction Loop -static -void test_array_stack_init_destroy(void) { - c_Array_t arr; - c_err_t err = c_Array_Init(&arr, 5, sizeof(int)); + // 初始化一个长度固定为 3 的 RGB 像素扁平大数组 + ASSERT_INT_EQ(C_ERR_OK, c_Array_Init(&img_line, sizeof(PixelRGB_t), 3, NULL)); + ASSERT_INT_EQ(3, c_Array_Size(&img_line)); + ASSERT_PTR_NOT_NULL(img_line.array); - ASSERT_LL_EQ(C_SUCCESS, err); - ASSERT_LL_EQ(5, c_Array_Length(&arr)); - ASSERT_LL_EQ(sizeof(int), c_Array_Size(&arr)); - ASSERT_PTR_NOT_NULL(arr.array); + PixelRGB_t red = { .r = 255, .g = 0, .b = 0 }; + PixelRGB_t green = { .r = 0, .g = 255, .b = 0 }; + PixelRGB_t white = { .r = 255, .g = 255, .b = 255 }; - c_Array_Destroy(&arr); + // 1. 验证定点写入 (Write) + ASSERT_INT_EQ(C_ERR_OK, c_Array_Write(&img_line, 0, &red)); + ASSERT_INT_EQ(C_ERR_OK, c_Array_Write(&img_line, 1, &green)); + + // 防御越界写入,应当报错拒绝 + ASSERT_INT_EQ(C_ERR_PARAM, c_Array_Write(&img_line, 3, &white)); + + // 2. 验证定点读取与值复制强屏障 (Read) + PixelRGB_t read_res; + ASSERT_INT_EQ(C_ERR_OK, c_Array_Read(&img_line, 0, &read_res)); + ASSERT_INT_EQ(255, read_res.r); + ASSERT_INT_EQ(0, read_res.g); + + // 修改局部临时变量,验证内部数据不受二次污染 + red.r = 123; + ASSERT_INT_EQ(C_ERR_OK, c_Array_Read(&img_line, 0, &read_res)); + ASSERT_INT_EQ(255, read_res.r); // 内部依旧是 255,证明完美值隔离 + + // 3. 验证原位窥探能力 (Get) + PixelRGB_t* direct_ptr = (PixelRGB_t*)c_Array_Get(&img_line, 1); + ASSERT_PTR_NOT_NULL(direct_ptr); + ASSERT_INT_EQ(255, direct_ptr->g); + + // 严苛验证固定物理内存布局: + // 索引 1 的地址必须与数组首地址精准偏移 1 个 item_size 字节,完全不存在任何链式空隙 + ASSERT_TRUE((void*)((char*)img_line.array + sizeof(PixelRGB_t)) == (void*)direct_ptr); + + // 4. 验证全局批量刷值功能 (Fill) + ASSERT_INT_EQ(C_ERR_OK, c_Array_Fill(&img_line, &white)); + + // 抽样验证填充后的每一项是否全变成了白色 + PixelRGB_t* check_p2 = (PixelRGB_t*)c_Array_Get(&img_line, 2); + ASSERT_INT_EQ(255, check_p2->r); + ASSERT_INT_EQ(255, check_p2->g); + ASSERT_INT_EQ(255, check_p2->b); + + c_Array_Destroy(&img_line); } -// 2. Heap Dynamic Allocation Lifecycles -static void test_array_heap_new_delete(void) { - c_Array_t* arr = c_Array_New(10, sizeof(double)); - - ASSERT_PTR_NOT_NULL(arr); - ASSERT_LL_EQ(10, c_Array_Length(arr)); - ASSERT_LL_EQ(sizeof(double), c_Array_Size(arr)); - - c_Array_Delete(&arr); - ASSERT_TRUE(arr==NULL); // Ensure pointer is zeroed out by reference parameter modification -} - -// 3. Put and Get Data Element Scenarios -static void test_array_put_and_get(void) { - c_Array_t* arr = c_Array_New(3, sizeof(int)); - ASSERT_PTR_NOT_NULL(arr); - ASSERT_INT_EQ(3, arr->length); - - int val1 = 100, val2 = 200, val3 = 300; - - // Put elements inside length limits - ASSERT_INT_EQ(C_SUCCESS, c_Array_Put(arr, 0, &val1)); - ASSERT_INT_EQ(C_SUCCESS, c_Array_Put(arr, 1, &val2)); - ASSERT_INT_EQ(C_SUCCESS, c_Array_Put(arr, 2, &val3)); - - // Out of bounds checks - int val_bad = 999; - ASSERT_INT_EQ(C_ERR_PARAM, c_Array_Put(arr, 3, &val_bad)); - - // Get verification - void* fetch_ptr = NULL; - ASSERT_INT_EQ(C_SUCCESS, c_Array_Get(arr, 1, &fetch_ptr)); - ASSERT_PTR_NOT_NULL(fetch_ptr); - ASSERT_INT_EQ(200, *(int*)fetch_ptr); - - // Out of bounds get verification - ASSERT_INT_EQ(C_ERR_PARAM, c_Array_Get(arr, 5, &fetch_ptr)); - - c_Array_Delete(&arr); -} - -// 4. Memory Resizing Limits Verification -static void test_array_resize(void) { - c_Array_t* arr = c_Array_New(2, sizeof(int)); - int val0 = 42, val1 = 84; - c_Array_Put(arr, 0, &val0); - c_Array_Put(arr, 1, &val1); - - // Resize up to 4 elements - ASSERT_INT_EQ(C_SUCCESS, c_Array_Resize(arr, 4)); - ASSERT_INT_EQ(4, c_Array_Length(arr)); - - // Verify older elements remain structurally untouched - void* res_ptr = NULL; - ASSERT_INT_EQ(C_SUCCESS, c_Array_Get(arr, 1, &res_ptr)); - ASSERT_INT_EQ(84, *(int*)res_ptr); - - // Resize down to 1 element - ASSERT_INT_EQ(C_SUCCESS, c_Array_Resize(arr, 1)); - ASSERT_INT_EQ(1, c_Array_Length(arr)); - - // Index 1 should now be unreachable / out of bounds - ASSERT_INT_EQ(C_ERR_PARAM, c_Array_Get(arr, 1, &res_ptr)); - - c_Array_Delete(&arr); -} - -// 5. Deep Copy Execution Verification -static void test_array_copy_and_copy_to(void) { - c_Array_t* source = c_Array_New(3, sizeof(int)); - int a = 11, b = 22, c = 33; - c_Array_Put(source, 0, &a); - c_Array_Put(source, 1, &b); - c_Array_Put(source, 2, &c); - - // Test c_Array_Copy (creates a new array object on the heap) - c_Array_t* copied_arr = c_Array_Copy(source, 2); // copy only first 2 items - ASSERT_PTR_NOT_NULL(copied_arr); - ASSERT_INT_EQ(2, c_Array_Length(copied_arr)); - - void* data_ptr = NULL; - c_Array_Get(copied_arr, 1, &data_ptr); - ASSERT_INT_EQ(22, *(int*)data_ptr); - - // Test c_Array_CopyTo (copies into an already initialized destination) - c_Array_t dest; - c_Array_Init(&dest, 3, sizeof(int)); - - ASSERT_INT_EQ(C_SUCCESS, c_Array_CopyTo(source, &dest)); - - c_Array_Get(&dest, 2, &data_ptr); - ASSERT_INT_EQ(33, *(int*)data_ptr); - - // Clean up all resources - c_Array_Delete(&copied_arr); - c_Array_Destroy(&dest); - c_Array_Delete(&source); -} - - int main(void) { - TEST_START(array_data_structure_suite); - - RUN_TEST(test_array_stack_init_destroy); - RUN_TEST(test_array_heap_new_delete); - RUN_TEST(test_array_put_and_get); - RUN_TEST(test_array_resize); - RUN_TEST(test_array_copy_and_copy_to); - + printf("\n"); + TEST_START(C_Fixed_Array_Core_Layout_Tests); + RUN_TEST(test_fixed_generic_array_flow); TEST_REPORT(); RETURN_TEST_STATUS; -} \ No newline at end of file +} diff --git a/Foundation/c_ArrayList.c b/Foundation/c_ArrayList.c index 51a2abf..084fb5e 100644 --- a/Foundation/c_ArrayList.c +++ b/Foundation/c_ArrayList.c @@ -1,101 +1,126 @@ #include -#include -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -#define DEFAULT_INITIAL_CAPACITY 4 -#define MIN_SHRINK_CAPACITY 4 - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -c_err_t c_ArrayList_Init(c_ArrayList_t* self, c_size_t obj_size, c_size_t capacity) { - if (!self || obj_size == 0) return C_ERR_PARAM; - - self->obj_size = (int)obj_size; - self->size = 0; +c_err_t c_ArrayList_Init(c_ArrayList_t *self, c_size_t item_size, c_size_t capacity, c_Allocator_t *allocator) { + if (!self || item_size==0) return C_ERR_PARAM; + self->allocator = (allocator!=NULL)?*allocator:c_DefaultAllocator; + self->item_size = item_size; self->capacity = capacity; + self->size = 0; - if (capacity==0) { + if (self->capacity==0) { self->array = NULL; }else { - self->array = C_ALLOC(self->capacity * self->obj_size); + self->array = c_Allocator_Alloc(&self->allocator, self->capacity * self->item_size); if (!self->array) { - self->capacity = 0; return C_ERR_NOMEM; } } - return C_ERR_OK; } void c_ArrayList_Destroy(c_ArrayList_t* self) { - if (!self) return; - C_FREE(self->array); - self->capacity = 0; + if (!self) { + return; + } + if (self->array) { + c_Allocator_Free(&self->allocator, self->array); + self->array = NULL; + } self->size = 0; - self->obj_size=0; + self->capacity = 0; } -c_err_t c_ArrayList_Add(c_ArrayList_t* self, void* obj) { - if (!self || !obj) return C_ERR_PARAM; - - // 動態擴容邏輯 - if (self->size >= self->capacity) { - const c_size_t new_capacity = (self->capacity==0)?DEFAULT_INITIAL_CAPACITY:(self->capacity<<1); - void* new_array = C_REALLOC(self->array, new_capacity * self->obj_size); - if (!new_array) { - return C_ERR_NOMEM; +c_err_t c_ArrayList_Resize(c_ArrayList_t* self, c_size_t new_capacity) { + if (!self) return C_ERR_PARAM; + // 情况 1: 如果新旧容量完全相同,无需任何操作,直接返回成功 + if (new_capacity == self->capacity) { + return C_ERR_OK; + } + // 情况 2: 如果新容量为 0,等同于清空并释放内部数据缓冲区 + if (new_capacity==0) { + if (self->array) { + c_Allocator_Free(&self->allocator, self->array); + self->array = NULL; } - self->array = new_array; - self->capacity = new_capacity; + self->capacity = 0; + self->size = 0; + return C_ERR_OK; } - // 計算目標記憶體地址並將物件內容複製進去 - char* target_addr = (char*)self->array + (self->size * self->obj_size); - memcpy(target_addr, obj, self->obj_size); + // 溢出检查:防止 new_capacity * item_size 导致乘法回绕引发堆破坏 + if (new_capacity > (c_size_t)-1 / self->item_size) { + return C_ERR_OUTOFBOUND; + } + const c_size_t old_bytes = self->capacity * self->item_size; + const c_size_t new_bytes = new_capacity * self->item_size; + + // 调用绑定的自定义/伙伴系统 Realloc 接口 + void* new_array = c_Allocator_Realloc(&self->allocator, self->array, old_bytes, new_bytes); + if (!new_array) { + return C_ERR_NOMEM; // 内存分配失败,保持原有状态不变(强异常安全性) + } + + // 更新内部状态 + self->array = new_array; + self->capacity = new_capacity; + + // 安全边界截断:如果新容量调小了,且当前已有元素数量超过了新容量,则被迫截断 + if (self->size > new_capacity) { + self->size = new_capacity; + } + + return C_ERR_OK; +} + +c_err_t c_ArrayList_Add(c_ArrayList_t* self, const void* item) { + if (!self || !item) return C_ERR_PARAM; + if (self->size>=self->capacity) { + c_err_t err = c_ArrayList_Resize(self, (self->capacity==0)?4:(self->capacity<<1)); + if (err!=C_ERR_OK) return err; + } + char* target = (char*)self->array + (self->size * self->item_size); + memcpy(target, item, self->item_size); self->size++; return C_ERR_OK; } -void* c_ArrayList_Get(c_ArrayList_t* self, c_size_t index) { - if (!self || !self->array || index >= self->size) { - return NULL; - } - // 回傳內部記憶體塊中該元素的實際起始地址 - return (char*)self->array + (index * self->obj_size); +void* c_ArrayList_Get(const c_ArrayList_t* self, c_size_t index) { + if (!self || index>=self->size) return NULL; + return (uint8_t*)self->array + (index * self->item_size); } -c_err_t c_ArrayList_Remove(c_ArrayList_t* self, c_size_t index) { - if (!self || !self->array) return C_ERR_PARAM; - if (index >= self->size) return C_ERR_OUTOFBOUND; - - // 如果刪除的不是最後一個元素,需要將後方所有物件往前平移一個單位 - if (index < self->size - 1) { - char* dest = (char*)self->array + (index * self->obj_size); - const char* src = dest + self->obj_size; - const c_size_t num_elements_to_move = self->size - index - 1; - - // 使用 memmove 處理重疊記憶體區塊的複製 - memmove(dest, src, num_elements_to_move * self->obj_size); +c_err_t c_ArrayList_Read(const c_ArrayList_t* self, c_size_t index, void* out_item) { + if (!self || index >= self->size) { + return C_ERR_PARAM; } - self->size--; + // 计算内部源数据的绝对物理字节地址 + const char* source = (const char*)self->array + (index * self->item_size); - // 策略:当实际大小少于等于容量的 1/4,且缩容后的容量不低于设定的最小阈值时触发 - if (self->size > 0 && self->size <= (self->capacity >> 2)) { - c_size_t new_capacity = self->capacity >> 1; // 容量减半 - void* new_array = C_REALLOC(self->array, new_capacity * self->obj_size); - if (new_array) { // 如果 realloc 失败不影响原有数据安全,这里采用安全赋值 - self->array = new_array; - self->capacity = new_capacity; - } + // 将底层数据值深度拷贝(复制)到用户提供的缓冲区中 + if (out_item) { + memcpy(out_item, source, self->item_size); } - return C_ERR_OK; } +c_err_t c_ArrayList_Remove(c_ArrayList_t* self, c_size_t index, void* out_item) { + if (!self || index>=self->size) return C_ERR_PARAM; + char* target = (char*)self->array + (index * self->item_size); + + if (out_item) { + memcpy(out_item, target, self->item_size); + } + + if (index < self->size - 1) { + char* next = target + self->item_size; + c_size_t move_bytes = (self->size - index - 1) * self->item_size; + memmove(target, next, move_bytes); + } + + self->size--; + return C_ERR_OK; +} diff --git a/Foundation/c_ArrayList.h b/Foundation/c_ArrayList.h index 74e30d3..1b042aa 100644 --- a/Foundation/c_ArrayList.h +++ b/Foundation/c_ArrayList.h @@ -5,32 +5,44 @@ #include #endif /*INCLUDED_C_TYPES_H*/ +#ifndef INCLUDED_C_ALLOCATOR_H +#include +#endif /*INCLUDED_C_ALLOCATOR_H*/ + + /* ------------------------------------------------------------------------------------------------------------------ */ /* */ - typedef struct { void* array; - int obj_size; + c_size_t item_size; c_size_t capacity; c_size_t size; + c_Allocator_t allocator; }c_ArrayList_t; -#define c_ArrayList(obj_size) ((c_ArrayList_t) { 0, (obj_size), 0, 0 }) - /* ------------------------------------------------------------------------------------------------------------------ */ /* */ -c_err_t c_ArrayList_Init(c_ArrayList_t* self, c_size_t obj_size, c_size_t capacity); +c_err_t c_ArrayList_Init(c_ArrayList_t *self, c_size_t item_size, c_size_t capacity, c_Allocator_t *allocator); void c_ArrayList_Destroy(c_ArrayList_t* self); -c_err_t c_ArrayList_Add(c_ArrayList_t* self, void* obj); +c_err_t c_ArrayList_Resize(c_ArrayList_t* self, c_size_t new_capacity); -void* c_ArrayList_Get(c_ArrayList_t* self, c_size_t index); +c_err_t c_ArrayList_Add(c_ArrayList_t* self, const void* item); -c_err_t c_ArrayList_Remove(c_ArrayList_t* self, c_size_t index); +void* c_ArrayList_Get(const c_ArrayList_t* self, c_size_t index); +c_err_t c_ArrayList_Read(const c_ArrayList_t* self, c_size_t index, void* out_item); + +c_err_t c_ArrayList_Remove(c_ArrayList_t* self, c_size_t index, void* out_item); + +C_STATIC_FORCE_INLINE +c_size_t c_ArrayList_Size(const c_ArrayList_t* self) { + if (!self) return 0; + return self->size; +} #endif /*INCLUDED_C_ARRAYLIST_H*/ diff --git a/Foundation/c_ArrayList.t.c b/Foundation/c_ArrayList.t.c index acab6fb..7e4d34c 100644 --- a/Foundation/c_ArrayList.t.c +++ b/Foundation/c_ArrayList.t.c @@ -3,154 +3,250 @@ #include #include -struct Vector2D { - double u, v; -}; +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ -/* ============================================================================== - * 🧪 测试全新通用 void* 缓冲区的初始化、自动扩容与随机 Remove 重排全周期行为 - * ============================================================================== */ -TEST_CASE(test_array_list_full_lifecycle_and_removal) -{ +typedef struct { + size_t active_allocations; + size_t total_alloc_bytes; + size_t total_free_bytes; + size_t realloc_calls; + size_t realloc_in_place_count; // 记录有多少次 Realloc 实现了就地复用(模拟伙伴系统) +} TestMemoryTracker_t; + +static TestMemoryTracker_t g_tracker = {0}; + +static size_t mock_buddy_power_of_two(size_t size) { + if (size == 0) return 0; + size_t p = 1; + while (p < size) p <<= 1; + return p; +} + +static void* test_alloc(size_t size, void* ctx) { + TestMemoryTracker_t* tracker = (TestMemoryTracker_t*)ctx; + if (tracker) { + tracker->active_allocations++; + tracker->total_alloc_bytes += size; + } + return malloc(size); +} +static void test_free(void* ptr, void* ctx) { + TestMemoryTracker_t* tracker = (TestMemoryTracker_t*)ctx; + if (ptr && tracker) { + tracker->active_allocations--; + } + free(ptr); +} + +static void* test_realloc(void* ptr, size_t old_size, size_t new_size, void* ctx) { + TestMemoryTracker_t* tracker = (TestMemoryTracker_t*)ctx; + if (tracker) tracker->realloc_calls++; + + if (new_size == 0) { + test_free(ptr, ctx); + if (tracker) tracker->total_free_bytes += old_size; + return NULL; + } + + if (!ptr) { + return test_alloc(new_size, ctx); + } + + // 【模拟伙伴系统核心逻辑】:如果新旧大小落在同一个 2 的幂阶数区间,则直接原地返回,零搬迁! + size_t old_buddy = mock_buddy_power_of_two(old_size); + size_t new_buddy = mock_buddy_power_of_two(new_size); + + if (old_buddy == new_buddy && old_buddy != 0) { + if (tracker) tracker->realloc_in_place_count++; + return ptr; + } + + // 阶数改变,模拟搬迁 + void* new_ptr = malloc(new_size); + if (!new_ptr) return NULL; + + size_t copy_size = (old_size < new_size) ? old_size : new_size; + memcpy(new_ptr, ptr, copy_size); + free(ptr); + + if (tracker) { + tracker->total_alloc_bytes += new_size; + tracker->total_free_bytes += old_size; + } + return new_ptr; +} + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +// 供 RUN_TEST_FIXTURE 使用的 Setup 和 Teardown 钩子 +static void custom_allocator_setup(void) { + memset(&g_tracker, 0, sizeof(TestMemoryTracker_t)); +} + +static void custom_allocator_teardown(void) { + // 每次测试结束,严格确保没有发生内存泄漏 + // 注意:不能在此处直接调用带有返回的断言,因为破坏了测试函数的封装,仅在内部测试中做二次校验或由测试用例本身断言。 +} + + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +typedef struct { + int node_id; + float threshold; + char name[16]; +} SensorNode_t; + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +// 测试一:基础生命周期与边界防御测试 +TEST_CASE(test_lifecycle_and_defense) { c_ArrayList_t list; - /* 1. 初始化:装载自定义 Vector2D 结构体,初始最大可容纳元素数量卡死限制为 2 */ - c_err_t init_err = c_ArrayList_Init(&list, sizeof(struct Vector2D), 2); - ASSERT_INT_EQ_MSG(init_err, C_ERR_OK, "弹性自愈 ArrayList 初始化成功"); - ASSERT_INT_EQ_MSG(list.size, 0, "有效初始记录必须为 0"); - struct Vector2D vec1 = { 11.1, 22.2 }; - struct Vector2D vec2 = { 33.3, 44.4 }; - struct Vector2D vec3 = { 55.5, 66.6 }; + // 防御测试:无效参数传入 + ASSERT_INT_EQ_MSG(C_ERR_PARAM, c_ArrayList_Init(NULL, sizeof(int), 4, NULL), "Should return C_ERR_PARAM when self is NULL"); + ASSERT_INT_EQ_MSG(C_ERR_PARAM, c_ArrayList_Init(&list, 0, 4, NULL), "Should return C_ERR_PARAM when item_size is 0"); + ASSERT_INT_EQ(0, c_ArrayList_Size(NULL)); - /* 2. 连续推入数据 */ - c_ArrayList_Add(&list, &vec1); - c_ArrayList_Add(&list, &vec2); + // 正常原地初始化 + c_err_t err = c_ArrayList_Init(&list, sizeof(int), 5, NULL); + ASSERT_INT_EQ(C_SUCCESS, err); + ASSERT_INT_EQ(0, c_ArrayList_Size(&list)); + ASSERT_INT_EQ(5, list.capacity); + ASSERT_PTR_NOT_NULL(list.array); - /* 🎯 扩容看点:此时满员,第三次写入将强行逼迫池子在内部启动 2 -> 4 自动翻倍重分配 */ - c_err_t add_err = c_ArrayList_Add(&list, &vec3); - ASSERT_INT_EQ_MSG(add_err, C_ERR_OK, "耗尽时追加写入,分配器必须完成全自动无感自愈扩容"); - ASSERT_INT_EQ_MSG(list.size, 3, "当前有效装载数递增至 3"); + // 销毁幂等性与清除检查 + c_ArrayList_Destroy(&list); + ASSERT_TRUE(list.array == NULL); + ASSERT_INT_EQ(0, list.capacity); + ASSERT_INT_EQ(0, list.size); - /* 3. 验证数据内容的物理隔离完整度 */ - struct Vector2D* p_check1 = (struct Vector2D*)c_ArrayList_Get(&list, 1); - ASSERT_MSG(p_check1 != NULL, "随机读取索引 1 节点成功"); - ASSERT_DOUBLE_EQ_MSG(p_check1->u, 33.3, "重分配内存迁移后,原有位置 1 的数据必须毫发无损"); + c_ArrayList_Destroy(&list); // 重复销毁不应崩溃 +} - /* 4. 🛠️ 高能测试点:随机抹除中间位置 1 的节点 (即删掉 vec2) - 预期结果:原位置 2 的 vec3 ({55.5, 66.6}) 必须在 O(N) 速度下向前平移,填补顶替空位 1 */ - c_err_t remove_err = c_ArrayList_Remove(&list, 1); - ASSERT_INT_EQ_MSG(remove_err, C_ERR_OK, "执行中途位置随机移除成功"); - ASSERT_INT_EQ_MSG(list.size, 2, "移除数据后,有效数据计数平滑扣减为 2"); +// 测试二:泛型值复制存储、安全 Read/Get 访问测试 +TEST_CASE(test_value_copy_and_access) { + c_ArrayList_t list; + c_ArrayList_Init(&list, sizeof(SensorNode_t), 2, NULL); - /* 5. 终极完整性断言:现在去 Get 原本的位置 1 */ - struct Vector2D* p_relocated = (struct Vector2D*)c_ArrayList_Get(&list, 1); - ASSERT_MSG(p_relocated != NULL, "重新获取平移顶替后的位置 1 节点成功"); + SensorNode_t node1 = { .node_id = 101, .threshold = 45.2f, .name = "Temp01" }; + SensorNode_t node2 = { .node_id = 102, .threshold = 12.8f, .name = "Humid02" }; - /* 核心断言:原位置 2 的数据现在必须完美出现在位置 1 线上,且精度不发生移位错乱! */ - ASSERT_DOUBLE_EQ_MSG(p_relocated->u, 55.5, "元素向前滑动对齐后,浮点特征完好无损"); - ASSERT_DOUBLE_EQ_MSG(p_relocated->v, 66.6, "元素向前滑动对齐后,浮点特征完好无损"); + // 写入测试 + ASSERT_INT_EQ(C_SUCCESS, c_ArrayList_Add(&list, &node1)); + ASSERT_INT_EQ(C_SUCCESS, c_ArrayList_Add(&list, &node2)); + ASSERT_INT_EQ(2, c_ArrayList_Size(&list)); - /* 6. 边界越界捕获安全防御线 */ - void* invalid_ptr = c_ArrayList_Get(&list, 2); /* 此时由于删了一个,索引 2 已变为空旷越界区 */ - ASSERT_MSG(invalid_ptr == NULL, "越界获取已经被逻辑截断删除的位置必须安全回传 NULL"); + // 强隔离隔离性检查:修改外部临时变量,内部数据不应被污染 + node1.node_id = 999; + + // 1. 测试 c_ArrayList_Read 拷出副本能力 + SensorNode_t read_buffer; + ASSERT_INT_EQ(C_SUCCESS, c_ArrayList_Read(&list, 0, &read_buffer)); + ASSERT_INT_EQ(101, read_buffer.node_id); // 应该依旧是原值 101 + ASSERT_DOUBLE_EQ_MSG(45.2f, read_buffer.threshold, "Float precision checking"); + ASSERT_TRUE(strcmp(read_buffer.name, "Temp01") == 0); + + // 2. 测试 c_ArrayList_Get 直接指针读取能力 + SensorNode_t* direct_ptr = (SensorNode_t*)c_ArrayList_Get(&list, 1); + ASSERT_PTR_NOT_NULL(direct_ptr); + ASSERT_INT_EQ(102, direct_ptr->node_id); + + // 3. 越界保护检查 + ASSERT_INT_EQ(C_ERR_PARAM, c_ArrayList_Read(&list, 2, &read_buffer)); + ASSERT_TRUE(c_ArrayList_Get(&list, 5) == NULL); c_ArrayList_Destroy(&list); } -static void test_list_auto_expansion() { - int data[] = {10, 20, 30}; +// 测试三:高危内存移动(memmove)及 Remove 位移正确性测试 +TEST_CASE(test_element_removal_and_shifting) { c_ArrayList_t list; - c_ArrayList_Init(&list, sizeof(int), 2); + c_ArrayList_Init(&list, sizeof(int), 5, NULL); - for (int i = 0; i < 3; i++) { - c_ArrayList_Add(&list, &data[i]); + int values[] = {10, 20, 30, 40, 50}; + for(int i = 0; i < 5; i++) { + c_ArrayList_Add(&list, &values[i]); } - // 验证容量是否翻倍 (2 << 1 = 4) - ASSERT_INT_EQ_MSG(4, list.capacity, "Capacity should double to 4"); - ASSERT_INT_EQ_MSG(3, list.size, "Size should be 3"); + // 移除中间的数字 30 (索引 2) 并精准接住拷出值 + int removed_val = 0; + ASSERT_INT_EQ(C_ERR_OK, c_ArrayList_Remove(&list, 2, &removed_val)); + ASSERT_INT_EQ(30, removed_val); + ASSERT_INT_EQ(4, c_ArrayList_Size(&list)); - // 验证最后一个元素有没有因为扩容导致内存搬移出错 - int* p3 = (int*)c_ArrayList_Get(&list, 2); - ASSERT_MSG(p3 != NULL, "Expanded element should be accessible"); - ASSERT_INT_EQ_MSG(30, *p3, "Expanded element data corruption"); + // 极其严苛地检测后面所有元素的向前位移是否对齐正确 + ASSERT_INT_EQ(10, *(int*)c_ArrayList_Get(&list, 0)); + ASSERT_INT_EQ(20, *(int*)c_ArrayList_Get(&list, 1)); + ASSERT_INT_EQ(40, *(int*)c_ArrayList_Get(&list, 2)); // 40 顶替了 30 的位置 + ASSERT_INT_EQ(50, *(int*)c_ArrayList_Get(&list, 3)); // 50 顶替了 40 的位置 + + // 验证静默删除(out_item 为 NULL) + ASSERT_INT_EQ(C_SUCCESS, c_ArrayList_Remove(&list, 0, NULL)); + ASSERT_INT_EQ(20, *(int*)c_ArrayList_Get(&list, 0)); // 20 变成了头元素 + + c_ArrayList_Destroy(&list); } -static void test_list_remove_element() { - int data[] = {11, 22, 33, 44}; +// 测试四:挂载自定义分配器,并验证伙伴系统(Buddy System)的 O(1) 就地复用优化 +TEST_CASE(test_buddy_system_allocator_integration) { + c_Allocator_t buddy_allocator = { + .alloc = test_alloc, + .realloc = test_realloc, + .free = test_free, + .ud = &g_tracker + }; + c_ArrayList_t list; - c_ArrayList_Init(&list, sizeof(int), 2); + // 单个元素 8 字节,初始容量 2。整个缓冲区 = 2 * 8 = 16 字节 + c_ArrayList_Init(&list, 8, 2, &buddy_allocator); - for(int i = 0; i < 4; i++) c_ArrayList_Add(&list, &data[i]); + // 验证 active_allocations 计数 (1控制头由调用者在栈分配,因此分配器内只有 1 个内部数据缓冲区 array) + ASSERT_INT_EQ(1, g_tracker.active_allocations); - // 删除索引为 1 的元素 (即数字 22) - c_err_t err = c_ArrayList_Remove(&list, 1); - ASSERT_INT_EQ_MSG(C_ERR_OK, err, "Remove operational failure"); - ASSERT_INT_EQ_MSG(3, list.size, "Size should decrease to 3"); + // 1. 显式调整容量从 2 -> 3 + // 旧大小 16 字节 (2^4),新大小 24 字节 (向上对齐到 2^5 = 32),阶数改变,模拟真实搬迁 + ASSERT_INT_EQ(C_SUCCESS, c_ArrayList_Resize(&list, 3)); + ASSERT_INT_EQ(0, g_tracker.realloc_in_place_count); // 跨越了幂次墙,没有就地复用 - // 此时索引 1 应该变成了 33,索引 2 应该变成了 44 - int* p1 = (int*)c_ArrayList_Get(&list, 1); - int* p2 = (int*)c_ArrayList_Get(&list, 2); + // 2. 深度契合点:再次调整容量从 3 -> 4 + // 旧大小 24 字节 (2^5 范围内),新大小 32 字节 (刚好跨入 2^5 满额边界) + // 【期望结果】:落在同一阶数内,c_Buddy_Realloc 应当直接 O(1) 返回原指针! + ASSERT_INT_EQ(C_SUCCESS, c_ArrayList_Resize(&list, 4)); + ASSERT_INT_EQ(1, g_tracker.realloc_in_place_count); // 完美!命中伙伴系统就地复用优化次数 1 次 - ASSERT_INT_EQ_MSG(33, *p1, "Element forward-shift error at index 1"); - ASSERT_INT_EQ_MSG(44, *p2, "Element forward-shift error at index 2"); + // 3. 极限截断缩小到 0 + ASSERT_INT_EQ(C_SUCCESS, c_ArrayList_Resize(&list, 0)); + ASSERT_INT_EQ(0, c_ArrayList_Size(&list)); + ASSERT_INT_EQ(0, list.capacity); + ASSERT_TRUE(list.array == NULL); - // 检查获取越界索引是否安全返回 NULL - ASSERT_MSG(c_ArrayList_Get(&list, 3) == NULL, "Out of bounds should return NULL"); + c_ArrayList_Destroy(&list); + + // 验证测试环境有没有发生任何内存泄漏 + ASSERT_INT_EQ_MSG(0, g_tracker.active_allocations, "Memory leak detected inside allocator!"); } -static void test_list_zero_initial_capacity() { - c_ArrayList_t zero_list; - c_ArrayList_Init(&zero_list, sizeof(int), 0); +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ - int val = 99; - // 如果你没有按照上方提示修复缺陷①,该断言将会失败(期望返回 OK 却返回了 PARAM 错误) - c_err_t err = c_ArrayList_Add(&zero_list, &val); - ASSERT_INT_EQ_MSG(C_ERR_OK, err, "Add failed when initial capacity is 0 (Bug ① Triggered!)"); +int main(int argc, char** argv){ - c_ArrayList_Destroy(&zero_list); -} + TEST_START(C_ArrayList_Module_Tests); -static void test_list_auto_shrink() { - // 1. 连续添加 9 个元素触发扩容 - // 初始化 0 -> 扩容到 4 -> 扩容到 8 -> 扩容到 16 - c_ArrayList_t list; - c_ArrayList_Init(&list, sizeof(int), 2); + // 运行常规测试 + RUN_TEST(test_lifecycle_and_defense); + RUN_TEST(test_value_copy_and_access); + RUN_TEST(test_element_removal_and_shifting); - for (int i = 0; i < 9; i++) { - c_ArrayList_Add(&list, &i); - } - ASSERT_INT_EQ_MSG(16, list.capacity, "Capacity should expand up to 16"); - - // 2. 依次删除元素,降低 size 以试图触发 1/4 缩容临界点 - // 当 size 减少到 4 时 (即 16 / 4), 应该触发缩容:16 减半变成 8 - for (int i = 0; i < 5; i++) { - c_ArrayList_Remove(&list, 0); // 总是移除首个元素 - } - - // 此时移除了 5 个,剩下 4 个元素 - ASSERT_INT_EQ_MSG(4, list.size, "Current size should be 4"); - ASSERT_INT_EQ_MSG(8, list.capacity, "Capacity should automatically shrink to 8"); - - // 3. 继续删除,观察是否会由于低于最小阈值(4)而停止缩容 - for (int i = 0; i < 3; i++) { - c_ArrayList_Remove(&list, 0); - } - // 此时只剩 1 个元素了 (1 <= 8/4),但由于 MIN_SHRINK_CAPACITY = 4 限制,容量不应该再减半到 2 - ASSERT_INT_EQ_MSG(1, list.size, "Current size should be 1"); - ASSERT_INT_EQ_MSG(2, list.capacity, "Capacity should hold at 2 to prevent thrashing"); -} - -int main(void) { - TEST_START(BaseArrayListNewSpecificationTestSuite); - - RUN_TEST(test_array_list_full_lifecycle_and_removal); - RUN_TEST(test_list_auto_expansion); - RUN_TEST(test_list_remove_element); - RUN_TEST(test_list_zero_initial_capacity); - RUN_TEST(test_list_auto_shrink); + // 使用 Fixture 模式运行涉及自定义状态追踪的伙伴系统测试 + RUN_TEST_FIXTURE(test_buddy_system_allocator_integration, custom_allocator_setup, custom_allocator_teardown); TEST_REPORT(); + RETURN_TEST_STATUS; } - diff --git a/Foundation/c_ArrayQueue.c b/Foundation/c_ArrayQueue.c index 83a4b67..7f9d15b 100644 --- a/Foundation/c_ArrayQueue.c +++ b/Foundation/c_ArrayQueue.c @@ -1,110 +1,123 @@ #include -#include -#define DEFAULT_INITIAL_CAPACITY 4 -#define MIN_SHRINK_CAPACITY 4 +#define DEFAULT_INIT_CAPACITY 4 -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ +c_err_t c_ArrayQueue_Init(c_ArrayQueue_t* self, c_size_t item_size, c_size_t capacity, c_Allocator_t* allocator) { + if (!self || item_size == 0) return C_ERR_PARAM; -c_err_t c_ArrayQueue_Init(c_ArrayQueue_t* self, int obj_size, c_size_t capacity) { - if (!self || obj_size == 0) return C_ERR_PARAM; - - self->obj_size = obj_size; - self->capacity = (capacity > 0) ? capacity : DEFAULT_INITIAL_CAPACITY; + self->allocator = (allocator != NULL) ? *allocator : c_DefaultAllocator; + self->item_size = item_size; self->size = 0; + self->head = 0; + self->tail = 0; + self->capacity = (capacity > 0) ? capacity : DEFAULT_INIT_CAPACITY; - self->array = C_ALLOC(self->capacity * self->obj_size); - if (!self->array) { - self->capacity = 0; - return C_ERR_NOMEM; - } + self->array = c_Allocator_Alloc(&self->allocator, self->capacity * item_size); + if (!self->array) return C_ERR_NOMEM; return C_ERR_OK; } void c_ArrayQueue_Destroy(c_ArrayQueue_t* self) { if (!self) return; - - C_FREE(self->array); - - self->capacity = 0; + if (self->array) { + c_Allocator_Free(&self->allocator, self->array); + self->array = NULL; + } self->size = 0; - self->obj_size = 0; + self->capacity = 0; + self->head = 0; + self->tail = 0; } -c_err_t c_ArrayQueue_Push(c_ArrayQueue_t* self, void* obj) { - if (!self || !self->array || !obj) return C_ERR_PARAM; +c_err_t c_ArrayQueue_Resize(c_ArrayQueue_t* self, c_size_t new_capacity) { + if (!self || new_capacity < self->size) return C_ERR_PARAM; // 不允许缩容到比当前已有元素还小 - if (self->size >= self->capacity) { - const c_size_t new_capacity = self->capacity << 1; - void* new_array = C_REALLOC(self->array, new_capacity * self->obj_size); - if (!new_array) { - return C_ERR_NOMEM; + if (new_capacity == self->capacity) return C_ERR_OK; + + const c_size_t new_bytes = new_capacity * self->item_size; + + // 1. 先用 Alloc 申请一块干净、独立的全新目标缓冲区 + void* new_array = c_Allocator_Alloc(&self->allocator, new_bytes); + if (!new_array) return C_ERR_NOMEM; + + // 2. 此时旧缓冲区 self->array 100% 安全存活,可以放心读取并执行平整化导出 + if (self->size > 0 && self->array) { + uint8_t* dst = (uint8_t*)new_array; + const uint8_t* src = (const uint8_t*)self->array; + + if (self->head < self->tail) { + // 情况 A: 数据是连续的,没有发生回绕 + memcpy(dst, src + (self->head * self->item_size), self->size * self->item_size); + } else { + // 情况 B: 数据发生了回绕,精准分两段导出到新阵列 + const c_size_t first_part_len = self->capacity - self->head; + const c_size_t second_part_len = self->tail; + + memcpy(dst, src + (self->head * self->item_size), first_part_len * self->item_size); + memcpy(dst + (first_part_len * self->item_size), src, second_part_len * self->item_size); } - self->array = new_array; - self->capacity = new_capacity; } - char* target = (char*)self->array + (self->size * self->obj_size); - memcpy(target, obj, self->obj_size); + // 3. 数据安全倒腾完毕后,显式手工释放旧空间(因为我们第一步用的是 Alloc 而不是 Realloc) + if (self->array) { + c_Allocator_Free(&self->allocator, self->array); + } + + // 4. 更新队列控制头状态 + self->array = new_array; + self->capacity = new_capacity; + self->head = 0; + self->tail = self->size; // 经过平整化铺平,新尾部直接等于已有大小 + + return C_ERR_OK; +} + + +// 内部自动扩容 +C_STATIC_FORCE_INLINE +bool c_ArrayQueue_EnsureCapacity(c_ArrayQueue_t* self) { + if (self->size < self->capacity) return true; + c_size_t new_capacity = self->capacity * 2; + return c_ArrayQueue_Resize(self, new_capacity) == C_ERR_OK; +} + +// 入队 (O(1) 性能,自动触发扩容) +c_err_t c_ArrayQueue_Enqueue(c_ArrayQueue_t* self, const void* item) { + if (!self || !item) return C_ERR_PARAM; + if (!c_ArrayQueue_EnsureCapacity(self)) return C_ERR_NOMEM; + + // 计算尾部插入点并拷贝数据 + uint8_t* target = (uint8_t*)self->array + (self->tail * self->item_size); + memcpy(target, item, self->item_size); + + // 环形推进 tail 指针 + self->tail = (self->tail + 1) % self->capacity; self->size++; - return C_ERR_OK; + return C_SUCCESS; } -c_err_t c_ArrayQueue_Pop(c_ArrayQueue_t* self, void* obj) { - if (!self || !self->array ) return C_ERR_PARAM; - if (self->size == 0) return C_ERR_EMPTY; // 佇列已空 +// 出队 (O(1) 性能,零内存移动开销) +c_err_t c_ArrayQueue_Dequeue(c_ArrayQueue_t* self, void* out_item) { + if (!self || self->size == 0) return C_ERR_PARAM; - char* pop_src = (char*)self->array; // 最前端索引 0 的地址 - - // 1. 直接值複製到呼叫端提供的記憶體中 - if (obj) { - memcpy(obj, pop_src, self->obj_size); - } - - // 2. 如果佇列內還有其他元素,將它們向前平移一個單位 - if (self->size > 1) { - char* dest = pop_src; - const char* src = pop_src + self->obj_size; - const c_size_t num_elements_to_move = self->size - 1; - memmove(dest, src, num_elements_to_move * self->obj_size); + // 找到队头数据源 + uint8_t* source = (uint8_t*)self->array + (self->head * self->item_size); + if (out_item) { + memcpy(out_item, source, self->item_size); } + // 环形推进 head 指针 + self->head = (self->head + 1) % self->capacity; self->size--; - if (self->size > 0 && self->size <= (self->capacity >> 2)) { - c_size_t new_capacity = self->capacity >> 1; // 容量减半 - - void* new_array = C_REALLOC(self->array, new_capacity * self->obj_size); - if (new_array) { // 如果 realloc 失败不影响原有数据安全,这里采用安全赋值 - self->array = new_array; - self->capacity = new_capacity; - } - } - - - return C_ERR_OK; + return C_SUCCESS; } -c_err_t c_ArrayQueue_Remove(c_ArrayQueue_t* self, c_size_t index) { - if (!self || !self->array) return C_ERR_PARAM; - if (index >= self->size) return C_ERR_OUTOFBOUND; - - if (index < self->size - 1) { - char* dest = (char*)self->array + (index * self->obj_size); - const char* src = dest + self->obj_size; - const c_size_t num_elements_to_move = self->size - index - 1; - memmove(dest, src, num_elements_to_move * self->obj_size); - } - - self->size--; - return C_ERR_OK; -} - -void* c_ArrayQueue_Peek(c_ArrayQueue_t* self) { - if (!self || !self->array || self->size == 0) return NULL; - return self->array; // 最前端索引 0 的起始地址即是 array 本身 +// 查看队头元素(不移除) +void* c_ArrayQueue_Peek(const c_ArrayQueue_t* self) { + if (!self || self->size == 0) return NULL; + return (uint8_t*)self->array + (self->head * self->item_size); } diff --git a/Foundation/c_ArrayQueue.h b/Foundation/c_ArrayQueue.h index 012ca81..1788c8a 100644 --- a/Foundation/c_ArrayQueue.h +++ b/Foundation/c_ArrayQueue.h @@ -5,29 +5,46 @@ #include #endif /*INCLUDED_C_TYPES_H*/ +#ifndef INCLUDED_C_ALLOCATOR_H +#include +#endif /*INCLUDED_C_ALLOCATOR_H*/ /* ------------------------------------------------------------------------------------------------------------------ */ /* */ typedef struct { - void* array; - int obj_size; - c_size_t capacity; - c_size_t size; -}c_ArrayQueue_t; + void* array; // 连续的动态环形缓冲区 + c_size_t item_size; // 单个元素的字节大小 + c_size_t capacity; // 环形缓冲区当前最大可承纳的元素容量 + c_size_t size; // 当前队列中已有的元素个数 + c_size_t head; // 指向队头元素的索引 + c_size_t tail; // 指向队尾下一个待插入坑位的索引 + c_Allocator_t allocator; // 绑定的内存管理器(支持自定义/伙伴系统) +} c_ArrayQueue_t; +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ -c_err_t c_ArrayQueue_Init(c_ArrayQueue_t* self, int obj_size, c_size_t capacity); - +c_err_t c_ArrayQueue_Init(c_ArrayQueue_t* self, c_size_t item_size, c_size_t capacity, c_Allocator_t* allocator); void c_ArrayQueue_Destroy(c_ArrayQueue_t* self); -c_err_t c_ArrayQueue_Push(c_ArrayQueue_t* self, void* obj); +// 核心队列操作 API +c_err_t c_ArrayQueue_Enqueue(c_ArrayQueue_t* self, const void* item); +c_err_t c_ArrayQueue_Dequeue(c_ArrayQueue_t* self, void* out_item); +void* c_ArrayQueue_Peek(const c_ArrayQueue_t* self); +c_err_t c_ArrayQueue_Resize(c_ArrayQueue_t* self, c_size_t new_capacity); -c_err_t c_ArrayQueue_Pop(c_ArrayQueue_t* self, void* obj); +// 内联高频辅助接口 +C_STATIC_FORCE_INLINE +c_size_t c_ArrayQueue_Size(const c_ArrayQueue_t* self) { + if (!self) return 0; + return self->size; +} -void* c_ArrayQueue_Peek(c_ArrayQueue_t* self); - -c_err_t c_ArrayQueue_Remove(c_ArrayQueue_t* self, c_size_t index); +C_STATIC_FORCE_INLINE +bool c_ArrayQueue_IsEmpty(const c_ArrayQueue_t* self) { + return c_ArrayQueue_Size(self) == 0; +} #endif /*INCLUDED_C_ARRAYQUEUE_H*/ diff --git a/Foundation/c_ArrayQueue.t.c b/Foundation/c_ArrayQueue.t.c index 8358e69..3ec45fb 100644 --- a/Foundation/c_ArrayQueue.t.c +++ b/Foundation/c_ArrayQueue.t.c @@ -2,150 +2,75 @@ #include #include #include +#include +#include "c_Alignment.h" /* ------------------------------------------------------------------------------------------------------------------ */ /* */ -static c_ArrayQueue_t g_queue; +TEST_CASE(test_queue_basic_operations) { + c_ArrayQueue_t queue; -// 启动环境:初始化一个初始容量为 4 的 int 类型队列 -void setup_queue() { - c_err_t err = c_ArrayQueue_Init(&g_queue, sizeof(int), 4); - if (err != C_ERR_OK) { - printf(" " COLOR_RED "[ERROR] Queue Setup failed!" COLOR_RESET "\n"); - } -} + c_Buddy_t buddy; + uint8_t* backing_buffer = (uint8_t*)malloc(1024); + // 初始化一個 1024 總大小的區塊 + c_Buddy_Init(&buddy, backing_buffer, 1024, C_ALIGN_SIZE); + c_BuddyAllocator_t buddyAllocator; + c_Allocator_t allocator = c_BuddyAllocator_Build(&buddyAllocator, &buddy); -// 清理环境:安全销毁队列 -void teardown_queue() { - c_ArrayQueue_Destroy(&g_queue); -} + // 初始化容量为 3 的整型队列 + ASSERT_INT_EQ(C_SUCCESS, c_ArrayQueue_Init(&queue, sizeof(int), 3, &allocator)); + ASSERT_TRUE(c_ArrayQueue_IsEmpty(&queue)); -// 用例 1:测试常规入队、查看对头、出队(FIFO 基础逻辑) -void test_queue_push_pop_basic() { + // 1. 入队 3 个元素 int v1 = 10, v2 = 20, v3 = 30; + ASSERT_INT_EQ(C_SUCCESS, c_ArrayQueue_Enqueue(&queue, &v1)); + ASSERT_INT_EQ(C_SUCCESS, c_ArrayQueue_Enqueue(&queue, &v2)); + ASSERT_INT_EQ(C_SUCCESS, c_ArrayQueue_Enqueue(&queue, &v3)); + ASSERT_INT_EQ(3, c_ArrayQueue_Size(&queue)); - // 入队 3 个元素 - ASSERT_INT_EQ_MSG(C_ERR_OK, c_ArrayQueue_Push(&g_queue, &v1), "Push 10 failed"); - ASSERT_INT_EQ_MSG(C_ERR_OK, c_ArrayQueue_Push(&g_queue, &v2), "Push 20 failed"); - ASSERT_INT_EQ_MSG(C_ERR_OK, c_ArrayQueue_Push(&g_queue, &v3), "Push 30 failed"); + // 2. 检查 Peek + ASSERT_INT_EQ(10, *(int*)c_ArrayQueue_Peek(&queue)); - // 检查大小 - ASSERT_INT_EQ_MSG(3, g_queue.size, "Size should be 3"); - - // Peek 检查队头(应该依然是 10,且不弹出元素) - int* front_ptr = (int*)c_ArrayQueue_Peek(&g_queue); - ASSERT_MSG(front_ptr != NULL, "Peek should not return NULL"); - ASSERT_INT_EQ_MSG(10, *front_ptr, "Peek value mismatches"); - - // 开始 Pop 出队,验证 FIFO 顺序 + // 3. 出队 1 个元素(此时 head 移动,腾出索引 0 的空间) int out_val = 0; + ASSERT_INT_EQ(C_SUCCESS, c_ArrayQueue_Dequeue(&queue, &out_val)); + ASSERT_INT_EQ(10, out_val); + ASSERT_INT_EQ(2, c_ArrayQueue_Size(&queue)); - ASSERT_INT_EQ_MSG(C_ERR_OK, c_ArrayQueue_Pop(&g_queue, &out_val), "Pop 1 failed"); - ASSERT_INT_EQ_MSG(10, out_val, "First out should be 10"); + // 4. 再次入队,触发环形回绕(tail 绕回到索引 0 处插入) + int v4 = 40; + ASSERT_INT_EQ(C_SUCCESS, c_ArrayQueue_Enqueue(&queue, &v4)); + ASSERT_INT_EQ(3, c_ArrayQueue_Size(&queue)); + ASSERT_INT_EQ(3, queue.capacity); // 刚好填满,未触发扩容 - ASSERT_INT_EQ_MSG(C_ERR_OK, c_ArrayQueue_Pop(&g_queue, &out_val), "Pop 2 failed"); - ASSERT_INT_EQ_MSG(20, out_val, "Second out should be 20"); + // 5. 核心:在“回绕状态下”强行插入第 5 个元素,迫使其触发 EnsureCapacity 扩容与平整化 + int v5 = 50; + ASSERT_INT_EQ(C_SUCCESS, c_ArrayQueue_Enqueue(&queue, &v5)); + ASSERT_INT_EQ(4, c_ArrayQueue_Size(&queue)); + ASSERT_INT_EQ(6, queue.capacity); // 翻倍扩容到了 6 - ASSERT_INT_EQ_MSG(2, g_queue.capacity, "Capacity management check"); // 选测:如果你内部写了 Pop 自动缩容 - ASSERT_INT_EQ_MSG(1, g_queue.size, "Size should drop to 1"); -} + // 6. 严苛校验扩容理顺后的出队顺序是否依然正确 (FIFO) + ASSERT_INT_EQ(C_SUCCESS, c_ArrayQueue_Dequeue(&queue, &out_val)); + ASSERT_INT_EQ(20, out_val); + ASSERT_INT_EQ(C_SUCCESS, c_ArrayQueue_Dequeue(&queue, &out_val)); + ASSERT_INT_EQ(30, out_val); + ASSERT_INT_EQ(C_SUCCESS, c_ArrayQueue_Dequeue(&queue, &out_val)); + ASSERT_INT_EQ(40, out_val); + ASSERT_INT_EQ(C_SUCCESS, c_ArrayQueue_Dequeue(&queue, &out_val)); + ASSERT_INT_EQ(50, out_val); - -// 用例 2:测试队列在空(Empty)或未初始化状态下的防御表现 -void test_queue_empty_bounds() { - int out_val = 999; - - // 空队列直接 Pop 应该报错 - c_err_t err = c_ArrayQueue_Pop(&g_queue, &out_val); - ASSERT_MSG(err != C_ERR_OK, "Pop on empty queue should return an error code"); - ASSERT_INT_EQ_MSG(999, out_val, "Output value should remain untouched on failure"); - - // 空队列 Peek 应该返回 NULL - ASSERT_MSG(c_ArrayQueue_Peek(&g_queue) == NULL, "Peek on empty queue must return NULL"); -} - - -// 用例 3:测试循环环绕与动态扩容(如果是循环队列,该用例极度核心) -void test_queue_wrap_around_and_expand() { - int v = 0; - int out = 0; - - // 1. 先把初始容量 4 填满 - for (int i = 1; i <= 4; i++) { - v = i * 10; // 10, 20, 30, 40 - c_ArrayQueue_Push(&g_queue, &v); - } - - // 2. 弹出 2 个元素(释放前面两个格子的空间,触发头部指针往后移动) - c_ArrayQueue_Pop(&g_queue, &out); // 弹出 10 - c_ArrayQueue_Pop(&g_queue, &out); // 弹出 20 - - // 3. 再次塞入 2 个元素(如果是循环队列,这俩元素会被存到刚才释放的 0 和 1 索引槽位) - v = 50; c_ArrayQueue_Push(&g_queue, &v); - v = 60; c_ArrayQueue_Push(&g_queue, &v); - - // 4. 此时队列满(包含 30, 40, 50, 60),再次 Push 触发扩容 - v = 70; - c_err_t err = c_ArrayQueue_Push(&g_queue, &v); - ASSERT_INT_EQ_MSG(C_ERR_OK, err, "Push triggering growth failed"); - ASSERT_MSG(g_queue.capacity > 4, "Queue failed to expand capacity"); - - // 5. 依次全部弹出,验证即使经历过“环绕”与“扩容搬移内存”,FIFO 序列依旧保持绝对准确 - int expected_sequence[] = {30, 40, 50, 60, 70}; - for (int i = 0; i < 5; i++) { - c_ArrayQueue_Pop(&g_queue, &out); - char msg[100]; - sprintf(msg, "Sequence broke at check-index [%d], expected %d", i, expected_sequence[i]); - ASSERT_INT_EQ_MSG(expected_sequence[i], out, msg); - } -} - - -// 用例 4:测试任意位置删除(c_ArrayQueue_Remove) -void test_queue_remove_by_index() { - int values[] = {100, 200, 300, 400}; - for (int i = 0; i < 4; i++) { - c_ArrayQueue_Push(&g_queue, &values[i]); - } - - // 尝试删除越界索引(当前有 4 个元素,有效索引为 0~3,删除 5 应该失败) - c_err_t err_out = c_ArrayQueue_Remove(&g_queue, 5); - ASSERT_MSG(err_out != C_ERR_OK, "Remove out of bounds should fail"); - - // 删除当前队列中的中间元素(索引 1,即删除 200) - c_err_t err_ok = c_ArrayQueue_Remove(&g_queue, 1); - ASSERT_INT_EQ_MSG(C_ERR_OK, err_ok, "Remove element failed"); - ASSERT_INT_EQ_MSG(3, g_queue.size, "Size should be 3 after removal"); - - // 依次 Pop 验证剩下的元素顺序是否已经平滑前移(应该是 100 -> 300 -> 400) - int out = 0; - - c_ArrayQueue_Pop(&g_queue, &out); - ASSERT_INT_EQ_MSG(100, out, "First element should still be 100"); - - c_ArrayQueue_Pop(&g_queue, &out); - ASSERT_INT_EQ_MSG(300, out, "Element 300 should shift forward to index 1"); - - c_ArrayQueue_Pop(&g_queue, &out); - ASSERT_INT_EQ_MSG(400, out, "Element 400 should shift forward to index 2"); + ASSERT_TRUE(c_ArrayQueue_IsEmpty(&queue)); + c_ArrayQueue_Destroy(&queue); + free(backing_buffer); } /* ------------------------------------------------------------------------------------------------------------------ */ /* */ int main(int argc, char** argv){ - TEST_START(Starting Unit Tests); - - RUN_TEST_FIXTURE(test_queue_push_pop_basic, setup_queue, teardown_queue); - RUN_TEST_FIXTURE(test_queue_empty_bounds, setup_queue, teardown_queue); - RUN_TEST_FIXTURE(test_queue_wrap_around_and_expand, setup_queue, teardown_queue); - RUN_TEST_FIXTURE(test_queue_remove_by_index, setup_queue, teardown_queue); - - // 打印最终统计报告 + TEST_START(C_ArrayQueue_Module_Tests); + RUN_TEST(test_queue_basic_operations); TEST_REPORT(); - RETURN_TEST_STATUS; - - return 0; } diff --git a/Foundation/c_ArrayStack.c b/Foundation/c_ArrayStack.c index f534036..7191f0b 100644 --- a/Foundation/c_ArrayStack.c +++ b/Foundation/c_ArrayStack.c @@ -1,113 +1,106 @@ -#include "c_ArrayStack.h" -#include +#include #define DEFAULT_INITIAL_CAPACITY 4 -c_err_t c_ArrayStack_Init(c_ArrayStack_t* self, int obj_size, c_size_t capacity) { - if (!self || obj_size <= 0) return C_ERR_PARAM; +c_err_t c_ArrayStack_Init(c_ArrayStack_t* self, c_size_t item_size, c_size_t capacity, c_Allocator_t* allocator) { + if (!self || item_size == 0) return C_ERR_PARAM; - self->obj_size = (int)obj_size; + self->allocator = (allocator != NULL) ? *allocator : c_DefaultAllocator; + self->item_size = item_size; self->size = 0; - self->capacity = capacity; + self->capacity = (capacity > 0) ? capacity : DEFAULT_INITIAL_CAPACITY; - if (capacity==0) { + // 为内部连续数据缓冲区分配内存 + self->array = c_Allocator_Alloc(&self->allocator, item_size * self->capacity); + if (!self->array) return C_ERR_NOMEM; + + return C_ERR_OK; +} + +void c_ArrayStack_Destroy(c_ArrayStack_t* self) { + if (!self) return; + if (self->array) { + c_Allocator_Free(&self->allocator, self->array); self->array = NULL; - }else { - self->array = C_ALLOC(self->capacity * self->obj_size); - if (!self->array) { - self->capacity = 0; - return C_ERR_NOMEM; + } + self->size = 0; + self->capacity = 0; +} + +c_err_t c_ArrayStack_Resize(c_ArrayStack_t* self, c_size_t new_capacity) { + if (!self) return C_ERR_PARAM; + if (new_capacity == self->capacity) return C_ERR_OK; + + // 情况 A: 如果新容量为 0,等同于彻底释放内存缓冲区 + if (new_capacity == 0) { + if (self->array) { + c_Allocator_Free(&self->allocator, self->array); + self->array = NULL; } + self->capacity = 0; + self->size = 0; + return C_ERR_OK; + } + + // 防御溢出检查 + if (new_capacity > (c_size_t)-1 / self->item_size) { + return C_ERR_OUTOFBOUND; + } + + const c_size_t old_bytes = self->capacity * self->item_size; + const c_size_t new_bytes = new_capacity * self->item_size; + + // 直接调用闭环的 Realloc(内存管理器已自动处理了数据复制和老物理块释放) + void* new_array = c_Allocator_Realloc(&self->allocator, self->array, old_bytes, new_bytes); + if (!new_array) return C_ERR_NOMEM; + + self->array = new_array; + self->capacity = new_capacity; + + // 缩容安全裁断:如果新容量调得比已有元素还小,强制截断到新容量边界 + if (self->size > new_capacity) { + self->size = new_capacity; } return C_ERR_OK; } - -void c_ArrayStack_Destroy(c_ArrayStack_t* self) { - if (!self) return; - - C_FREE(self->array); - self->capacity = 0; - self->size = 0; - self->obj_size = 0; +C_STATIC_FORCE_INLINE +bool c_ArrayStack_EnsureCapacity(c_ArrayStack_t* self) { + if (self->size < self->capacity) return true; + c_size_t new_capacity = self->capacity * 2; + if (new_capacity == 0) new_capacity = 4; + return c_ArrayStack_Resize(self, new_capacity) == C_ERR_OK; } -c_err_t c_ArrayStack_Push(c_ArrayStack_t* self, void* obj) { - if (!self || !self->array || !obj) return C_ERR_PARAM; +c_err_t c_ArrayStack_Push(c_ArrayStack_t* self, const void* item) { + if (!self || !item) return C_ERR_PARAM; + if (!c_ArrayStack_EnsureCapacity(self)) return C_ERR_NOMEM; - if (self->size >= self->capacity) { - const c_size_t new_capacity = (self->capacity==0)?DEFAULT_INITIAL_CAPACITY:(self->capacity<<1); - void* new_array = C_REALLOC(self->array, new_capacity * self->obj_size); - if (!new_array) { - return C_ERR_NOMEM; - } - self->array = new_array; - self->capacity = new_capacity; - } - - // 計算頂端目標記憶體地址並寫入資料 - char* target = (char*)self->array + (self->size * self->obj_size); - memcpy(target, obj, self->obj_size); + // 计算当前栈顶的物理指针坑位并直接拷贝进去 + char* target = (char*)self->array + (self->size * self->item_size); + memcpy(target, item, self->item_size); self->size++; return C_ERR_OK; } -c_err_t c_ArrayStack_Pop(c_ArrayStack_t* self, void* obj) { - if (!self || !self->array || !obj) return C_ERR_PARAM; - if (self->size == 0) return C_ERR_EMPTY; // 堆疊已空 +c_err_t c_ArrayStack_Pop(c_ArrayStack_t* self, void* out_item) { + if (!self || self->size == 0) return C_ERR_OUTOFBOUND; - // 取得位於 size - 1 的堆疊頂端元素地址 - const char* pop_src = (char*)self->array + ((self->size - 1) * self->obj_size); - - // 直接複製到呼叫端提供的記憶體中 - memcpy(obj, pop_src, self->obj_size); - - self->size--; - - if (self->size > 0 && self->size <= (self->capacity >> 2)) { - c_size_t new_capacity = self->capacity >> 1; - void* new_array = C_REALLOC(self->array, new_capacity * self->obj_size); - if (new_array) { - self->array = new_array; - self->capacity = new_capacity; - } + self->size--; // 先缩减栈顶 + if (out_item) { + // 找到被退栈的数据源并向外拷贝快照 + const char* source = (const char*)self->array + (self->size * self->item_size); + memcpy(out_item, source, self->item_size); } return C_ERR_OK; } -void* c_ArrayStack_Peek(c_ArrayStack_t* self) { - if (!self || !self->array || self->size == 0) return NULL; - return (char*)self->array + ((self->size - 1) * self->obj_size); +void* c_ArrayStack_Peek(const c_ArrayStack_t* self) { + if (!self || self->size == 0) return NULL; + // 栈顶元素处于索引 size - 1 的坑位 + return (char*)self->array + ((self->size - 1) * self->item_size); } -c_err_t c_ArrayStack_Remove(c_ArrayStack_t* self, c_size_t index) { - if (!self || !self->array) return C_ERR_PARAM; - if (index >= self->size) return C_ERR_OUTOFBOUND; - - // 如果刪除的不是頂端元素,則後續元素需向前平移一個單位 - if (index < self->size - 1) { - char* dest = (char*)self->array + (index * self->obj_size); - const char* src = dest + self->obj_size; - const c_size_t num_elements_to_move = self->size - index - 1; - memmove(dest, src, num_elements_to_move * self->obj_size); - } - - self->size--; - - if (self->size > 0 && self->size <= (self->capacity >> 2)) { - c_size_t new_capacity = self->capacity >> 1; - void* new_array = C_REALLOC(self->array, new_capacity * self->obj_size); - if (new_array) { - self->array = new_array; - self->capacity = new_capacity; - } - } - - return C_ERR_OK; -} - - - diff --git a/Foundation/c_ArrayStack.h b/Foundation/c_ArrayStack.h index e33b6cf..9207253 100644 --- a/Foundation/c_ArrayStack.h +++ b/Foundation/c_ArrayStack.h @@ -5,28 +5,41 @@ #include #endif /*INCLUDED_C_TYPES_H*/ +#ifndef INCLUDED_C_ALLOCATOR_H +#include +#endif /*INCLUDED_C_ALLOCATOR_H*/ + /* ------------------------------------------------------------------------------------------------------------------ */ /* */ - typedef struct { - void* array; - int obj_size; - c_size_t capacity; - c_size_t size; + void* array; // 连续的数据存储区(直接存储数据值) + c_size_t item_size; // 单个元素的字节大小(例如 sizeof(int)) + c_size_t capacity; // 当前栈的最大可容纳容量 + c_size_t size; // 当前栈内的元素个数(同时也是下一个入栈元素的索引位置) + c_Allocator_t allocator; // 绑定的内存管理器 } c_ArrayStack_t; -c_err_t c_ArrayStack_Init(c_ArrayStack_t* self, int obj_size, c_size_t capacity); +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +c_err_t c_ArrayStack_Init(c_ArrayStack_t* self, c_size_t item_size, c_size_t capacity, c_Allocator_t* allocator); void c_ArrayStack_Destroy(c_ArrayStack_t* self); -c_err_t c_ArrayStack_Push(c_ArrayStack_t* self, void* obj); -c_err_t c_ArrayStack_Pop(c_ArrayStack_t* self, void* obj); -void* c_ArrayStack_Peek(c_ArrayStack_t* self); -c_err_t c_ArrayStack_Remove(c_ArrayStack_t* self, c_size_t index); +c_err_t c_ArrayStack_Resize(c_ArrayStack_t* self, c_size_t new_capacity); +c_err_t c_ArrayStack_Push(c_ArrayStack_t* self, const void* item); +c_err_t c_ArrayStack_Pop(c_ArrayStack_t* self, void* out_item) ; +void* c_ArrayStack_Peek(const c_ArrayStack_t* self); C_STATIC_FORCE_INLINE -c_bool_t c_ArrayStack_IsEmpty(c_ArrayStack_t* self) { - return self->size == 0; +c_size_t c_ArrayStack_Size(const c_ArrayStack_t* self) { + if (!self) return 0; + return self->size; +} + +C_STATIC_FORCE_INLINE +bool c_ArrayStack_IsEmpty(const c_ArrayStack_t* self) { + return c_ArrayStack_Size(self) == 0; } #endif /*INCLUDED_C_ARRAYSTACK_H*/ diff --git a/Foundation/c_ArrayStack.t.c b/Foundation/c_ArrayStack.t.c index 46d3191..5a55642 100644 --- a/Foundation/c_ArrayStack.t.c +++ b/Foundation/c_ArrayStack.t.c @@ -1,152 +1,53 @@ #include "c_ArrayStack.h" -#include -#include #include -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ -static c_ArrayStack_t g_stack; +TEST_CASE(test_stack_basic_flow) { + c_ArrayStack_t stack; -// 启动环境:初始化一个初始容量为 2 的 int 类型栈 -static void setup_stack() { - c_err_t err = c_ArrayStack_Init(&g_stack, sizeof(int), 2); - if (err != C_ERR_OK) { - printf(" " COLOR_RED "[ERROR] Stack Setup failed!" COLOR_RESET "\n"); - } + // 初始化一个基础容量为 2 的双精度浮点数(double)栈 + ASSERT_INT_EQ(C_ERR_OK, c_ArrayStack_Init(&stack, sizeof(double), 2, NULL)); + ASSERT_TRUE(c_ArrayStack_IsEmpty(&stack)); + + // 1. 入栈测试 (Push) + double d1 = 3.1415, d2 = 2.7182, d3 = 1.4142; + ASSERT_INT_EQ(C_ERR_OK, c_ArrayStack_Push(&stack, &d1)); + ASSERT_INT_EQ(C_ERR_OK, c_ArrayStack_Push(&stack, &d2)); + ASSERT_INT_EQ(2, c_ArrayStack_Size(&stack)); + + // 2. 触发自动扩容测试 (EnsureCapacity) + ASSERT_INT_EQ(C_ERR_OK, c_ArrayStack_Push(&stack, &d3)); // 触发 2 -> 4 扩容 + ASSERT_INT_EQ(3, c_ArrayStack_Size(&stack)); + ASSERT_INT_EQ(4, stack.capacity); + + // 3. 栈顶窥探测试 (Peek) + double* top_ptr = (double*)c_ArrayStack_Peek(&stack); + ASSERT_PTR_NOT_NULL(top_ptr); + ASSERT_DOUBLE_EQ_MSG(1.4142, *top_ptr, "Peek should fetch the latest pushed element"); + + // 4. 出栈逻辑与先进后出顺序校验 (Pop) + double out_val = 0.0; + + ASSERT_INT_EQ(C_ERR_OK, c_ArrayStack_Pop(&stack, &out_val)); + ASSERT_DOUBLE_EQ_MSG(1.4142, out_val, "LIFO Verification Part 1"); + + ASSERT_INT_EQ(C_ERR_OK, c_ArrayStack_Pop(&stack, &out_val)); + ASSERT_DOUBLE_EQ_MSG(2.7182, out_val, "LIFO Verification Part 2"); + + ASSERT_INT_EQ(C_ERR_OK, c_ArrayStack_Pop(&stack, &out_val)); + ASSERT_DOUBLE_EQ_MSG(3.1415, out_val, "LIFO Verification Part 3"); + + // 5. 空栈防护与下溢判定 + ASSERT_TRUE(c_ArrayStack_IsEmpty(&stack)); + ASSERT_INT_EQ(C_ERR_OUTOFBOUND, c_ArrayStack_Pop(&stack, &out_val)); + ASSERT_TRUE(c_ArrayStack_Peek(&stack) == NULL); + + c_ArrayStack_Destroy(&stack); } -// 清理环境:安全销毁栈,杜绝内存泄漏 -static void teardown_stack() { - c_ArrayStack_Destroy(&g_stack); -} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - - -// 用例 1:测试 LIFO(后进先出)核心逻辑、IsEmpty 状态及 Peek 观察 -static void test_stack_push_pop_lifo() { - // 初始状态应该为空 - ASSERT_MSG(c_ArrayStack_IsEmpty(&g_stack) == true, "Stack should be empty initially"); - - int v1 = 111, v2 = 222; - ASSERT_INT_EQ_MSG(C_ERR_OK, c_ArrayStack_Push(&g_stack, &v1), "Push 111 failed"); - ASSERT_INT_EQ_MSG(C_ERR_OK, c_ArrayStack_Push(&g_stack, &v2), "Push 222 failed"); - - // 此时不应该为空,大小应为 2 - ASSERT_MSG(c_ArrayStack_IsEmpty(&g_stack) == false, "Stack should not be empty"); - ASSERT_INT_EQ_MSG(2, g_stack.size, "Stack size should be 2"); - - // 测试 Peek:应该看到最后压入的 222,且栈大小不变 - int* top_ptr = (int*)c_ArrayStack_Peek(&g_stack); - ASSERT_MSG(top_ptr != NULL, "Peek should not return NULL"); - ASSERT_INT_EQ_MSG(222, *top_ptr, "Peek value should be 222"); - ASSERT_INT_EQ_MSG(2, g_stack.size, "Size must remain 2 after peek"); - - // 测试 Pop:验证 LIFO 顺序 - int out_val = 0; - ASSERT_INT_EQ_MSG(C_ERR_OK, c_ArrayStack_Pop(&g_stack, &out_val), "First pop failed"); - ASSERT_INT_EQ_MSG(222, out_val, "First popped value should be 222 (LIFO)"); - - ASSERT_INT_EQ_MSG(C_ERR_OK, c_ArrayStack_Pop(&g_stack, &out_val), "Second pop failed"); - ASSERT_INT_EQ_MSG(111, out_val, "Second popped value should be 111"); - - // 最终应该重新变为空栈 - ASSERT_MSG(c_ArrayStack_IsEmpty(&g_stack) == true, "Stack should be empty after popping all elements"); -} - - -// 用例 2:测试空栈(Empty)的边界防御表现 -static void test_stack_empty_bounds() { - int dummy = 999; - - // 空栈执行 Pop 应该安全报错(例如返回 C_ERR_EMPTY 或非 OK 状态) - c_err_t err = c_ArrayStack_Pop(&g_stack, &dummy); - ASSERT_MSG(err != C_ERR_OK, "Pop on empty stack should return an error code"); - ASSERT_INT_EQ_MSG(999, dummy, "Output buffer should remain unchanged on failure"); - - // 空栈执行 Peek 应该安全返回 NULL - ASSERT_MSG(c_ArrayStack_Peek(&g_stack) == NULL, "Peek on empty stack must return NULL"); -} - - -// 用例 3:动态自动扩容测试 -static void test_stack_auto_expansion() { - // 初始容量设为了 2,连续压入 4 个数据触发自动扩容 - for (int i = 1; i <= 4; i++) { - int val = i * 10; - c_err_t err = c_ArrayStack_Push(&g_stack, &val); - char msg[64]; - sprintf(msg, "Pushing element %d failed", val); - ASSERT_INT_EQ_MSG(C_ERR_OK, err, msg); - } - - // 校验容量是否增长 - ASSERT_MSG(g_stack.capacity > 2, "Stack capacity should have grown"); - ASSERT_INT_EQ_MSG(4, g_stack.size, "Stack size should be 4"); - - // 倒序弹出校验,确保扩容重构内存后历史数据未损坏 - int out_val = 0; - int expected_vals[] = {40, 30, 20, 10}; - for (int i = 0; i < 4; i++) { - c_ArrayStack_Pop(&g_stack, &out_val); - char msg[64]; - sprintf(msg, "Mismatched LIFO element at step %d", i); - ASSERT_INT_EQ_MSG(expected_vals[i], out_val, msg); - } -} - - -// 用例 4:测试从任意指定索引删除元素(c_ArrayStack_Remove) -static void test_stack_remove_by_index() { - // 压入底 -> 顶:10, 20, 30, 40 - // 索引映射:index 0 -> 10, index 1 -> 20, index 2 -> 30, index 3 -> 40 - for (int i = 1; i <= 4; i++) { - int val = i * 10; - c_ArrayStack_Push(&g_stack, &val); - } - - // 1. 测试越界删除防御(有效索引为 0~3) - c_err_t err_invalid = c_ArrayStack_Remove(&g_stack, 4); - ASSERT_MSG(err_invalid != C_ERR_OK, "Remove out of bounds should fail"); - - // 2. 删除中间的元素:索引 1 (对应数字 20) - c_err_t err_ok = c_ArrayStack_Remove(&g_stack, 1); - ASSERT_INT_EQ_MSG(C_ERR_OK, err_ok, "Remove middle element failed"); - ASSERT_INT_EQ_MSG(3, g_stack.size, "Size should drop to 3 after remove"); - - // 3. 验证删除后的整体结构。由于移除了 20,剩下的数组结构应为:10, 30, 40 - // 按照栈的 LIFO 弹出顺序,依次拿到的应该是 40 -> 30 -> 10 - int out_val = 0; - - c_ArrayStack_Pop(&g_stack, &out_val); - ASSERT_INT_EQ_MSG(40, out_val, "Top should still be 40"); - - c_ArrayStack_Pop(&g_stack, &out_val); - ASSERT_INT_EQ_MSG(30, out_val, "Next should be 30 (since 20 was removed)"); - - c_ArrayStack_Pop(&g_stack, &out_val); - ASSERT_INT_EQ_MSG(10, out_val, "Bottom element should be 10"); -} - - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -int main(int argc, char** argv){ - - TEST_START(Starting Unit Tests); - - // 运行需要内存环境的用例 - RUN_TEST_FIXTURE(test_stack_push_pop_lifo, setup_stack, teardown_stack); - RUN_TEST_FIXTURE(test_stack_empty_bounds, setup_stack, teardown_stack); - RUN_TEST_FIXTURE(test_stack_auto_expansion, setup_stack, teardown_stack); - RUN_TEST_FIXTURE(test_stack_remove_by_index, setup_stack, teardown_stack); - - - // 打印最终统计报告 +int main(void) { + TEST_START(C_ArrayStack_Module_Tests); + RUN_TEST(test_stack_basic_flow); TEST_REPORT(); - RETURN_TEST_STATUS; } diff --git a/Foundation/c_Atomic.c b/Foundation/c_Atomic.c deleted file mode 100644 index e22b7a7..0000000 --- a/Foundation/c_Atomic.c +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/Foundation/c_Atomic.h b/Foundation/c_Atomic.h deleted file mode 100644 index 33edafb..0000000 --- a/Foundation/c_Atomic.h +++ /dev/null @@ -1,147 +0,0 @@ -#ifndef INCLUDED_C_ATOMIC_H -#define INCLUDED_C_ATOMIC_H - -#ifndef INCLUDED_C_TYPES_H -#include -#endif /*INCLUDED_C_TYPES_H*/ - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -#if defined(_MSC_VER) - #include - - // Windows 平台原子型態定義 - typedef volatile char c_atomic_8_t; - typedef volatile long c_atomic_32_t; - typedef volatile __int64 c_atomic_64_t; - typedef volatile int c_atomic_int_t; - typedef void* volatile c_atomic_ptr_t; - typedef volatile char c_atomic_bool_t; - - // MSVC 8-Bit (uint8_t/bool) 原子加減法模擬 (利用 CAS 迴圈確保硬體原子性) - static inline char _msvc_atomic_fetch_add_8(volatile char* p, char v) { - char old_val; - do { - old_val = *p; - } while (InterlockedCompareExchange8((volatile char*)p, (char)(old_val + v), old_val) != old_val); - return old_val; - } - - static inline char _msvc_atomic_fetch_sub_8(volatile char* p, char v) { - char old_val; - do { - old_val = *p; - } while (InterlockedCompareExchange8((volatile char*)p, (char)(old_val - v), old_val) != old_val); - return old_val; - } - -#elif defined(__GNUC__) || defined(__clang__) - // GCC/Clang 平台原子型態定義 (與標準 C 原始型態無縫相容) - typedef int8_t c_atomic_8_t; - typedef int32_t c_atomic_32_t; - typedef int64_t c_atomic_64_t; - typedef int c_atomic_int_t; - typedef void* c_atomic_ptr_t; - typedef bool c_atomic_bool_t; - - // GCC/Clang 內建函數自帶全自動型態泛型 - #define _C_ATOMIC_LOAD_ANY(p) __atomic_load_n((p), __ATOMIC_SEQ_CST) - #define _C_ATOMIC_ADD_ANY(p, v) __atomic_fetch_add((p), (v), __ATOMIC_SEQ_CST) - #define _C_ATOMIC_SUB_ANY(p, v) __atomic_fetch_sub((p), (v), __ATOMIC_SEQ_CST) - #define _C_ATOMIC_EXCH_ANY(p, v) __atomic_exchange_n((p), (v), __ATOMIC_SEQ_CST) - -#else - #error "當前編譯器環境不支援硬體級跨平台原子操作!" -#endif - -/* ================================================================================================================== */ -/* 2. 強型態的特化 API 提供 */ - -#define c_atomic_init_8(p, v) (*(p) = (v)) -#define c_atomic_init_32(p, v) (*(p) = (v)) -#define c_atomic_init_64(p, v) (*(p) = (v)) -#define c_atomic_init_int(p, v) (*(p) = (v)) -#define c_atomic_init_ptr(p, v) (*(p) = (v)) -#define c_atomic_init_bool(p, v) (*(p) = (v)) - -#ifdef _MSC_VER - // ---- 8-Bit (uint8_t) ---- - #define c_atomic_load_8(p) InterlockedCompareExchange8((volatile char*)(p), 0, 0) - #define c_atomic_fetch_add_8(p, v) _msvc_atomic_fetch_add_8((volatile char*)(p), (char)(v)) - #define c_atomic_fetch_sub_8(p, v) _msvc_atomic_fetch_sub_8((volatile char*)(p), (char)(v)) - // ---- 32-Bit ---- - #define c_atomic_load_32(p) InterlockedCompareExchange((volatile LONG*)(p), 0, 0) - #define c_atomic_fetch_add_32(p, v) InterlockedExchangeAdd((volatile LONG*)(p), (LONG)(v)) - #define c_atomic_fetch_sub_32(p, v) InterlockedExchangeAdd((volatile LONG*)(p), -(LONG)(v)) - // ---- 64-Bit ---- - #define c_atomic_load_64(p) InterlockedCompareExchange64((volatile LONG64*)(p), 0, 0) - #define c_atomic_fetch_add_64(p, v) InterlockedExchangeAdd64((volatile LONG64*)(p), (LONGLONG)(v)) - #define c_atomic_fetch_sub_64(p, v) InterlockedExchangeAdd64((volatile LONG64*)(p), -(LONGLONG)(v)) - // ---- Pointer (void*) ---- - #define c_atomic_load_ptr(p) InterlockedCompareExchangePointer((void* volatile*)(p), NULL, NULL) - #define c_atomic_exchange_ptr(p, v) InterlockedExchangePointer((void* volatile*)(p), (void*)(v)) - // ---- Bool ---- - #define c_atomic_load_bool(p) (InterlockedCompareExchange8((volatile char*)(p), 0, 0) != 0) - #define c_atomic_exchange_bool(p, v) (InterlockedExchange8((volatile char*)(p), (char)(v)) != 0) -#else - // GCC/Clang 特化映射(全型態直接套用系統內建泛型,編譯效率極高) - #define c_atomic_load_8(p) _C_ATOMIC_LOAD_ANY(p) - #define c_atomic_fetch_add_8(p, v) _C_ATOMIC_ADD_ANY(p, v) - #define c_atomic_fetch_sub_8(p, v) _C_ATOMIC_SUB_ANY(p, v) - - #define c_atomic_load_32(p) _C_ATOMIC_LOAD_ANY(p) - #define c_atomic_fetch_add_32(p, v) _C_ATOMIC_ADD_ANY(p, v) - #define c_atomic_fetch_sub_32(p, v) _C_ATOMIC_SUB_ANY(p, v) - - #define c_atomic_load_64(p) _C_ATOMIC_LOAD_ANY(p) - #define c_atomic_fetch_add_64(p, v) _C_ATOMIC_ADD_ANY(p, v) - #define c_atomic_fetch_sub_64(p, v) _C_ATOMIC_SUB_ANY(p, v) - - #define c_atomic_load_ptr(p) _C_ATOMIC_LOAD_ANY(p) - #define c_atomic_exchange_ptr(p, v) _C_ATOMIC_EXCH_ANY(p, v) - - #define c_atomic_load_bool(p) _C_ATOMIC_LOAD_ANY(p) - #define c_atomic_exchange_bool(p, v) _C_ATOMIC_EXCH_ANY(p, v) -#endif - -// 原生 Int 動態配適映射 -#define c_atomic_load_int(p) (sizeof(int) == 8 ? (int)c_atomic_load_64((c_atomic_64_t*)(p)) : (int)c_atomic_load_32((c_atomic_32_t*)(p))) -#define c_atomic_fetch_add_int(p, v) (sizeof(int) == 8 ? (int)c_atomic_fetch_add_64((c_atomic_64_t*)(p), v) : (int)c_atomic_fetch_add_32((c_atomic_32_t*)(p), v)) -#define c_atomic_fetch_sub_int(p, v) (sizeof(int) == 8 ? (int)c_atomic_fetch_sub_64((c_atomic_64_t*)(p), v) : (int)c_atomic_fetch_sub_32((c_atomic_32_t*)(p), v)) - -/* ================================================================================================================== */ -/* 3. 全型態 C11 _Generic 萬能泛型巨集分派 */ - -#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L - #define C_ATOMIC_LOAD(p) _Generic(*(p), \ - bool: c_atomic_load_bool((c_atomic_bool_t*)(p)), \ - int8_t: c_atomic_load_8((c_atomic_8_t*)(p)), \ - uint8_t: c_atomic_load_8((c_atomic_8_t*)(p)), \ - int32_t: c_atomic_load_32((c_atomic_32_t*)(p)), \ - uint32_t: c_atomic_load_32((c_atomic_32_t*)(p)), \ - int64_t: c_atomic_load_64((c_atomic_64_t*)(p)), \ - uint64_t: c_atomic_load_64((c_atomic_64_t*)(p)), \ - void*: c_atomic_load_ptr((c_atomic_ptr_t*)(p)) \ - ) - - #define C_ATOMIC_FETCH_ADD(p, v) _Generic(*(p), \ - int8_t: c_atomic_fetch_add_8((c_atomic_8_t*)(p), (v)), \ - uint8_t: c_atomic_fetch_add_8((c_atomic_8_t*)(p), (v)), \ - int32_t: c_atomic_fetch_add_32((c_atomic_32_t*)(p), (v)), \ - uint32_t: c_atomic_fetch_add_32((c_atomic_32_t*)(p), (v)), \ - int64_t: c_atomic_fetch_add_64((c_atomic_64_t*)(p), (v)), \ - uint64_t: c_atomic_fetch_add_64((c_atomic_64_t*)(p), (v)) \ - ) - - #define C_ATOMIC_FETCH_SUB(p, v) _Generic(*(p), \ - int8_t: c_atomic_fetch_sub_8((c_atomic_8_t*)(p), (v)), \ - uint8_t: c_atomic_fetch_sub_8((c_atomic_8_t*)(p), (v)), \ - int32_t: c_atomic_fetch_sub_32((c_atomic_32_t*)(p), (v)), \ - uint32_t: c_atomic_fetch_sub_32((c_atomic_32_t*)(p), (v)), \ - int64_t: c_atomic_fetch_sub_64((c_atomic_64_t*)(p), (v)), \ - uint64_t: c_atomic_fetch_sub_64((c_atomic_64_t*)(p), (v)) \ - ) -#endif - -#endif /*INCLUDED_C_ATOMIC_H*/ diff --git a/Foundation/c_ByteRingBuffer.c b/Foundation/c_ByteRingBuffer.c deleted file mode 100644 index 71d1245..0000000 --- a/Foundation/c_ByteRingBuffer.c +++ /dev/null @@ -1,543 +0,0 @@ -#include -#include -#include -#include -#include -#include - - -c_err_t c_ByteRingBuffer_Init(c_ByteRingBuffer_t* self, c_size_t capacity) { - if (!self || capacity == 0) return C_ERR_PARAM; - - self->capacity = capacity; - self->head = 0; - self->tail = 0; - self->is_full = C_FALSE; - - self->buffer = (uint8_t*)C_ALLOC(self->capacity); - if (!self->buffer) { - self->capacity = 0; - return C_ERR_NOMEM; - } - - return C_ERR_OK; -} - -void c_ByteRingBuffer_Destroy(c_ByteRingBuffer_t* self) { - if (!self) return; - - C_FREE(self->buffer); - self->capacity = 0; - self->head = 0; - self->tail = 0; - self->is_full = C_FALSE; -} - -// Writes a single byte. O(1) performance. -c_err_t c_ByteRingBuffer_WriteByte(c_ByteRingBuffer_t* self, uint8_t byte) { - if (!self || !self->buffer) return C_ERR_PARAM; - if (self->is_full) return C_ERR_FULL; - - self->buffer[self->tail] = byte; - self->tail = (self->tail + 1) % self->capacity; - - if (self->tail == self->head) { - self->is_full = C_TRUE; - } - - return C_ERR_OK; -} - -// Reads a single byte. O(1) performance. -c_err_t c_ByteRingBuffer_ReadByte(c_ByteRingBuffer_t* self, uint8_t* out_byte) { - if (!self || !self->buffer || !out_byte) return C_ERR_PARAM; - if (c_ByteRingBuffer_IsEmpty(self)) return C_ERR_EMPTY; - - *out_byte = self->buffer[self->head]; - self->head = (self->head + 1) % self->capacity; - self->is_full = C_FALSE; - - return C_ERR_OK; -} - -// Writes an entire chunk of bytes. Returns the total number of bytes successfully written. -c_size_t c_ByteRingBuffer_WriteBuffer(c_ByteRingBuffer_t* self, const uint8_t* src, c_size_t len) { - if (!self || !self->buffer || !src || len == 0) return 0; - - c_size_t bytes_written = 0; - while (bytes_written < len && !self->is_full) { - self->buffer[self->tail] = src[bytes_written]; - self->tail = (self->tail + 1) % self->capacity; - - if (self->tail == self->head) { - self->is_full = C_TRUE; - } - bytes_written++; - } - return bytes_written; -} - -// Reads an entire chunk of bytes. Returns the total number of bytes successfully read. -c_size_t c_ByteRingBuffer_ReadBuffer(c_ByteRingBuffer_t* self, uint8_t* dest, c_size_t len) { - if (!self || !self->buffer || !dest || len == 0) return 0; - - c_size_t bytes_read = 0; - while (bytes_read < len && !c_ByteRingBuffer_IsEmpty(self)) { - dest[bytes_read] = self->buffer[self->head]; - self->head = (self->head + 1) % self->capacity; - self->is_full = C_FALSE; - bytes_read++; - } - return bytes_read; -} - -c_size_t c_ByteRingBuffer_GetSize(const c_ByteRingBuffer_t* self) { - if (!self || !self->buffer) return 0; - if (self->is_full) return self->capacity; - - if (self->tail >= self->head) { - return self->tail - self->head; - } else { - return self->capacity + self->tail - self->head; - } -} - -c_bool_t c_ByteRingBuffer_IsEmpty(const c_ByteRingBuffer_t* self) { - if (!self) return C_TRUE; - return (self->head == self->tail) && !self->is_full; -} - -c_bool_t c_ByteRingBuffer_IsFull(const c_ByteRingBuffer_t* self) { - if (!self) return C_FALSE; - return self->is_full; -} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -void c_ByteRingBuffer_WriteByteOverwrite(c_ByteRingBuffer_t* self, uint8_t byte) { - if (!self || !self->buffer) return; - - if (self->is_full) { - // Advance head position to discard the oldest item before placing the new data - self->head = (self->head + 1) % self->capacity; - } - - self->buffer[self->tail] = byte; - self->tail = (self->tail + 1) % self->capacity; - - if (self->tail == self->head) { - self->is_full = C_TRUE; - } -} - -c_size_t c_ByteRingBuffer_WriteBufferOverwrite(c_ByteRingBuffer_t* self, const uint8_t* src, c_size_t len) { - if (!self || !self->buffer || !src || len == 0) return 0; - - // Boundary edge-case optimization: If incoming payload exceeds entire capacity, - // only the absolute last subset window matching 'capacity' will survive anyway. - if (len >= self->capacity) { - src += (len - self->capacity); - len = self->capacity; - - // Blindly overwrite entire buffer matrix instantly - memcpy(self->buffer, src, len); - self->head = 0; - self->tail = 0; - self->is_full = C_TRUE; - return len; - } - - c_size_t size = c_ByteRingBuffer_GetSize(self); - c_size_t free_space = self->capacity - size; - - // Track if writing this string length overflows existing configurations - if (len > free_space) { - c_size_t overwrite_count = len - free_space; - self->head = (self->head + overwrite_count) % self->capacity; - } - - // Segment 1: Physical top copy action - c_size_t space_to_end = self->capacity - self->tail; - c_size_t first_chunk = (len < space_to_end) ? len : space_to_end; - memcpy(self->buffer + self->tail, src, first_chunk); - - // Segment 2: Physical circular bottom split copy action - c_size_t second_chunk = len - first_chunk; - if (second_chunk > 0) { - memcpy(self->buffer, src + first_chunk, second_chunk); - self->tail = second_chunk; - } else { - self->tail = (self->tail + first_chunk) % self->capacity; - } - - if (self->tail == self->head) { - self->is_full = C_TRUE; - } else { - self->is_full = C_FALSE; // Only set false if it didn't completely fill out layout thresholds - } - - return len; -} - -c_err_t c_ByteRingBuffer_PeekByte(const c_ByteRingBuffer_t* self, uint8_t* out_byte) { - if (!self || !self->buffer || !out_byte) return C_ERR_PARAM; - if (c_ByteRingBuffer_IsEmpty(self)) return -3; // Underflow - - *out_byte = self->buffer[self->head]; - return C_SUCCESS; -} - -c_size_t c_ByteRingBuffer_PeekBuffer(const c_ByteRingBuffer_t* self, uint8_t* dest, c_size_t len) { - if (!self || !self->buffer || !dest || len == 0) return 0; - - c_size_t available_bytes = c_ByteRingBuffer_GetSize(self); - if (len > available_bytes) { - len = available_bytes; - } - - if (len == 0) return 0; - - // Duplicate standard ReadBuffer chunk copy patterns without changing the 'head' cursor state - c_size_t bytes_to_end = self->capacity - self->head; - c_size_t first_chunk = (len < bytes_to_end) ? len : bytes_to_end; - memcpy(dest, self->buffer + self->head, first_chunk); - - c_size_t second_chunk = len - first_chunk; - if (second_chunk > 0) { - memcpy(dest + first_chunk, self->buffer, second_chunk); - } - - return len; -} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -c_size_t c_ByteRingBuffer_Discard(c_ByteRingBuffer_t* self, c_size_t len) { - if (!self || !self->buffer || len == 0) return 0; - - c_size_t available_bytes = c_ByteRingBuffer_GetSize(self); - if (len > available_bytes) { - len = available_bytes; - } - - if (len == 0) return 0; - - self->head = (self->head + len) % self->capacity; - self->is_full = C_FALSE; // Dropping bytes guarantees it is no longer full - - return len; -} - -const uint8_t* c_ByteRingBuffer_GetReadPtr(const c_ByteRingBuffer_t* self, c_size_t* out_contiguous_len) { - if (!self || !self->buffer || !out_contiguous_len) return NULL; - - *out_contiguous_len = 0; - if (c_ByteRingBuffer_IsEmpty(self)) return NULL; - - if (self->tail > self->head) { - // Data path is completely linear up to the tail index position - *out_contiguous_len = self->tail - self->head; - } else { - // Data path wraps around; the first contiguous stretch runs to the array tail boundary - *out_contiguous_len = self->capacity - self->head; - } - - return self->buffer + self->head; -} - -uint8_t* c_ByteRingBuffer_GetWritePtr(const c_ByteRingBuffer_t* self, c_size_t* out_contiguous_len) { - if (!self || !self->buffer || !out_contiguous_len) return NULL; - - *out_contiguous_len = 0; - if (self->is_full) return NULL; - - if (self->tail >= self->head) { - // Free space path runs from tail up to the absolute array wrap boundary - // Special case adjustment: If head is exactly at index 0, we can write up to capacity - 1 - // but since is_full flag tracking isolates capacity limits, write blocks up to standard edge boundaries. - *out_contiguous_len = self->capacity - self->tail; - - // Minor modification check: If head index configuration is further up but tail wraps, - // don't overlap onto the head index area until the next subsequent hardware layout fetch pass. - if (self->head == 0 && *out_contiguous_len == self->capacity) { - // Full allocation window available - } - } else { - // Free space path is bounded cleanly between tail position and head position index spaces - *out_contiguous_len = self->head - self->tail; - } - - return self->buffer + self->tail; -} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - - -C_STATIC_FORCE_INLINE -uint8_t c_ByteRingBuffer_GetAtRelativeInternal(const c_ByteRingBuffer_t* self, c_size_t relative_offset) { - c_size_t absolute_index = (self->head + relative_offset) % self->capacity; - return self->buffer[absolute_index]; -} - -c_index_t c_ByteRingBuffer_IndexOfBuffer(const c_ByteRingBuffer_t* self, const uint8_t* pattern, c_size_t pattern_len) { - if (!self || !self->buffer || !pattern || pattern_len == 0) return C_ERR_FAIL; - - c_size_t total_size = c_ByteRingBuffer_GetSize(self); - if (pattern_len > total_size) return C_ERR_FAIL; - - // Slide search window across the total available size boundary - c_size_t max_search_offset = total_size - pattern_len; - - for (c_size_t offset = 0; offset <= max_search_offset; offset++) { - c_bool_t match_found = C_TRUE; - - // Perform relative window byte sequence comparison - for (c_size_t p_idx = 0; p_idx < pattern_len; p_idx++) { - if (c_ByteRingBuffer_GetAtRelativeInternal(self, offset + p_idx) != pattern[p_idx]) { - match_found = C_FALSE; - break; - } - } - - if (match_found) { - return (c_index_t)offset; // Returns offset relative to current head position - } - } - - return C_ERR_FAIL; -} - -c_index_t c_ByteRingBuffer_IndexOfByte(const c_ByteRingBuffer_t* self, uint8_t target) { - if (!self || !self->buffer) return C_ERR_FAIL; - - c_size_t total_size = c_ByteRingBuffer_GetSize(self); - if (total_size == 0) return C_ERR_FAIL; - - // Linear pass mapping relative pointers natively across internal split layers - for (c_size_t offset = 0; offset < total_size; offset++) { - if (c_ByteRingBuffer_GetAtRelativeInternal(self, offset) == target) { - return (c_index_t)offset; - } - } - - return C_ERR_FAIL; -} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - - -c_index_t c_ByteRingBuffer_LastIndexOfBuffer(const c_ByteRingBuffer_t* self, const uint8_t* pattern, c_size_t pattern_len) { - if (!self || !self->buffer || !pattern || pattern_len == 0) return C_ERR_FAIL; - - c_size_t total_size = c_ByteRingBuffer_GetSize(self); - if (pattern_len > total_size) return C_ERR_FAIL; - - // Scan backwards from the largest possible relative offset down to index 0 - c_size_t max_search_offset = total_size - pattern_len; - - for (c_size_t offset = max_search_offset; ; offset--) { - c_bool_t match_found = C_TRUE; - - for (c_size_t p_idx = 0; p_idx < pattern_len; p_idx++) { - if (c_ByteRingBuffer_GetAtRelativeInternal(self, offset + p_idx) != pattern[p_idx]) { - match_found = C_FALSE; - break; - } - } - - if (match_found) { - return (c_index_t)offset; - } - - if (offset == 0) break; // Secure unsigned loop breakout guard rail - } - - return C_ERR_FAIL; -} - -c_size_t c_ByteRingBuffer_ReadUntilToken(c_ByteRingBuffer_t* self, const uint8_t* token, c_size_t token_len, uint8_t* dest, c_size_t dest_max_len) { - if (!self || !self->buffer || !token || token_len == 0 || !dest || dest_max_len == 0) return 0; - - // Step 1: Scan for the token sequence location relative to the head - c_index_t match_offset = c_ByteRingBuffer_IndexOfBuffer(self, token, token_len); - if (match_offset == C_ERR_FAIL) { - return 0; // Token sequence not currently hosted inside the window pipeline - } - - // Step 2: Compute total structural extraction requirements including the token depth - c_size_t aggregate_bytes = (c_size_t)match_offset + token_len; - - // Absolute safety check: Safeguard against destination memory container overflows - if (aggregate_bytes > dest_max_len) { - return 0; // Reject processing since target container is too small to safely store the complete payload string - } - - // Step 3: Perform standard destructive consumption via ReadBuffer - c_size_t bytes_extracted = c_ByteRingBuffer_ReadBuffer(self, dest, aggregate_bytes); - return bytes_extracted; -} - -c_err_t c_ByteRingBuffer_GetAtRelative(const c_ByteRingBuffer_t* self, c_size_t relative_offset, uint8_t* out_byte) { - if (!self || !self->buffer || !out_byte) return C_ERR_PARAM; - - // Validate that the request falls inside the populated byte array span - c_size_t active_size = c_ByteRingBuffer_GetSize(self); - if (relative_offset >= active_size) { - return C_ERR_OUTOFBOUND; - } - - // Safely fold the relative offset over physical ring buffer wrapping thresholds - c_size_t absolute_index = (self->head + relative_offset) % self->capacity; - - *out_byte = self->buffer[absolute_index]; - return C_SUCCESS; -} - -c_bool_t c_ByteRingBuffer_Is(const c_ByteRingBuffer_t* self, c_index_t offset, uint8_t value) { - // Return false immediately if the buffer is uninitialized or the offset is negative - if (!self || !self->buffer || offset < 0) { - return C_FALSE; - } - - // Verify that the requested relative offset falls within the currently readable window - c_size_t active_size = c_ByteRingBuffer_GetSize(self); - if ((c_size_t)offset >= active_size) { - return C_FALSE; - } - - // Map the relative offset to the physical, wrapped array index bounds - c_size_t absolute_index = (self->head + (c_size_t)offset) % self->capacity; - - // Evaluate content identity match condition - return (self->buffer[absolute_index] == value) ? C_TRUE : C_FALSE; -} - - -int c_ByteRingBuffer_Memcmp(const c_ByteRingBuffer_t* self, c_size_t offset, const uint8_t* buffer, c_size_t len) { - if (!self || !self->buffer || !buffer) { - return C_ERR_PARAM; - } - if (len == 0) { - return 0; // Empty comparison matches instantly - } - - c_size_t active_size = c_ByteRingBuffer_GetSize(self); - // Boundary check: Verify the comparison window falls entirely within readable buffer constraints - if (offset >= active_size || (offset + len) > active_size) { - return C_ERR_OUTOFBOUND; - } - - // Resolve the real physical starting index inside the memory array - c_size_t absolute_start = (self->head + offset) % self->capacity; - - // Calculate how many contiguous bytes run in a straight line up to the array boundary edge - c_size_t bytes_to_end = self->capacity - absolute_start; - - if (len <= bytes_to_end) { - // Scenario 1: The target verification window is completely contiguous - return memcmp(self->buffer + absolute_start, buffer, len); - } else { - // Scenario 2: The window wraps around the physical edge bounds. Execute a split-block comparison. - - // Pass A: Compare up to the wrapping array edge boundary - int first_segment_match = memcmp(self->buffer + absolute_start, buffer, bytes_to_end); - if (first_segment_match != 0) { - return first_segment_match; // Return mismatch direction immediately - } - - // Pass B: Wrap around to index 0 and compare the remainder sequence - c_size_t remaining_bytes = len - bytes_to_end; - return memcmp(self->buffer, buffer + bytes_to_end, remaining_bytes); - } -} - -c_err_t c_ByteRingBuffer_Strtoul(const c_ByteRingBuffer_t* self, c_size_t offset, int base, unsigned long* out_value, c_size_t* out_end_offset) { - if (!self || !self->buffer || !out_value) return C_ERR_PARAM; - - c_size_t total_size = c_ByteRingBuffer_GetSize(self); - if (offset >= total_size) return C_ERR_OUTOFBOUND; - - // 1. Skip leading whitespace using the internal helper function - c_size_t scan_idx = offset; - while (scan_idx < total_size) { - uint8_t byte = c_ByteRingBuffer_GetAtRelativeInternal(self, scan_idx); - if (!isspace(byte)) break; - scan_idx++; - } - - if (scan_idx == total_size) return C_ERR_PARAM; // Buffer contains only whitespace - - // 2. Measure the exact alphanumeric chunk layout width boundary - c_size_t start_numeric_offset = scan_idx; - c_size_t numeric_len = 0; - while (scan_idx < total_size) { - uint8_t byte = c_ByteRingBuffer_GetAtRelativeInternal(self, scan_idx); - // Track hex modifiers (x, X), signs, and alphanumeric digits - if (!isalnum(byte) && byte != '+' && byte != '-') { - break; - } - numeric_len++; - scan_idx++; - } - - if (numeric_len == 0) return C_ERR_PARAM; - - // 3. Compute absolute pointers and optimize memory operations based on wrap layouts - c_size_t absolute_start = (self->head + start_numeric_offset) % self->capacity; - c_size_t bytes_to_end = self->capacity - absolute_start; - - unsigned long result = 0; - char* parse_end = NULL; - int current_errno = errno; - errno = 0; - - if (numeric_len <= bytes_to_end) { - // Linear path optimization: Parse directly out of the contiguous array space - const char* flat_ptr = (const char*)(self->buffer + absolute_start); - result = strtoul(flat_ptr, &parse_end, base); - - c_size_t parsed_bytes = (c_size_t)(parse_end - flat_ptr); - if (parsed_bytes == 0 || parse_end == flat_ptr) { - errno = current_errno; - return C_ERR_PARAM; - } - - if (errno == ERANGE) return C_ERR_OUTOFBOUND; - - *out_value = result; - if (out_end_offset) { - *out_end_offset = start_numeric_offset + parsed_bytes; - } - } else { - // Fragmented Wrap handling path: Copy across loop slices onto a small stack array - if (numeric_len >= 64) return C_ERR_OUTOFBOUND; // Enforce safe parsing limits - - char stack_scratch[64]; - for (c_size_t i = 0; i < numeric_len; i++) { - stack_scratch[i] = (char)c_ByteRingBuffer_GetAtRelativeInternal(self, start_numeric_offset + i); - } - stack_scratch[numeric_len] = '\0'; // Guarantee safe string boundary termination - - result = strtoul(stack_scratch, &parse_end, base); - c_size_t parsed_bytes = (c_size_t)(parse_end - stack_scratch); - - if (parsed_bytes == 0 || parse_end == stack_scratch) { - errno = current_errno; - return C_ERR_PARAM; - } - - if (errno == ERANGE) return C_ERR_OUTOFBOUND; - - *out_value = result; - if (out_end_offset) { - *out_end_offset = start_numeric_offset + parsed_bytes; - } - } - - errno = current_errno; // Restore system state integrity flags cleanly - return C_SUCCESS; -} diff --git a/Foundation/c_ByteRingBuffer.h b/Foundation/c_ByteRingBuffer.h deleted file mode 100644 index cd5d7b8..0000000 --- a/Foundation/c_ByteRingBuffer.h +++ /dev/null @@ -1,140 +0,0 @@ -#ifndef INCLUDED_C_BYTERINGBUFFER_H -#define INCLUDED_C_BYTERINGBUFFER_H - -#ifndef INCLUDED_C_TYPES_H -#include -#endif /*INCLUDED_C_TYPES_H*/ - - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -typedef struct { - uint8_t* buffer; - c_size_t capacity; - c_size_t head; - c_size_t tail; - c_bool_t is_full; -}c_ByteRingBuffer_t; - -c_err_t c_ByteRingBuffer_Init(c_ByteRingBuffer_t* self, c_size_t capacity); -void c_ByteRingBuffer_Destroy(c_ByteRingBuffer_t* self); - -c_err_t c_ByteRingBuffer_WriteByte(c_ByteRingBuffer_t* self, uint8_t byte); -c_err_t c_ByteRingBuffer_ReadByte(c_ByteRingBuffer_t* self, uint8_t* out_byte); - -c_size_t c_ByteRingBuffer_WriteBuffer(c_ByteRingBuffer_t* self, const uint8_t* src, c_size_t len); -c_size_t c_ByteRingBuffer_ReadBuffer(c_ByteRingBuffer_t* self, uint8_t* dest, c_size_t len); - -c_size_t c_ByteRingBuffer_GetSize(const c_ByteRingBuffer_t* self); -c_bool_t c_ByteRingBuffer_IsEmpty(const c_ByteRingBuffer_t* self); -c_bool_t c_ByteRingBuffer_IsFull(const c_ByteRingBuffer_t* self); - -/* - * Writes a single byte, overwriting the oldest byte if the buffer is full. - */ -void c_ByteRingBuffer_WriteByteOverwrite(c_ByteRingBuffer_t* self, uint8_t byte); - -/* - * Writes a buffer span, overwriting the oldest bytes continuously if capacity is exceeded. - */ -c_size_t c_ByteRingBuffer_WriteBufferOverwrite(c_ByteRingBuffer_t* self, const uint8_t* src, c_size_t len); - -/* - * Inspects a single byte at the head position without removing it. - */ -c_err_t c_ByteRingBuffer_PeekByte(const c_ByteRingBuffer_t* self, uint8_t* out_byte); - -/* - * Inspects up to 'len' bytes starting from the head position without removing them. - * Returns the actual number of bytes peeked. - */ -c_size_t c_ByteRingBuffer_PeekBuffer(const c_ByteRingBuffer_t* self, uint8_t* dest, c_size_t len); - - -/* - * Advances the head pointer to drop up to 'len' bytes without copying data. - * Returns the actual number of bytes dropped. - */ -c_size_t c_ByteRingBuffer_Discard(c_ByteRingBuffer_t* self, c_size_t len); - -/* - * Returns the direct linear address to read the first available contiguous memory block. - * @param out_contiguous_len: Populated with the byte depth length of the straight chunk line. - * @return Pointer into the structural array channel, or NULL if buffer is empty. - */ -const uint8_t* c_ByteRingBuffer_GetReadPtr(const c_ByteRingBuffer_t* self, c_size_t* out_contiguous_len); - -/* - * Returns the direct linear address to write into the first available contiguous free memory block. - * @param out_contiguous_len: Populated with the space depth length of the straight chunk line. - * @return Pointer into the structural array channel, or NULL if buffer is full. - */ -uint8_t* c_ByteRingBuffer_GetWritePtr(const c_ByteRingBuffer_t* self, c_size_t* out_contiguous_len); - -/* - * Searches for the first occurrence of a byte sequence (pattern) within the ring buffer. - * Returns the relative offset from the current head pointer (0 to size-1), or C_ERR_NOT_FOUND. - */ -c_index_t c_ByteRingBuffer_IndexOfBuffer(const c_ByteRingBuffer_t* self, const uint8_t* pattern, c_size_t pattern_len); - -/* - * Searches for the first occurrence of a single byte within the ring buffer. - * Returns the relative offset from the current head pointer (0 to size-1), or C_ERR_NOT_FOUND. - */ -c_index_t c_ByteRingBuffer_IndexOfByte(const c_ByteRingBuffer_t* self, uint8_t target); - -/* - * Searches for the last occurrence of a byte sequence within the ring buffer. - * Returns the relative offset from the current head pointer (0 to size-1), or C_ERR_NOT_FOUND. - */ -c_index_t c_ByteRingBuffer_LastIndexOfBuffer(const c_ByteRingBuffer_t* self, const uint8_t* pattern, c_size_t pattern_len); - -/* - * Consumes and extracts data into 'dest' up to and including the specified token sequence. - * Returns the total number of bytes read and placed into dest, or 0 if token is not found. - */ -c_size_t c_ByteRingBuffer_ReadUntilToken(c_ByteRingBuffer_t* self, const uint8_t* token, c_size_t token_len, uint8_t* dest, c_size_t dest_max_len); - -/* - * Retrieves a single byte from the buffer at a relative index position from the head. - * @param self: The ring buffer instance. - * @param relative_offset: The offset relative to the head pointer (0 = oldest unread byte, size-1 = newest byte). - * @param out_byte: Destination pointer for the extracted byte. - * @return C_SUCCESS on clean execution, C_ERR_INVALID_PARAM, or C_ERR_OUT_OF_BOUNDS. - */ -c_err_t c_ByteRingBuffer_GetAtRelative(const c_ByteRingBuffer_t* self, c_size_t relative_offset, uint8_t* out_byte); - -/* - * Checks if the byte at a specific relative offset from the head matches the given value. - * @param self: The ring buffer instance. - * @param offset: The relative offset from the current head pointer (0 = oldest unread byte). - * @param value: The expected byte value to compare against. - * @return C_TRUE (1) if it matches perfectly, C_FALSE (0) if it mismatches, is empty, or out of bounds. - */ -c_bool_t c_ByteRingBuffer_Is(const c_ByteRingBuffer_t* self, c_index_t offset, uint8_t value); - -/* - * Compares the contents of the ring buffer starting at a relative offset with an external flat buffer. - * @param self: The ring buffer instance. - * @param offset: The relative offset from the current head pointer to start comparing from. - * @param buffer: The external memory array to compare against. - * @param len: The number of bytes to compare. - * @return 0 if the memory blocks match exactly, < 0 if the ring buffer data is lexicographically smaller, - * > 0 if it is larger. Returns (C_ERR_INVALID_PARAM) or (C_ERR_OUT_OF_BOUNDS) on range violations. - */ -int c_ByteRingBuffer_Memcmp(const c_ByteRingBuffer_t* self, c_size_t offset, const uint8_t* buffer, c_size_t len); - -/* - * Parses an unsigned long value from the ring buffer starting at a specific relative offset. - * @param self: The ring buffer instance. - * @param offset: The relative offset from the current head pointer to start parsing from. - * @param base: The number base system to parse (0 for auto-detection, 2-36). - * @param out_value: Destination pointer for the parsed unsigned long. - * @param out_end_offset: Optional destination pointer for the relative offset immediately following the parsed number. - * @return C_SUCCESS on clean execution, C_ERR_INVALID_PARAM, or C_ERR_OUT_OF_BOUNDS. - */ -c_err_t c_ByteRingBuffer_Strtoul(const c_ByteRingBuffer_t* self, c_size_t offset, int base, unsigned long* out_value, c_size_t* out_end_offset); - - -#endif /*INCLUDED_C_BYTERINGBUFFER_H*/ diff --git a/Foundation/c_ByteRingBuffer.t.c b/Foundation/c_ByteRingBuffer.t.c deleted file mode 100644 index d5eceac..0000000 --- a/Foundation/c_ByteRingBuffer.t.c +++ /dev/null @@ -1,346 +0,0 @@ -#include "c_ByteRingBuffer.h" -#include -#include -#include - -#define RUN_TEST_CASE(test_func) \ - do { \ - printf("[RUNNING] %-40s ... ", #test_func); \ - fflush(stdout); \ - test_func(); \ - printf("[PASSED]\n"); \ - } while (0) - -void test_ring_buffer_behavior(void) { - c_ByteRingBuffer_t ring; - assert(c_ByteRingBuffer_Init(&ring, 5) == C_SUCCESS); - assert(c_ByteRingBuffer_IsEmpty(&ring) == C_TRUE); - - // Fill to capacity bounds - assert(c_ByteRingBuffer_WriteByte(&ring, 0xAA) == C_SUCCESS); - assert(c_ByteRingBuffer_WriteByte(&ring, 0xBB) == C_SUCCESS); - assert(c_ByteRingBuffer_WriteByte(&ring, 0xCC) == C_SUCCESS); - assert(c_ByteRingBuffer_GetSize(&ring) == 3); - - uint8_t batch_src[3] = {0x11, 0x22, 0x33}; - // Should write only 2 bytes because total capacity limit is 5 - assert(c_ByteRingBuffer_WriteBuffer(&ring, batch_src, 3) == 2); - assert(c_ByteRingBuffer_IsFull(&ring) == C_TRUE); - - // Verify retrieval matches FIFO sequencing rules - uint8_t read_byte = 0; - assert(c_ByteRingBuffer_ReadByte(&ring, &read_byte) == C_SUCCESS); - assert(read_byte == 0xAA); - assert(c_ByteRingBuffer_IsFull(&ring) == C_FALSE); - - // Bulk wrap-around extraction - uint8_t batch_dest[4]; - assert(c_ByteRingBuffer_ReadBuffer(&ring, batch_dest, 4) == 4); - assert(batch_dest[0] == 0xBB); - assert(batch_dest[1] == 0xCC); - assert(batch_dest[2] == 0x11); - assert(batch_dest[3] == 0x22); - - assert(c_ByteRingBuffer_IsEmpty(&ring) == C_TRUE); - c_ByteRingBuffer_Destroy(&ring); -} - -static void test_overwrite_and_peek_mechanics(void) { - c_ByteRingBuffer_t ring; - assert(c_ByteRingBuffer_Init(&ring, 4) == C_SUCCESS); // Capacity = 4 - - // 1. Validate Single Overwrite - c_ByteRingBuffer_WriteByte(&ring, 0x01); - c_ByteRingBuffer_WriteByte(&ring, 0x02); - c_ByteRingBuffer_WriteByte(&ring, 0x03); - c_ByteRingBuffer_WriteByte(&ring, 0x04); // Buffer now full: [0x01, 0x02, 0x03, 0x04] - assert(c_ByteRingBuffer_IsFull(&ring) == C_TRUE); - - c_ByteRingBuffer_WriteByteOverwrite(&ring, 0x05); // 0x01 gets evicted. Head shifts to 0x02 - - uint8_t peek_check = 0; - assert(c_ByteRingBuffer_PeekByte(&ring, &peek_check) == C_SUCCESS); - assert(peek_check == 0x02); // FIFO rules dictate oldest remaining byte is 0x02 - - // 2. Validate Bulk Overwrite Loops - uint8_t incoming_stream[3] = {0x06, 0x07, 0x08}; - // Ring has 4 bytes capacity. Writing 3 bytes over an already full buffer evicts [0x02, 0x03, 0x04] - assert(c_ByteRingBuffer_WriteBufferOverwrite(&ring, incoming_stream, 3) == 3); - - uint8_t verification_dump[4] = {0}; - c_size_t read_out = c_ByteRingBuffer_PeekBuffer(&ring, verification_dump, 4); - assert(read_out == 4); - assert(verification_dump[0] == 0x05); // Preserved from previous transaction - assert(verification_dump[1] == 0x06); - assert(verification_dump[2] == 0x07); - assert(verification_dump[3] == 0x08); - - // 3. Confirm Peek leaves data sequence entirely untouched - assert(c_ByteRingBuffer_GetSize(&ring) == 4); - - c_ByteRingBuffer_Destroy(&ring); -} - -static void test_dma_and_discard_mechanics(void) { - c_ByteRingBuffer_t ring; - assert(c_ByteRingBuffer_Init(&ring, 8) == C_SUCCESS); // Capacity = 8 - - // Force initialization of data that loops around the internal ring memory map - uint8_t payload[] = {0xA1, 0xA2, 0xA3, 0xA4, 0xA5}; - c_ByteRingBuffer_WriteBuffer(&ring, payload, 5); - - // Discard oldest 2 items: drops 0xA1, 0xA2. Cursors shift. - assert(c_ByteRingBuffer_Discard(&ring, 2) == 2); - assert(c_ByteRingBuffer_GetSize(&ring) == 3); - - // Write some more to force a wrap-around layout - uint8_t wrap_payload[] = {0xB1, 0xB2, 0xB3, 0xB4}; - c_ByteRingBuffer_WriteBuffer(&ring, wrap_payload, 4); // Total size now = 7 bytes - - // Validate GetReadPtr isolates Block Segment 1 cleanly - c_size_t read_chunk_len = 0; - const uint8_t* read_ptr = c_ByteRingBuffer_GetReadPtr(&ring, &read_chunk_len); - - assert(read_ptr != NULL); - // Head was shifted to index 2. 8 - 2 = 6 available linearly up to memory array edge - assert(read_chunk_len == 6); - assert(read_ptr[0] == 0xA3); // First remaining item - - // Clear those processed items via direct execution tracking - c_ByteRingBuffer_Discard(&ring, read_chunk_len); - - // Call secondary pass to capture remaining wrapped bytes - read_ptr = c_ByteRingBuffer_GetReadPtr(&ring, &read_chunk_len); - assert(read_chunk_len == 1); - assert(read_ptr[0] == 0xB4); // Wrapped character check - - c_ByteRingBuffer_Destroy(&ring); -} - -static void test_ring_buffer_index_searching(void) { - c_ByteRingBuffer_t ring; - assert(c_ByteRingBuffer_Init(&ring, 8) == C_SUCCESS); // Capacity = 8 - - // Force a data write footprint that wraps around the buffer margins - uint8_t standard_fill[] = {0x00, 0x00, 0x00, 0x00, 0x11, 0x22, 0x33, 0x44}; - c_ByteRingBuffer_WriteBuffer(&ring, standard_fill, 8); - - // Discard 4 elements to position head cursor at absolute index 4 - c_ByteRingBuffer_Discard(&ring, 4); - - // Append sequence to cross edge wrap boundaries cleanly - uint8_t wrap_fill[] = {0x55, 0x66, 0x77}; - c_ByteRingBuffer_WriteBuffer(&ring, wrap_fill, 3); - // Dynamic ring content layout from head: [0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77] - - // 1. Single byte search lookup match - assert(c_ByteRingBuffer_IndexOfByte(&ring, 0x33) == 2); // Relative offset index 2 from head - assert(c_ByteRingBuffer_IndexOfByte(&ring, 0x99) == C_ERR_FAIL); - - // 2. Pattern buffer sequence scan (testing across structural wrap-around edge boundaries) - uint8_t search_pattern[] = {0x44, 0x55, 0x66}; - c_index_t match_offset = c_ByteRingBuffer_IndexOfBuffer(&ring, search_pattern, 3); - - assert(match_offset == 3); // 0x44 sits exactly at relative offset position 3 - - // Application Workflow Integration: Cleanly discard up to token match prefix point - c_ByteRingBuffer_Discard(&ring, (c_size_t)match_offset); - uint8_t current_head_byte = 0; - c_ByteRingBuffer_PeekByte(&ring, ¤t_head_byte); - assert(current_head_byte == 0x44); // The buffer head has been successfully synchronized to the token location - - c_ByteRingBuffer_Destroy(&ring); -} - -static void test_reverse_search_and_token_stream(void) { - c_ByteRingBuffer_t ring; - assert(c_ByteRingBuffer_Init(&ring, 8) == C_SUCCESS); // Capacity = 8 - - uint8_t raw_payload[] = {0xAA, 0x11, 0x22, 0xBB, 0x11, 0x22, 0xCC, 0xDD}; - c_ByteRingBuffer_WriteBuffer(&ring, raw_payload, 8); - - uint8_t pattern[] = {0x11, 0x22}; - - // 1. Verify Reverse Pattern Detection Matches Latest Occurrence - assert(c_ByteRingBuffer_IndexOfBuffer(&ring, pattern, 2) == 1); // First pair starts at offset 1 - assert(c_ByteRingBuffer_LastIndexOfBuffer(&ring, pattern, 2) == 4); // Latest pair starts at offset 4 - - // 2. Clear out buffer to run frame serialization test - c_ByteRingBuffer_Discard(&ring, 8); - - uint8_t stream_data[] = {'P', 'a', 'c', 'k', 'e', 't', '\r', '\n'}; - c_ByteRingBuffer_WriteBuffer(&ring, stream_data, 8); - - uint8_t frame_terminator[] = {'\r', '\n'}; - uint8_t output_staging[16] = {0}; - - // Fail Case: Pass a staging array that is structurally too cramped to hold the payload safely - assert(c_ByteRingBuffer_ReadUntilToken(&ring, frame_terminator, 2, output_staging, 5) == 0); - assert(c_ByteRingBuffer_GetSize(&ring) == 8); // Data remains locked safely inside the ring - - // Success Case: Pass a valid container size to execute frame extraction - c_size_t read_bytes = c_ByteRingBuffer_ReadUntilToken(&ring, frame_terminator, 2, output_staging, 16); - assert(read_bytes == 8); - assert(memcmp(output_staging, "Packet\r\n", 8) == 0); - assert(c_ByteRingBuffer_IsEmpty(&ring) == C_TRUE); // Frame has been cleanly consumed from the queue - - c_ByteRingBuffer_Destroy(&ring); -} - -static void test_relative_random_access(void) { - c_ByteRingBuffer_t ring; - assert(c_ByteRingBuffer_Init(&ring, 4) == C_SUCCESS); // Capacity = 4 - - uint8_t seed_data[] = {0x10, 0x20, 0x30}; - c_ByteRingBuffer_WriteBuffer(&ring, seed_data, 3); - - // Shift the head pointer downstream via a single byte consumption - uint8_t discard_sink = 0; - c_ByteRingBuffer_ReadByte(&ring, &discard_sink); // 0x10 dropped. Head points to 0x20 - - // Append items to cross physical wrapping thresholds cleanly - c_ByteRingBuffer_WriteByte(&ring, 0x40); - c_ByteRingBuffer_WriteByte(&ring, 0x50); // Buffer contents: [0x20, 0x30, 0x40, 0x50] - - uint8_t extracted_byte = 0; - - // 1. Verify standard random read coordinates relative to the head position - assert(c_ByteRingBuffer_GetAtRelative(&ring, 0, &extracted_byte) == C_SUCCESS); - assert(extracted_byte == 0x20); // Relative 0 points directly to the current head - - assert(c_ByteRingBuffer_GetAtRelative(&ring, 2, &extracted_byte) == C_SUCCESS); - assert(extracted_byte == 0x40); // Wrapped index check - - assert(c_ByteRingBuffer_GetAtRelative(&ring, 3, &extracted_byte) == C_SUCCESS); - assert(extracted_byte == 0x50); // Newest unread byte check - - // 2. Validate bounds-checking flags - assert(c_ByteRingBuffer_GetAtRelative(&ring, 4, &extracted_byte) == C_ERR_OUTOFBOUND); - assert(c_ByteRingBuffer_GetAtRelative(&ring, 99, &extracted_byte) == C_ERR_OUTOFBOUND); - assert(c_ByteRingBuffer_GetAtRelative(NULL, 0, &extracted_byte) == C_ERR_PARAM); - - c_ByteRingBuffer_Destroy(&ring); -} - -static void test_conditional_is_validator(void) { - c_ByteRingBuffer_t ring; - assert(c_ByteRingBuffer_Init(&ring, 4) == C_SUCCESS); - - uint8_t input_stream[] = {0xAA, 0xBB, 0xCC}; - c_ByteRingBuffer_WriteBuffer(&ring, input_stream, 3); - - // 1. Validate clean true/false matches relative to the head - assert(c_ByteRingBuffer_Is(&ring, 0, 0xAA) == C_TRUE); // Oldest byte at head matches - assert(c_ByteRingBuffer_Is(&ring, 1, 0xBB) == C_TRUE); // Next element matches - assert(c_ByteRingBuffer_Is(&ring, 1, 0x99) == C_FALSE); // Mismatch returns false - - // Consume 1 byte to advance the head pointer and test wrapping boundaries - uint8_t sink = 0; - c_ByteRingBuffer_ReadByte(&ring, &sink); // Head now points to 0xBB - c_ByteRingBuffer_WriteByte(&ring, 0xDD); // Layout: [..., 0xBB, 0xCC, 0xDD] - - // 2. Re-verify offsets after structural pointer wrap shifts - assert(c_ByteRingBuffer_Is(&ring, 0, 0xBB) == C_TRUE); // Head index position 0 is now 0xBB - assert(c_ByteRingBuffer_Is(&ring, 2, 0xDD) == C_TRUE); // Wrapped index element match - - // 3. Confirm error/bounds conditions return false instead of blowing up memory layout boundaries - assert(c_ByteRingBuffer_Is(&ring, 3, 0x00) == C_FALSE); // Out of bounds index - assert(c_ByteRingBuffer_Is(&ring, -5, 0xBB) == C_FALSE); // Negative index handling protection - assert(c_ByteRingBuffer_Is(NULL, 0, 0xBB) == C_FALSE); // NULL safety check - - c_ByteRingBuffer_Destroy(&ring); -} - -static void test_ring_buffer_memcmp(void) { - c_ByteRingBuffer_t ring; - assert(c_ByteRingBuffer_Init(&ring, 6) == C_SUCCESS); // Capacity = 6 - - uint8_t payload[] = {0x00, 0x11, 0x22, 0x33}; - c_ByteRingBuffer_WriteBuffer(&ring, payload, 4); - - // Consume 2 bytes to step the head pointer forward to absolute index 2 - uint8_t sink = 0; - c_ByteRingBuffer_ReadByte(&ring, &sink); - c_ByteRingBuffer_ReadByte(&ring, &sink); // Buffer active layout from head: [0x22, 0x33] - - // Append data to trigger an explicit physical wrap-around edge split layout - uint8_t wrap_payload[] = {0x44, 0x55, 0x66}; - c_ByteRingBuffer_WriteBuffer(&ring, wrap_payload, 3); - // Buffer dynamic content path tracking from head: [0x22, 0x33, 0x44, 0x55, 0x66] - // Physical layout behind indices inside array: [0x55, 0x66, 0x22, 0x33, 0x44, ...] - - // 1. Validate contiguous segment match comparisons - uint8_t check_a[] = {0x22, 0x33}; - assert(c_ByteRingBuffer_Memcmp(&ring, 0, check_a, 2) == 0); // Perfect contiguous match - - // 2. Validate multi-segment wrap-around comparison mechanics - uint8_t check_b[] = {0x33, 0x44, 0x55, 0x66}; - assert(c_ByteRingBuffer_Memcmp(&ring, 1, check_b, 4) == 0); // Perfect split wrap-around match - - // 3. Mismatch checks - uint8_t check_mismatch[] = {0x33, 0x44, 0x99, 0x66}; - assert(c_ByteRingBuffer_Memcmp(&ring, 1, check_mismatch, 4) != 0); // Identifies internal divergence - - // 4. Bounds and parameter checks - assert(c_ByteRingBuffer_Memcmp(&ring, 0, check_b, 100) == C_ERR_OUTOFBOUND); // Request width overflows content - assert(c_ByteRingBuffer_Memcmp(&ring, 99, check_b, 1) == C_ERR_OUTOFBOUND); // Start pointer invalid - assert(c_ByteRingBuffer_Memcmp(NULL, 0, check_b, 1) == C_ERR_PARAM); - - c_ByteRingBuffer_Destroy(&ring); -} -static void test_ring_buffer_strtoul(void) { - c_ByteRingBuffer_t ring; - assert(c_ByteRingBuffer_Init(&ring, 8) == C_SUCCESS); // Capacity = 8 - - // 1. Standard Linear Base-10 Parsing - uint8_t input_a[] = {'1', '2', '3', '4', ' ', 'A', 'B', 'C'}; - c_ByteRingBuffer_WriteBuffer(&ring, input_a, 8); - - unsigned long parsed_val = 0; - c_size_t end_offset = 0; - - assert(c_ByteRingBuffer_Strtoul(&ring, 0, 10, &parsed_val, &end_offset) == C_SUCCESS); - assert(parsed_val == 1234); - assert(end_offset == 4); // Points exactly to the trailing space character offset - - // Reset buffer tracking lines - c_ByteRingBuffer_Discard(&ring, 8); - - // 2. Fragmented Wrap Hex Parsing - // Pre-fill 5 elements to push cursor indices near wrapping layout boundaries - uint8_t pre_fill[] = {0, 0, 0, 0, 0}; - c_ByteRingBuffer_WriteBuffer(&ring, pre_fill, 5); - c_ByteRingBuffer_Discard(&ring, 5); // Head pointer sits at physical index 5 - - // Write Hex parameter payload string ("0x2F") across memory boundaries - uint8_t input_hex[] = {'0', 'x', '2', 'F'}; - c_ByteRingBuffer_WriteBuffer(&ring, input_hex, 4); - - assert(c_ByteRingBuffer_Strtoul(&ring, 0, 16, &parsed_val, &end_offset) == C_SUCCESS); - assert(parsed_val == 47); // 0x2F translates to decimal 47 - assert(end_offset == 4); - - c_ByteRingBuffer_Destroy(&ring); -} - - -int main() { - printf("==================================================\n"); - printf(" Starting c_ByteRingBuffer Unit Testing Suite\n"); - printf("==================================================\n\n"); - - RUN_TEST_CASE(test_ring_buffer_behavior); - RUN_TEST_CASE(test_overwrite_and_peek_mechanics); - RUN_TEST_CASE(test_dma_and_discard_mechanics); - RUN_TEST_CASE(test_ring_buffer_index_searching); - RUN_TEST_CASE(test_reverse_search_and_token_stream); - RUN_TEST_CASE(test_relative_random_access); - RUN_TEST_CASE(test_conditional_is_validator); - RUN_TEST_CASE(test_ring_buffer_memcmp); - RUN_TEST_CASE(test_ring_buffer_strtoul); - - printf("\n==================================================\n"); - printf(" Success! Byte RingBuffer tests passed!\n"); - printf("==================================================\n"); - return 0; -} \ No newline at end of file diff --git a/Foundation/c_Cond.c b/Foundation/c_Cond.c deleted file mode 100644 index 7ba2151..0000000 --- a/Foundation/c_Cond.c +++ /dev/null @@ -1,88 +0,0 @@ -#include - -#if defined(PLATFORM_POSIX) -#include -#include -#endif - -c_err_t c_Cond_Init(c_Cond_t* cond) { - if (!cond) return C_ERR_PARAM; - -#if defined(PLATFORM_WINDOWS) - // Windows 的条件变量初始化只是一个清零操作,不会失败 - InitializeConditionVariable(&cond->handle); - cond->is_initialized = C_TRUE; - return C_ERR_OK; -#elif defined(PLATFORM_POSIX) - if (pthread_cond_init(&cond->handle, NULL) == 0) { - cond->is_initialized = C_TRUE; - return C_ERR_OK; - } - return C_ERR_FAIL; -#endif -} - - -void c_Cond_Destroy(c_Cond_t* cond) { - if (!cond || !cond->is_initialized) return; - -#if defined(PLATFORM_WINDOWS) - // Windows 的 CONDITION_VARIABLE 不需要显式销毁(内核会自动回收) -#elif defined(PLATFORM_POSIX) - pthread_cond_destroy(&cond->handle); -#endif - cond->is_initialized = C_FALSE; -} - -void c_Cond_Wait(c_Cond_t* cond, c_Mutex_t* mutex) { - if (!cond || !cond->is_initialized || !mutex || !mutex->is_initialized) return; - -#if defined(PLATFORM_WINDOWS) - // SleepConditionVariableCS 会自动在内部释放传入的锁,并在唤醒时重新重新获取锁 - SleepConditionVariableCS(&cond->handle, &mutex->handle, INFINITE); -#elif defined(PLATFORM_POSIX) - pthread_cond_wait(&cond->handle, &mutex->handle); -#endif -} - -c_bool_t c_Cond_TimedWait(c_Cond_t* cond, c_Mutex_t* mutex, c_uint_t timeout_ms) { - if (!cond || !cond->is_initialized || !mutex || !mutex->is_initialized) return false; - -#if defined(PLATFORM_WINDOWS) - // 返回非 0 表示成功(收到信号),返回 0 表示超时 - return SleepConditionVariableCS(&cond->handle, &mutex->handle, timeout_ms) != 0; -#elif defined(PLATFORM_POSIX) - struct timespec ts; - struct timeval tv; - gettimeofday(&tv, NULL); - - // 计算绝对终止时间 - long long ns = (long long)tv.tv_usec * 1000 + (long long)timeout_ms * 1000000; - ts.tv_sec = tv.tv_sec + ns / 1000000000LL; - ts.tv_nsec = ns % 1000000000LL; - - // 返回 0 表示成功收到信号 - return pthread_cond_timedwait(&cond->handle, &mutex->handle, &ts) == 0; -#endif -} - -void c_Cond_Signal(c_Cond_t* cond) { - if (!cond || !cond->is_initialized) return; - -#if defined(PLATFORM_WINDOWS) - WakeConditionVariable(&cond->handle); -#elif defined(PLATFORM_POSIX) - pthread_cond_signal(&cond->handle); -#endif -} - -void c_Cond_Broadcast(c_Cond_t* cond) { - if (!cond || !cond->is_initialized) return; - -#if defined(PLATFORM_WINDOWS) - WakeAllConditionVariable(&cond->handle); -#elif defined(PLATFORM_POSIX) - pthread_cond_broadcast(&cond->handle); -#endif -} - diff --git a/Foundation/c_Cond.h b/Foundation/c_Cond.h deleted file mode 100644 index 6ff2f07..0000000 --- a/Foundation/c_Cond.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef INCLUDED_C_COND_H -#define INCLUDED_C_COND_H - -#ifndef INCLUDED_C_MUTEX_H -#include -#endif /*INCLUDED_C_MUTEX_H*/ - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -typedef struct { -#if defined(PLATFORM_WINDOWS) - CONDITION_VARIABLE handle; -#elif defined(PLATFORM_POSIX) - pthread_cond_t handle; -#endif - c_bool_t is_initialized; -} c_Cond_t; - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -c_err_t c_Cond_Init(c_Cond_t* cond); -void c_Cond_Destroy(c_Cond_t* cond); -void c_Cond_Wait(c_Cond_t* cond, c_Mutex_t* mutex); -c_bool_t c_Cond_TimedWait(c_Cond_t* cond, c_Mutex_t* mutex, c_uint_t timeout_ms); -void c_Cond_Signal(c_Cond_t* cond); -void c_Cond_Broadcast(c_Cond_t* cond); - - - -#endif /*INCLUDED_C_COND_H*/ diff --git a/Foundation/c_Console.c b/Foundation/c_Console.c deleted file mode 100644 index 8102b3f..0000000 --- a/Foundation/c_Console.c +++ /dev/null @@ -1,571 +0,0 @@ -#include -#include -#include -#include - -#if defined(_WIN32) || defined(_WIN64) - -#else -#include -#include -#include -#include -#endif - - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -// 仅在 POSIX (Linux/macOS) 平台下使用的全局变量,用于恢复终端 -#if defined(_WIN32) && defined(_WIN64) -// 备份用户进入程序前的原始代码页 -static UINT orig_in_cp = 0; -static UINT orig_out_cp = 0; -#else -static struct termios orig_termios; -static int is_terminal_initialized = 0; -#endif - -// 内部私有回调:用于程序退出时自动恢复终端属性 -static void c_Console_ResetOnExit(void) { -#if defined(_WIN32) || defined(_WIN64) - // 恢复 Windows 用户原本的代码页环境,避免污染用户的 CMD/PowerShell 终端 - if (orig_in_cp != 0) SetConsoleCP(orig_in_cp); - if (orig_out_cp != 0) SetConsoleOutputCP(orig_out_cp); -#else - // Linux 恢复原始 Raw Mode 设置(参考上一轮代码) - extern void disable_raw_mode(void); - disable_raw_mode(); -#endif -} - -/** - * @brief 跨平台初始化控制台环境 - * Windows: 激活全局 ANSI 转义序列支持 - * Linux/macOS: 关闭行缓冲、关闭按键回显,并注册退出恢复钩子 - */ -void c_Console_Init(void) { - // 1. 全平台通用的 C 标准库本地化声明(促使 printf/scanf 内部行为适配 UTF-8) - setlocale(LC_ALL, ".UTF-8"); - -#if defined(_WIN32) || defined(_WIN64) - // ---------------------------------------------------- - // Windows 平台:激活 VT 模式并全面强制 UTF-8 (65001) - // ---------------------------------------------------- - // 备份旧代码页 - orig_in_cp = GetConsoleCP(); - orig_out_cp = GetConsoleOutputCP(); - - // 强行设为 UTF-8 编码(65001 == CP_UTF8) - SetConsoleCP(CP_UTF8); // 影响控制台输入(如 scanf/fgets) - SetConsoleOutputCP(CP_UTF8); // 影响控制台输出(如 printf) - - // 注册退出钩子,以便程序正常退出或 exit 时自动还原环境 - atexit(c_Console_ResetOnExit); - - // 激活虚拟终端 (VT) 从而支持 ANSI 转义序列 - HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); - if (hOut != INVALID_HANDLE_VALUE) { - DWORD dwMode = 0; - if (GetConsoleMode(hOut, &dwMode)) { - dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; - SetConsoleMode(hOut, dwMode); - } - } - - HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE); - if (hIn!=INVALID_HANDLE_VALUE) { - DWORD mode; - // 1. 获取当前控制台的输入模式 - if (GetConsoleMode(hIn, &mode)) { - // 2. 启用鼠标输入 - mode |= ENABLE_MOUSE_INPUT; - - // 3. 禁用快速编辑模式(非常关键!如果不禁用,鼠标事件会被控制台自身拦截用于复制文本) - mode &= ~ENABLE_QUICK_EDIT_MODE; - - // 4. 启用扩展属性(如果要修改 QUICK_EDIT,必须同时带上这个标志) - mode |= ENABLE_EXTENDED_FLAGS; - - // 5. 应用新模式 - SetConsoleMode(hIn, mode); - } - } - - -#else - // ---------------------------------------------------- - // Linux/macOS 平台:开启 Raw Mode(沿用上一轮逻辑) - // ---------------------------------------------------- - extern struct termios orig_termios; - extern int is_terminal_initialized; - - if (!isatty(STDIN_FILENO)) return; - if (tcgetattr(STDIN_FILENO, &orig_termios) < 0) return; - - atexit(c_Console_ResetOnExit); - is_terminal_initialized = 1; - - struct termios raw = orig_termios; - raw.c_lflag &= ~(ICANON | ECHO); // 禁用回显和标准缓冲 - raw.c_cc[VMIN] = 1; - raw.c_cc[VTIME] = 0; - tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw); -#endif - - // 确保标准输出缓冲区立即刷新 - fflush(stdout); -} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -int c_Console_kbhit(void) { -#if defined(_WIN32) || defined(_WIN64) - return _kbhit(); -#else - struct timeval tv = {0, 0}; - fd_set fds; - FD_ZERO(&fds); - FD_SET(STDIN_FILENO, &fds); - return select(STDIN_FILENO + 1, &fds, NULL, NULL, &tv) > 0; -#endif -} - - -int c_Console_getch(void) { -#if defined(_WIN32) || defined(_WIN64) - return _getch(); -#else - char ch = 0; - if (read(STDIN_FILENO, &ch, 1) < 0) return 0; - return ch; -#endif -} - -void c_Console_Sleep(int milliseconds) { -#if defined(_WIN32) || defined(_WIN64) - Sleep(milliseconds); -#else - usleep(milliseconds * 1000); -#endif -} -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - - -void c_Console_BlankLine(int y) { - // 1. 将光标移动到目标行的第 1 列 - // \033[%d;1H : 移动到第 y 行,第 1 列 - printf("\033[%d;1H", y); - - // 2. 清除从光标位置到行尾的所有内容(现代终端推荐直接用 2K 清除整行) - // \033[2K : 清除光标所在的整行内容,但光标位置保持不变 - printf("\033[2K"); - - // 3. 强制刷新输出缓冲区,确保屏幕立刻更新 - fflush(stdout); -} - -/** - * @brief 从指定坐标 (x, y) 开始清空到该行的末尾 - */ -void c_Console_BlankLineFrom(int x, int y) { - printf("\033[%d;%dH", y, x); // 移动到 (x, y) - printf("\033[0K"); // 清除从当前光标到行尾 - fflush(stdout); -} - -/** - * @brief 跨平台移动控制台光标到指定坐标 - * @param x 目标列坐标 (Column/Horizontal),从 1 开始计,自左向右递增 - * @param y 目标行坐标 (Row/Vertical),从 1 开始计,自上向下递增 - */ -void c_Console_GotoXY(int x, int y) { - // 防御性保护:ANSI 坐标必须从 1 开始 - if (x < 1) x = 1; - if (y < 1) y = 1; - - // \033[%d;%dH : 第一个参数是行(y),第二个参数是列(x) - // 这是 ANSI X3.64 标准的固定顺序,切勿将 x 和 y 的位置颠倒 - printf("\033[%d;%dH", y, x); - - // 强制刷新缓冲区,确保光标立即移动到位 - fflush(stdout); -} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -void c_Console_GetSize(int *width, int *height) { - if (!width || !height) return; - -#if defined(_WIN32) || defined(_WIN64) - CONSOLE_SCREEN_BUFFER_INFO csbi; - HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); - if (hOut != INVALID_HANDLE_VALUE && GetConsoleScreenBufferInfo(hOut, &csbi)) { - // srWindow 存储了当前可视窗口的矩形边界(0-based 坐标) - *width = csbi.srWindow.Right - csbi.srWindow.Left + 1; - *height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1; - } else { - *width = 80; // 失败时的兜底默认值 - *height = 25; - } -#else - struct winsize w; - // 使用 ioctl 的 TIOCGWINSZ 标志直接获取终端窗口大小 - if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) == 0) { - *width = w.ws_col; - *height = w.ws_row; - } else { - *width = 80; // 失败时的兜底默认值 - *height = 25; - } -#endif -} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -int c_Console_GetVisualWidth(const char *str) { - if (!str) return 0; - - int visual_width = 0; - int i = 0; - - while (str[i] != '\0') { - unsigned char c = (unsigned char)str[i]; - - if (c < 0x80) { - // ---------------------------------------------------- - // 1. ASCII 字符 (0x00 - 0x7F) -> 占 1 字节,视觉宽度 1 - // ---------------------------------------------------- - visual_width += 1; - i += 1; - } - else if ((c & 0xE0) == 0xC0) { - // ---------------------------------------------------- - // 2. 2字节 UTF-8 字符 (如部分拉丁文、希腊字母) -> 视觉宽度 1 - // ---------------------------------------------------- - visual_width += 1; - i += 2; - } - else if ((c & 0xF0) == 0xE0) { - // ---------------------------------------------------- - // 3. 3字节 UTF-8 字符 (绝大多数中日韩汉字、常用标点) -> 视觉宽度 2 - // ---------------------------------------------------- - visual_width += 2; - i += 3; - } - else if ((c & 0xF8) == 0xF0) { - // ---------------------------------------------------- - // 4. 4字节 UTF-8 字符 (如 Emoji 表情、生僻字) -> 视觉宽度 2 - // ---------------------------------------------------- - visual_width += 2; - i += 4; - } - else { - // 异常安全降级处理 - i += 1; - } - } - return visual_width; -} - -void c_Console_PrintCenter(int y, int box_width, const char *str) { - if (!str) return; - - // 1. 计算文本的实际视觉宽度 - int text_width = c_Console_GetVisualWidth(str); - - // 2. 计算居中所需的左侧起始 X 坐标 (1-based 坐标系) - int start_x = (box_width - text_width) / 2 + 1; - if (start_x < 1) start_x = 1; // 边界防御 - - // 3. 跨平台移动光标并打印 - // 注意:需要使用外部已实现的 c_Console_GotoXY,此处以标准 ANSI 语法演示 - printf("\033[%d;%dH%s", y, start_x, str); - fflush(stdout); -} - -void c_Console_PrintLeftAligned(const char *str, int align_len) { - if (!str) return; - - // 打印文本 - printf("%s", str); - - // 计算实际占用的宽度,并动态补齐缺失的物理空格 - int text_width = c_Console_GetVisualWidth(str); - int padding = align_len - text_width; - - for (int i = 0; i < padding; i++) { - putchar(' '); - } -} - - -int c_Console_WriteXY(int x, int y, const char *format, ...) { - // 1. 防御性保护:确保坐标合法 - if (x < 1) x = 1; - if (y < 1) y = 1; - - // 2. 移动光标到目标坐标 (使用 ANSI CUP 序列) - printf("\033[%d;%dH", y, x); - - // 3. 处理 C 语言可变参数并安全输出 - va_list args; - va_start(args, format); - int result = vprintf(format, args); // 核心:使用 vprintf 将参数包直接输出到控制台 - va_end(args); - - // 4. 强制刷新输出缓冲区,确保文本和光标立即更新,防止画面滞后 - fflush(stdout); - - return result; -} - - -int c_Console_WriteColorXY(int x, int y, c_ConsoleColor_t fg, c_ConsoleColor_t bg, const char *format, ...) { - // 1. 防御性保护:确保坐标合法 - if (x < 1) x = 1; - if (y < 1) y = 1; - - // 2. 移动光标到指定位置 - printf("\033[%d;%dH", y, x); - - // 3. 构建并发送 ANSI 颜色控制序列 - // 标准前景色: 30-37, 高亮前景色: 90-97 - // 标准背景色: 40-47, 高亮背景色: 100-107 - if (fg != C_COLOR_NONE) { - if (fg < 8) { - printf("\033[%dm", 30 + fg); // 标准前景色 - } else { - printf("\033[%dm", 90 + (fg - 8)); // 高亮前景色 - } - } - if (bg != C_COLOR_NONE) { - if (bg < 8) { - printf("\033[%dm", 40 + bg); // 标准背景色 - } else { - printf("\033[%dm", 100 + (bg - 8));// 高亮背景色 - } - } - - // 4. 处理可变参数并安全输出文本 - va_list args; - va_start(args, format); - int result = vprintf(format, args); - va_end(args); - - // 5. 关键:格式化文本打印结束后,**必须重置颜色**,否则会污染后续的所有打印 - printf("\033[0m"); - - // 6. 强制刷新输出缓冲区 - fflush(stdout); - - return result; -} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -void c_Console_EnableMouse(void) { -#if defined(_WIN32) || defined(_WIN64) - HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE); - DWORD dwMode = 0; - GetConsoleMode(hIn, &dwMode); - // 启用鼠标输入标志 - dwMode |= ENABLE_MOUSE_INPUT; - // 如果启用了快速编辑模式(QuickEdit),会导致鼠标点击被系统拦截变成选中文字,必须关闭 - dwMode &= ~ENABLE_QUICK_EDIT_MODE; - SetConsoleMode(hIn, dwMode); -#else - // Linux/macOS: 发送 ANSI 序列开启鼠标追踪 - // \033[?1003h: 追踪所有鼠标动作(包括移动、点击、释放) - // \033[?1006h: 启用 SGR 鼠标编码模式(现代终端标配,坐标支持超过 255) - printf("\033[?1003h\033[?1006h"); - fflush(stdout); -#endif -} - - -void c_Console_DisableMouse(void) { -#if !defined(_WIN32) && !defined(_WIN64) - printf("\033[?1003l\033[?1006l"); // 关闭鼠标追踪 - fflush(stdout); -#endif -} - -/** - * @brief 跨平台非阻塞读取鼠标事件 - * @param mouse_evt 用于接收转换后的通用鼠标事件结构体 - * @return int 如果成功捕获到鼠标事件返回 1,否则返回 0 - */ -int c_Console_ReadMouse(c_ConsoleMouseEvent_t *mouse_evt) { - if (!mouse_evt) return 0; - mouse_evt->type = MOUSE_EVENT_NONE; - -#if defined(_WIN32) || defined(_WIN64) - // ---------------------------------------------------- - // Windows 平台实现 - // ---------------------------------------------------- - HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE); - DWORD numEvents = 0; - - // 检查输入缓冲区中是否有事件 - GetNumberOfConsoleInputEvents(hIn, &numEvents); - if (numEvents == 0) return 0; - - INPUT_RECORD inRec; - DWORD numRead = 0; - // 窥视而不直接移出,先确认是不是鼠标事件 - PeekConsoleInput(hIn, &inRec, 1, &numRead); - - if (numRead > 0 && inRec.EventType == MOUSE_EVENT) { - // 确实是鼠标事件,正式读出 - ReadConsoleInput(hIn, &inRec, 1, &numRead); - MOUSE_EVENT_RECORD mer = inRec.Event.MouseEvent; - - // 转换坐标 (Windows 是 0-based,我们要统一转换为 1-based) - mouse_evt->x = mer.dwMousePosition.X + 1; - mouse_evt->y = mer.dwMousePosition.Y + 1; - - // 判断事件类型 - if (mer.dwEventFlags == 0) { - // 点击或释放 - if (mer.dwButtonState & FROM_LEFT_1ST_BUTTON_PRESSED) { - mouse_evt->type = MOUSE_EVENT_PRESS_LEFT; - } else if (mer.dwButtonState & RIGHTMOST_BUTTON_PRESSED) { - mouse_evt->type = MOUSE_EVENT_PRESS_RIGHT; - } else if (mer.dwButtonState & FROM_LEFT_2ND_BUTTON_PRESSED) { - mouse_evt->type = MOUSE_EVENT_PRESS_MIDDLE; - } else { - mouse_evt->type = MOUSE_EVENT_RELEASE; - } - } else if (mer.dwEventFlags == MOUSE_WHEELED) { - // 滚轮滚动 (HIWORD 为正向上,为负向下) - if ((short)HIWORD(mer.dwButtonState) > 0) { - mouse_evt->type = MOUSE_EVENT_WHEEL_UP; - } else { - mouse_evt->type = MOUSE_EVENT_WHEEL_DOWN; - } - } else if (mer.dwEventFlags == MOUSE_MOVED) { - mouse_evt->type = MOUSE_EVENT_MOVE; - } - return 1; - } else if (numRead > 0) { - // 如果不是鼠标事件(比如是键盘事件),则丢弃或由其他函数处理 - ReadConsoleInput(hIn, &inRec, 1, &numRead); - } - -#else - // ---------------------------------------------------- - // Linux/macOS 平台实现 (解析 SGR 鼠标协议序列) - // SGR 格式一般为: \033[<按钮代号>;X坐标;Y坐标M (或 m 代表释放) - // ---------------------------------------------------- - - if (!c_Console_kbhit()) return 0; - - int ch = c_Console_getch(); - if (ch == 27) { // 捕获到 ESC (\033) - if (c_Console_getch() == '[') { - if (c_Console_getch() == '<') { - int btn = 0, x = 0, y = 0; - char action = 0; - - // 解析 SGR 密文参数,例如 "0;45;12M" - // 现代终端标准,直接使用 scanf 变体或手动循环读取 - if (scanf("%d;%d;%d%c", &btn, &x, &y, &action) == 4) { - mouse_evt->x = x; - mouse_evt->y = y; - - if (action == 'm') { - mouse_evt->type = MOUSE_EVENT_RELEASE; - } else if (action == 'M') { - if (btn == 0) mouse_evt->type = MOUSE_EVENT_PRESS_LEFT; - else if (btn == 1) mouse_evt->type = MOUSE_EVENT_PRESS_MIDDLE; - else if (btn == 2) mouse_evt->type = MOUSE_EVENT_PRESS_RIGHT; - else if (btn == 32) mouse_evt->type = MOUSE_EVENT_MOVE; // 伴随左键的移动 - else if (btn == 35) mouse_evt->type = MOUSE_EVENT_MOVE; // 纯移动 - else if (btn == 64) mouse_evt->type = MOUSE_EVENT_WHEEL_UP; - else if (btn == 65) mouse_evt->type = MOUSE_EVENT_WHEEL_DOWN; - } - return 1; - } - } - } - } -#endif - return 0; -} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -/** - * @brief 跨平台精准读取并转换键盘按键(包含方向键、Esc、Enter) - * @note 必须确保终端已通过 c_Console_Init() 切换到非阻塞/Raw 模式 - * @return int 返回转换后的统一 c_ConsoleKeyCode_t 键值,若为普通字符则原样返回其 ASCII 码 - */ -int c_Console_ReadKey(void) { - if (!c_Console_kbhit()) return C_KEY_UNKNOWN; - - int ch = c_Console_getch(); - -#if defined(_WIN32) || defined(_WIN64) - // ---------------------------------------------------- - // Windows 平台:处理扩展键双字节 - // ---------------------------------------------------- - if (ch == 0 || ch == 224) { - // 遇到特殊前缀,必须紧接着读取第二个字节 - int sub_ch = _getch(); - switch (sub_ch) { - case 72: return C_KEY_UP; - case 80: return C_KEY_DOWN; - case 75: return C_KEY_LEFT; - case 77: return C_KEY_RIGHT; - default: return C_KEY_UNKNOWN; - } - } - - // Windows 的回车可能返回 '\r' (13),统一规范化 - if (ch == '\r' || ch == '\n') return C_KEY_ENTER; - - return ch; // 普通 ASCII 字符 (如 'w', 'a', 's', 'd') 直接原样返回 - -#else - // ---------------------------------------------------- - // Linux/macOS 平台:处理 ANSI 键盘转义序列流 - // ---------------------------------------------------- - if (ch == 27) { // 捕获到第一个字节是 ESC - // 立即检查缓冲区,看后面有没有跟着字符。如果没有,说明用户真的只按了独立的 Esc 键 - if (!c_Console_kbhit()) { - return C_KEY_ESC; - } - - int next1 = c_Console_getch(); - if (next1 == '[') { - if (!c_Console_kbhit()) return C_KEY_UNKNOWN; - int next2 = c_Console_getch(); - - // 标准方向键序列判定: ESC [ A/B/C/D - switch (next2) { - case 'A': return C_KEY_UP; - case 'B': return C_KEY_DOWN; - case 'C': return C_KEY_RIGHT; - case 'D': return C_KEY_LEFT; - default: return C_KEY_UNKNOWN; - } - } - return C_KEY_UNKNOWN; - } - - // Linux 退格键适配 - if (ch == 127) return C_KEY_BACKSPACE; - // 回车键统一 - if (ch == '\n' || ch == '\r') return C_KEY_ENTER; - - return ch; // 普通 ASCII 字符原样返回 -#endif -} - diff --git a/Foundation/c_Console.h b/Foundation/c_Console.h deleted file mode 100644 index eccb0a9..0000000 --- a/Foundation/c_Console.h +++ /dev/null @@ -1,241 +0,0 @@ -#ifndef INCLUDED_C_CONSOLE_H -#define INCLUDED_C_CONSOLE_H - -#ifndef INCLUDED_C_TYPES_H -#include -#endif /*INCLUDED_C_TYPES_H*/ - -#ifndef INCLUDED_STDIO_H -#define INCLUDED_STDIO_H -#include -#endif /*INCLUDED_STDIO_H*/ - - -#if defined(_WIN32) || defined(_WIN64) - #include - #include -#else - #include - #include - #include -#endif - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -// ========================================== -// 2. 终端控制 ANSI 转义宏 (全平台通用) -// ========================================== -#define CONSOLE_CLEAR() printf("\033[2J\033[H") // 清屏并将光标归位 -#define CONSOLE_GOTOXY(x, y) printf("\033[%d;%dH", (y), (x)) // 移动光标 (1-based) -#define CONSOLE_HIDE_CURSOR() printf("\033[?25l") // 隐藏光标 -#define CONSOLE_SHOW_CURSOR() printf("\033[?25h") // 显示光标 -#define CONSOLE_COLOR_RESET() printf("\033[0m") // 重置属性 -#define CONSOLE_COLOR_RED() printf("\033[1;31m") // 高亮红 -#define CONSOLE_COLOR_GREEN() printf("\033[1;32m") // 高亮绿 -#define CONSOLE_COLOR_BLUE() printf("\033[1;34m") // 高亮蓝 - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -/** - * @brief 控制台 16 色标准颜色枚举(同时适用于前景色和背景色计算) - */ -typedef enum { - C_COLOR_BLACK = 0, - C_COLOR_RED = 1, - C_COLOR_GREEN = 2, - C_COLOR_YELLOW = 3, - C_COLOR_BLUE = 4, - C_COLOR_MAGENTA = 5, - C_COLOR_CYAN = 6, - C_COLOR_WHITE = 7, - - // 高亮色系列(加粗/明亮) - C_COLOR_BRIGHT_BLACK = 8, - C_COLOR_BRIGHT_RED = 9, - C_COLOR_BRIGHT_GREEN = 10, - C_COLOR_BRIGHT_YELLOW = 11, - C_COLOR_BRIGHT_BLUE = 12, - C_COLOR_BRIGHT_MAGENTA = 13, - C_COLOR_BRIGHT_CYAN = 14, - C_COLOR_BRIGHT_WHITE = 15, - - C_COLOR_NONE = -1 // 不改变原有颜色(保持默认) -} c_ConsoleColor_t; - -// 鼠标事件类型 -typedef enum { - MOUSE_EVENT_NONE = 0, - MOUSE_EVENT_PRESS_LEFT, // 左键按下 - MOUSE_EVENT_PRESS_RIGHT, // 右键按下 - MOUSE_EVENT_PRESS_MIDDLE, // 中键按下 - MOUSE_EVENT_RELEASE, // 任意键释放 - MOUSE_EVENT_WHEEL_UP, // 滚轮向上滚动 - MOUSE_EVENT_WHEEL_DOWN, // 滚轮向下滚动 - MOUSE_EVENT_MOVE // 鼠标移动 -} c_ConsoleMouseEventType_t; - -// 统一的鼠标事件结构体 -typedef struct { - c_ConsoleMouseEventType_t type; // 事件类型 - int x; // 触发时的列坐标 (从 1 开始) - int y; // 触发时的行坐标 (从 1 开始) -} c_ConsoleMouseEvent_t; - -typedef enum { - // 基础控制键(单字节即可判定的按键) - C_KEY_UNKNOWN = 0, - C_KEY_ENTER = 13, // 统一回车键 - C_KEY_ESC = 27, // 统一 ESC 键 - C_KEY_SPACE = 32, // 空格键 - C_KEY_BACKSPACE = 127,// 退格键 - - // 特殊扩展按键(方向键) - C_KEY_UP = 1001, - C_KEY_DOWN = 1002, - C_KEY_LEFT = 1003, - C_KEY_RIGHT = 1004 -} c_ConsoleKeyCode_t; - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -/** - * @brief 跨平台初始化控制台环境 - * Windows: 激活全局 ANSI 转义序列支持 - * Linux/macOS: 关闭行缓冲、关闭按键回显,并注册退出恢复钩子 - */ -void c_Console_Init(void); - -/** - * @brief 跨平台非阻塞检查是否有键盘输入 - * @return - */ -int c_Console_kbhit(void); - -/** - * @brief 跨平台直接读取单个按键字符 - * @return - */ -int c_Console_getch(void); - -/** - * - * @param milliseconds - */ -void c_Console_Sleep(int milliseconds); - -/** - * @brief 跨平台清除控制台中的指定行 - * @param y 目标行的纵坐标 (从 1 开始计) - */ -void c_Console_BlankLine(int y); - - -/** - * @brief 从指定坐标 (x, y) 开始清空到该行的末尾 - */ -void c_Console_BlankLineFrom(int x, int y); - - -/** - * @brief 跨平台移动控制台光标到指定坐标 - * @param x 目标列坐标 (Column/Horizontal),从 1 开始计,自左向右递增 - * @param y 目标行坐标 (Row/Vertical),从 1 开始计,自上向下递增 - */ -void c_Console_GotoXY(int x, int y); - -/** - * @brief 跨平台获取当前控制台窗口的大小(宽高) - * @param width 用于接收总列数(X方向字符数)的指针 - * @param height 用于接收总行数(Y方向字符数)的指针 - */ -void c_Console_GetSize(int *width, int *height); - - -/** - * @brief 在控制台指定行的指定总宽度内,将 UTF-8 文本居中打印 - * @param y 目标行坐标 (从 1 开始) - * @param box_width 容器的总宽度(例如整个控制台的宽度,或一个 UI 矩形框的宽度) - * @param str 要打印的 UTF-8 字符串 - */ -void c_Console_PrintCenter(int y, int box_width, const char *str); - -/** - * @brief 精准计算一个 UTF-8 字符串在控制台上的实际“光标显示宽度” - * @param str 输入的 UTF-8 字符串 - * @return 屏幕实际占用的列数(英文字符算 1,中文/日文/韩文等全角字符算 2) - */ -int c_Console_GetVisualWidth(const char *str); - -/** - * @brief 格式化等宽对齐打印(常用于表格、菜单选项对齐) - * @param str 要打印的文本 - * @param align_len 限定的视觉总宽度(若文本不足此宽度,自动在右侧补齐空格) - */ -void c_Console_PrintLeftAligned(const char *str, int align_len); - -/** - * @brief 跨平台在指定坐标处格式化输出 UTF-8 文本 - * @param x 目标列坐标 (从 1 开始计) - * @param y 目标行坐标 (从 1 开始计) - * @param format 格式化字符串 (与 printf 完全一致,如 "Score: %d") - * @param ... 可变参数 - * @return 成功打印的物理字节数(若失败返回负数) - */ -int c_Console_WriteXY(int x, int y, const char *format, ...); - -/** - * @brief 跨平台在指定坐标处,以指定的颜色格式化输出文本 - * @param x 目标列坐标 (从 1 开始) - * @param y 目标行坐标 (从 1 开始) - * @param fg 前景色 (文字颜色),传入 C_COLOR_NONE 表示不修改 - * @param bg 背景色 (文字底色),传入 C_COLOR_NONE 表示不修改 - * @param format 格式化字符串 - * @param ... 可变参数 - * @return 成功打印的物理字节数 - */ -int c_Console_WriteColorXY(int x, int y, c_ConsoleColor_t fg, c_ConsoleColor_t bg, const char *format, ...); - -/** - * @brief 开启鼠标事件追踪 - */ -void c_Console_EnableMouse(void); - -/** - * @brief 关闭鼠标事件追踪(程序退出时必须调用,避免污染用户终端) - */ -void c_Console_DisableMouse(void); - -/** - * @brief 跨平台非阻塞读取鼠标事件 - * @param mouse_evt 用于接收转换后的通用鼠标事件结构体 - * @return int 如果成功捕获到鼠标事件返回 1,否则返回 0 - */ -int c_Console_ReadMouse(c_ConsoleMouseEvent_t *mouse_evt); - - -/** - * @brief 跨平台精准读取并转换键盘按键(包含方向键、Esc、Enter) - * @note 必须确保终端已通过 c_Console_Init() 切换到非阻塞/Raw 模式 - * @return int 返回转换后的统一 c_ConsoleKeyCode_t 键值,若为普通字符则原样返回其 ASCII 码 - */ -int c_Console_ReadKey(void); - - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -C_STATIC_FORCE_INLINE -void c_Console_HideCursor(void) { - printf("\033[?25l"); -} - -C_STATIC_FORCE_INLINE -void c_Console_ShowCursor(void) { - printf("\033[?25h"); -} - - -#endif /*INCLUDED_C_CONSOLE_H*/ diff --git a/Foundation/c_Console.t.c b/Foundation/c_Console.t.c deleted file mode 100644 index 49248d6..0000000 --- a/Foundation/c_Console.t.c +++ /dev/null @@ -1,59 +0,0 @@ -#include "c_Console.h" -#include -#include - -int main() { - c_Console_Init(); - CONSOLE_CLEAR(); - CONSOLE_HIDE_CURSOR(); - - int x = 10, y = 5; - int running = 1; - - CONSOLE_GOTOXY(1, 1); - CONSOLE_COLOR_GREEN(); - printf("=== 跨平台控制台框架示例 ==="); - CONSOLE_GOTOXY(1, 2); - CONSOLE_COLOR_RESET(); - printf("控制键: W/A/S/D 移动,Q 退出\n"); - - while (running) { - // 1. 处理输入 - if (c_Console_kbhit()) { - int key = c_Console_getch(); - - // 擦除旧位置 - CONSOLE_GOTOXY(x, y); - printf(" "); - - switch (key) { - case 'w': case 'W': y--; break; - case 's': case 'S': y++; break; - case 'a': case 'A': x--; break; - case 'd': case 'D': x++; break; - case 'q': case 'Q': running = 0; break; - default: break; - } - - // 边界约束 - if (x < 1) x = 1; - if (y < 3) y = 3; - } - - // 2. 渲染画面 - CONSOLE_GOTOXY(x, y); - CONSOLE_COLOR_RED(); - printf("@"); // 绘制玩家 - fflush(stdout); // 刷新标准输出缓冲区(防止字符滞留) - - // 3. 控制帧率 (约 30 FPS) - c_Console_Sleep(33); - } - - // 退出处理 - CONSOLE_CLEAR(); - CONSOLE_SHOW_CURSOR(); - CONSOLE_COLOR_RESET(); - printf("程序已安全退出。\n"); - return 0; -} \ No newline at end of file diff --git a/Foundation/c_Console_Menu.t.c b/Foundation/c_Console_Menu.t.c deleted file mode 100644 index 3c379ee..0000000 --- a/Foundation/c_Console_Menu.t.c +++ /dev/null @@ -1,127 +0,0 @@ -#include "c_Console.h" -#include -#include - -int main(void) { - // 1. 全局初始化控制台环境(支持 UTF-8、启用鼠标追踪、隐藏光标、Raw模式) - c_Console_Init(); - CONSOLE_CLEAR(); - CONSOLE_HIDE_CURSOR(); - - int screen_w = 80, screen_h = 25; - c_Console_GetSize(&screen_w, &screen_h); - - // 2. 绘制可视化测试台的固定 UI 边框与标题 - c_Console_WriteColorXY(1, 1, C_COLOR_BRIGHT_WHITE, C_COLOR_BLUE, "==== 跨平台 c_Console 自动化全功能可视化测试台 ===="); - c_Console_WriteColorXY(1, 2, C_COLOR_BRIGHT_BLACK, C_COLOR_NONE, "操作指南: 按 [方向键 ↑↓←→] 测试键盘,用 [鼠标点击/滚轮] 测试动态事件。按 [Esc] 键退出。"); - - // 3. 绘制 UTF-8 中英文混排对照区,验证等宽对齐算法 - c_Console_WriteColorXY(2, 5, C_COLOR_BRIGHT_CYAN, C_COLOR_NONE, "【1. UTF-8 宽度测试对齐基准线】:"); - c_Console_WriteColorXY(2, 6, C_COLOR_WHITE, C_COLOR_NONE, "字符串A: [C++ 2026]") ; - c_Console_WriteColorXY(2, 7, C_COLOR_WHITE, C_COLOR_NONE, "字符串B: [C语言实现]") ; - - // 动态计算并打印视觉宽度进行自检 - int lenA = c_Console_GetVisualWidth("[C++ 2026]"); - int lenB = c_Console_GetVisualWidth("[C语言实现]"); - c_Console_WriteColorXY(30, 6, C_COLOR_YELLOW, C_COLOR_NONE, "<- 判定宽度: %d (理论应为 10)", lenA); - c_Console_WriteColorXY(30, 7, C_COLOR_YELLOW, C_COLOR_NONE, "<- 判定宽度: %d (理论应为 10)", lenB); - - // 4. 绘制两个交互式虚拟测试按钮供鼠标点击 - c_Console_WriteColorXY(5, 10, C_COLOR_WHITE, C_COLOR_GREEN, " [ 按钮 A ] "); - c_Console_WriteColorXY(20, 10, C_COLOR_WHITE, C_COLOR_MAGENTA, " [ 按钮 B ] "); - - // 键盘移动小方块的起始坐标状态 - int k_x = 5, k_y = 15; - c_Console_WriteColorXY(k_x, k_y, C_COLOR_BRIGHT_RED, C_COLOR_NONE, "■"); - - int running = 1; - while (running) { - // ---------------------------------------------------- - // 测试项 A: 键盘输入流测试 - // ---------------------------------------------------- - int key = c_Console_ReadKey(); - if (key != C_KEY_UNKNOWN) { - // 清空第 12 行并更新键盘状态 - printf("\033[12;1H\033[2K"); - - if (key == C_KEY_ESC) { - running = 0; // 按 Esc 键退出 - } - else if (key == C_KEY_UP || key == C_KEY_DOWN || key == C_KEY_LEFT || key == C_KEY_RIGHT) { - // 擦除旧位置 - c_Console_WriteColorXY(k_x, k_y, C_COLOR_NONE, C_COLOR_NONE, " "); - // 响应方向键 - if (key == C_KEY_UP) k_y--; - if (key == C_KEY_DOWN) k_y++; - if (key == C_KEY_LEFT) k_x -= 2; // 方块占2个物理宽度 - if (key == C_KEY_RIGHT) k_x += 2; - // 边界约束 - if (k_x < 1) k_x = 1; if (k_y < 13) k_y = 13; - // 绘制新位置 - c_Console_WriteColorXY(k_x, k_y, C_COLOR_BRIGHT_RED, C_COLOR_NONE, "■"); - - c_Console_WriteColorXY(2, 12, C_COLOR_BRIGHT_GREEN, C_COLOR_NONE, "键盘响应: [方向键] 成功触发! 当前方块坐标: (%d, %d)", k_x, k_y); - } - else if (key == C_KEY_ENTER) { - c_Console_WriteColorXY(2, 12, C_COLOR_BRIGHT_GREEN, C_COLOR_NONE, "键盘响应: [Enter 回车键] 成功触发!"); - } - else { - c_Console_WriteColorXY(2, 12, C_COLOR_BRIGHT_GREEN, C_COLOR_NONE, "键盘响应: 普通字符键 [%c] ASCII: %d", (char)key, key); - } - } - - // ---------------------------------------------------- - // 测试项 B: 鼠标与滚轮流测试 - // ---------------------------------------------------- - c_ConsoleMouseEvent_t mouse_evt; - if (c_Console_ReadMouse(&mouse_evt)) { - // 在第 18 行实时刷新鼠标动作 - printf("\033[18;1H\033[2K"); - - switch (mouse_evt.type) { - case MOUSE_EVENT_PRESS_LEFT: - c_Console_WriteColorXY(2, 18, C_COLOR_BRIGHT_YELLOW, C_COLOR_NONE, "鼠标响应: 【左键点击】 坐标: (%d, %d)", mouse_evt.x, mouse_evt.y); - - // 按钮矩形区域碰撞检测 - if (mouse_evt.y == 10) { - if (mouse_evt.x >= 5 && mouse_evt.x <= 15) { - c_Console_WriteColorXY(5, 11, C_COLOR_BRIGHT_RED, C_COLOR_NONE, "🔥 触发 A !"); - } else if (mouse_evt.x >= 20 && mouse_evt.x <= 30) { - c_Console_WriteColorXY(20, 11, C_COLOR_BRIGHT_RED, C_COLOR_NONE, "🔥 触发 B !"); - } - } - break; - case MOUSE_EVENT_PRESS_RIGHT: - c_Console_WriteColorXY(2, 18, C_COLOR_BRIGHT_YELLOW, C_COLOR_NONE, "鼠标响应: 【右键点击】 坐标: (%d, %d)", mouse_evt.x, mouse_evt.y); - break; - case MOUSE_EVENT_WHEEL_UP: - c_Console_WriteColorXY(2, 18, C_COLOR_BRIGHT_BLUE, C_COLOR_NONE, "滚轮响应: 【向上滚动 ↑】 坐标: (%d, %d)", mouse_evt.x, mouse_evt.y); - break; - case MOUSE_EVENT_WHEEL_DOWN: - c_Console_WriteColorXY(2, 18, C_COLOR_BRIGHT_BLUE, C_COLOR_NONE, "滚轮响应: 【向下滚动 ↓】 坐标: (%d, %d)", mouse_evt.x, mouse_evt.y); - break; - case MOUSE_EVENT_MOVE: - // 右下角高频显示当前准心坐标 - c_Console_WriteColorXY(screen_w - 20, 3, C_COLOR_BRIGHT_BLACK, C_COLOR_NONE, "鼠标悬停: (%03d, %03d)", mouse_evt.x, mouse_evt.y); - break; - case MOUSE_EVENT_RELEASE: - // 释放鼠标时清理按钮下方的触发提示字样 - printf("\033[11;1H\033[2K"); - break; - default: - break; - } - } - - // 控制刷新帧率(约 50 FPS),避免 CPU 满载 - c_Console_Sleep(20); - } - - // 5. 退出处理:清屏并让 atexit 自动恢复终端原始设置 - printf("\033[2J\033[H"); - CONSOLE_CLEAR(); - CONSOLE_SHOW_CURSOR(); - CONSOLE_COLOR_RESET(); - return 0; -} - diff --git a/Foundation/c_FastByteRingBuffer.c b/Foundation/c_FastByteRingBuffer.c deleted file mode 100644 index d39f931..0000000 --- a/Foundation/c_FastByteRingBuffer.c +++ /dev/null @@ -1,544 +0,0 @@ -#include -#include -#include -#include -#include - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -C_STATIC_FORCE_INLINE -c_size_t round_up_to_pow2(c_size_t v) { - v--; - v |= v >> 1; - v |= v >> 2; - v |= v >> 4; - v |= v >> 8; - v |= v >> 16; -#if (defined(__WORDSIZE) && __WORDSIZE == 64) || defined(_WIN64) || defined(__x86_64__) || defined(__aarch64__) - v |= v >> 32; -#endif - v++; - return v; -} - -C_STATIC_FORCE_INLINE -c_bool_t c_FastByteRingBuffer_IsPow2(c_size_t capacity) { - // A power of 2 must be greater than zero. - // The bitwise trick (capacity & (capacity - 1)) works because a power of 2 - // has exactly one bit set (e.g., 01000). Subtracting 1 flips all bits up to - // that set bit (e.g., 00111). Performing a bitwise AND yields exactly 0. - if (capacity == 0) { - return C_FALSE; - } - return ((capacity & (capacity - 1)) == 0) ? C_TRUE : C_FALSE; -} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -c_err_t c_FastByteRingBuffer_Init(c_FastByteRingBuffer_t* self, c_size_t capacity) { - if (!self || capacity == 0) return C_ERR_PARAM; - if (!c_FastByteRingBuffer_IsPow2(capacity)) { - return C_ERR_PARAM; - } - // 自動向上對齊,確保符合 Power of Two - self->capacity = capacity; - self->mask = self->capacity - 1; // 建立遮罩 - self->head = 0; - self->tail = 0; - self->is_full = C_FALSE; - - self->buffer = (uint8_t*)C_ALLOC(self->capacity); - if (!self->buffer) { - self->capacity = 0; - self->mask = 0; - return C_ERR_NOMEM; - } - - return C_ERR_OK; -} - -void c_FastByteRingBuffer_Destroy(c_FastByteRingBuffer_t* self) { - if (!self) return; - - C_FREE(self->buffer); - self->capacity = 0; - self->mask = 0; - self->head = 0; - self->tail = 0; - self->is_full = C_FALSE; -} - -// 寫入單一單元組 (極速 O(1)) -c_err_t c_FastByteRingBuffer_WriteByte(c_FastByteRingBuffer_t* self, uint8_t byte) { - if (!self || !self->buffer) return C_ERR_PARAM; - if (self->is_full) return C_ERR_FULL; - - self->buffer[self->tail] = byte; - - // 使用高速位元與運算取代模除 % - self->tail = (self->tail + 1) & self->mask; - - if (self->tail == self->head) { - self->is_full = C_TRUE; - } - - return C_ERR_OK; -} - -// 讀取單一單元組 (極速 O(1)) -c_err_t c_FastByteRingBuffer_ReadByte(c_FastByteRingBuffer_t* self, uint8_t* out_byte) { - if (!self || !self->buffer || !out_byte) return C_ERR_PARAM; - if (c_FastByteRingBuffer_IsEmpty(self)) return C_ERR_EMPTY; - - *out_byte = self->buffer[self->head]; - - // 使用高速位元與運算取代模除 % - self->head = (self->head + 1) & self->mask; - self->is_full = C_FALSE; - - return C_ERR_OK; -} - - -c_size_t c_FastByteRingBuffer_WriteBuffer(c_FastByteRingBuffer_t* self, const uint8_t* src, c_size_t len) { - if (!self || !self->buffer || !src || len == 0) return 0; - if (self->is_full) return 0; - - // Calculate free space directly using fast size validation tracking - c_size_t current_size = c_FastByteRingBuffer_GetSize(self); - c_size_t free_space = self->capacity - current_size; - - // Clamp write operations to avoid overrunning existing readable elements - if (len > free_space) { - len = free_space; - } - - if (len == 0) return 0; - - // Segment 1: Write from tail index up to the physical end boundary of the backing array - c_size_t space_to_end = self->capacity - self->tail; - c_size_t first_chunk = (len < space_to_end) ? len : space_to_end; - memcpy(self->buffer + self->tail, src, first_chunk); - - // Segment 2: Wrap around to index 0 using bitwise optimizations if a split block configuration is required - c_size_t second_chunk = len - first_chunk; - if (second_chunk > 0) { - memcpy(self->buffer, src + first_chunk, second_chunk); - self->tail = second_chunk; // The wrapped tail calculation reduces cleanly to second_chunk - } else { - // Fast tail stepping path utilizing the mask constant - self->tail = (self->tail + first_chunk) & self->mask; - } - - // Set the full status flag if the cursors perfectly intersect - if (self->tail == self->head) { - self->is_full = C_TRUE; - } - - return len; -} - - -// 區塊讀取 -c_size_t c_FastByteRingBuffer_ReadBuffer(c_FastByteRingBuffer_t* self, uint8_t* dest, c_size_t len) { - if (!self || !self->buffer || !dest || len == 0) return 0; - - c_size_t bytes_read = 0; - while (bytes_read < len && !c_FastByteRingBuffer_IsEmpty(self)) { - dest[bytes_read] = self->buffer[self->head]; - self->head = (self->head + 1) & self->mask; - self->is_full = C_FALSE; - bytes_read++; - } - return bytes_read; -} - -c_size_t c_FastByteRingBuffer_GetSize(const c_FastByteRingBuffer_t* self) { - if (!self || !self->buffer) return 0; - if (self->is_full) return self->capacity; - - if (self->tail >= self->head) { - return self->tail - self->head; - } else { - return self->capacity + self->tail - self->head; - } -} - -c_bool_t c_FastByteRingBuffer_IsEmpty(const c_FastByteRingBuffer_t* self) { - if (!self) return C_TRUE; - return (self->head == self->tail) && !self->is_full; -} - -c_bool_t c_FastByteRingBuffer_IsFull(const c_FastByteRingBuffer_t* self) { - if (!self) return C_FALSE; - return self->is_full; -} - - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - - - -C_STATIC_FORCE_INLINE -uint8_t c_FastByteRingBuffer_GetAtRelativeInternal(const c_FastByteRingBuffer_t* self, c_size_t relative_offset) { - c_size_t absolute_index = (self->head + relative_offset) & self->mask; - return self->buffer[absolute_index]; -} - -/* ------------------------------------------------------------------------------------------------------------------ */ - -void c_FastByteRingBuffer_WriteByteOverwrite(c_FastByteRingBuffer_t* self, uint8_t byte) { - if (!self || !self->buffer) return; - - if (self->is_full) { - // 環形陣列已滿時,強制將讀取指標向前推一格,拋棄最舊數據 - self->head = (self->head + 1) & self->mask; - } - - self->buffer[self->tail] = byte; - self->tail = (self->tail + 1) & self->mask; - - if (self->tail == self->head) { - self->is_full = C_TRUE; - } -} - -c_size_t c_FastByteRingBuffer_WriteBufferOverwrite(c_FastByteRingBuffer_t* self, const uint8_t* src, c_size_t len) { - if (!self || !self->buffer || !src || len == 0) return 0; - - // 邊界極端優化:如果寫入長度超過總容量,只有最後符合容量大小的數據能存活 - if (len >= self->capacity) { - src += (len - self->capacity); - len = self->capacity; - - memcpy(self->buffer, src, len); - self->head = 0; - self->tail = 0; - self->is_full = C_TRUE; - return len; - } - - c_size_t size = c_FastByteRingBuffer_GetSize(self); - c_size_t free_space = self->capacity - size; - - // 若寫入長度大於剩餘空間,計算溢出量並自動同步前推 head 指標 - if (len > free_space) { - c_size_t overwrite_count = len - free_space; - self->head = (self->head + overwrite_count) & self->mask; - } - - // 分段一:從 tail 寫入到物理內存陣列末尾 - c_size_t space_to_end = self->capacity - self->tail; - c_size_t first_chunk = (len < space_to_end) ? len : space_to_end; - memcpy(self->buffer + self->tail, src, first_chunk); - - // 分段二:折返到內存陣列開頭寫入剩餘數據 - c_size_t second_chunk = len - first_chunk; - if (second_chunk > 0) { - memcpy(self->buffer, src + first_chunk, second_chunk); - self->tail = second_chunk; - } else { - self->tail = (self->tail + first_chunk) & self->mask; - } - - if (self->tail == self->head) { - self->is_full = C_TRUE; - } else { - self->is_full = C_FALSE; - } - - return len; -} - -c_err_t c_FastByteRingBuffer_PeekByte(const c_FastByteRingBuffer_t* self, uint8_t* out_byte) { - if (!self || !self->buffer || !out_byte) return C_ERR_PARAM; - if (c_FastByteRingBuffer_IsEmpty(self)) return C_ERR_EMPTY; - - *out_byte = self->buffer[self->head]; - return C_SUCCESS; -} - -c_size_t c_FastByteRingBuffer_PeekBuffer(const c_FastByteRingBuffer_t* self, uint8_t* dest, c_size_t len) { - if (!self || !self->buffer || !dest || len == 0) return 0; - - c_size_t available_bytes = c_FastByteRingBuffer_GetSize(self); - if (len > available_bytes) { - len = available_bytes; - } - - if (len == 0) return 0; - - // 複製標準讀取邏輯,但完全不變動真實核心 head 指標狀態 - c_size_t bytes_to_end = self->capacity - self->head; - c_size_t first_chunk = (len < bytes_to_end) ? len : bytes_to_end; - memcpy(dest, self->buffer + self->head, first_chunk); - - c_size_t second_chunk = len - first_chunk; - if (second_chunk > 0) { - memcpy(dest + first_chunk, self->buffer, second_chunk); - } - - return len; -} - -c_size_t c_FastByteRingBuffer_Discard(c_FastByteRingBuffer_t* self, c_size_t len) { - if (!self || !self->buffer || len == 0) return 0; - - c_size_t available_bytes = c_FastByteRingBuffer_GetSize(self); - if (len > available_bytes) { - len = available_bytes; - } - - if (len == 0) return 0; - - self->head = (self->head + len) & self->mask; - self->is_full = C_FALSE; - - return len; -} - -const uint8_t* c_FastByteRingBuffer_GetReadPtr(const c_FastByteRingBuffer_t* self, c_size_t* out_contiguous_len) { - if (!self || !self->buffer || !out_contiguous_len) return NULL; - - *out_contiguous_len = 0; - if (c_FastByteRingBuffer_IsEmpty(self)) return NULL; - - if (self->tail > self->head) { - *out_contiguous_len = self->tail - self->head; - } else { - *out_contiguous_len = self->capacity - self->head; - } - - return self->buffer + self->head; -} - -uint8_t* c_FastByteRingBuffer_GetWritePtr(const c_FastByteRingBuffer_t* self, c_size_t* out_contiguous_len) { - if (!self || !self->buffer || !out_contiguous_len) return NULL; - - *out_contiguous_len = 0; - if (self->is_full) return NULL; - - if (self->tail >= self->head) { - *out_contiguous_len = self->capacity - self->tail; - } else { - *out_contiguous_len = self->head - self->tail; - } - - return self->buffer + self->tail; -} - -c_index_t c_FastByteRingBuffer_IndexOfByte(const c_FastByteRingBuffer_t* self, uint8_t target) { - if (!self || !self->buffer) return C_ERR_FAIL; - - c_size_t total_size = c_FastByteRingBuffer_GetSize(self); - for (c_size_t offset = 0; offset < total_size; offset++) { - if (c_FastByteRingBuffer_GetAtRelativeInternal(self, offset) == target) { - return (c_index_t)offset; - } - } - return C_ERR_NOTFOUND; -} - -c_index_t c_FastByteRingBuffer_IndexOfBuffer(const c_FastByteRingBuffer_t* self, const uint8_t* pattern, c_size_t pattern_len) { - if (!self || !self->buffer || !pattern || pattern_len == 0) return C_ERR_FAIL; - - c_size_t total_size = c_FastByteRingBuffer_GetSize(self); - if (pattern_len > total_size) return C_ERR_FAIL; - - c_size_t max_search_offset = total_size - pattern_len; - - for (c_size_t offset = 0; offset <= max_search_offset; offset++) { - c_bool_t match_found = C_TRUE; - - for (c_size_t p_idx = 0; p_idx < pattern_len; p_idx++) { - if (c_FastByteRingBuffer_GetAtRelativeInternal(self, offset + p_idx) != pattern[p_idx]) { - match_found = C_FALSE; - break; - } - } - - if (match_found) { - return (c_index_t)offset; - } - } - return C_ERR_FAIL; -} - -c_index_t c_FastByteRingBuffer_LastIndexOfBuffer(const c_FastByteRingBuffer_t* self, const uint8_t* pattern, c_size_t pattern_len) { - if (!self || !self->buffer || !pattern || pattern_len == 0) return C_ERR_FAIL; - - c_size_t total_size = c_FastByteRingBuffer_GetSize(self); - if (pattern_len > total_size) return C_ERR_FAIL; - - c_size_t max_search_offset = total_size - pattern_len; - - for (c_size_t offset = max_search_offset; ; offset--) { - c_bool_t match_found = C_TRUE; - - for (c_size_t p_idx = 0; p_idx < pattern_len; p_idx++) { - if (c_FastByteRingBuffer_GetAtRelativeInternal(self, offset + p_idx) != pattern[p_idx]) { - match_found = C_FALSE; - break; - } - } - - if (match_found) { - return (c_index_t)offset; - } - - if (offset == 0) break; - } - return C_ERR_FAIL; -} - -c_size_t c_FastByteRingBuffer_ReadUntilToken(c_FastByteRingBuffer_t* self, const uint8_t* token, c_size_t token_len, uint8_t* dest, c_size_t dest_max_len) { - if (!self || !self->buffer || !token || token_len == 0 || !dest || dest_max_len == 0) return 0; - - c_index_t match_offset = c_FastByteRingBuffer_IndexOfBuffer(self, token, token_len); - if (match_offset == C_ERR_FAIL) { - return 0; - } - - c_size_t aggregate_bytes = (c_size_t)match_offset + token_len; - if (aggregate_bytes > dest_max_len) { - return 0; // 避免目標緩衝區溢出 - } - - return c_FastByteRingBuffer_ReadBuffer(self, dest, aggregate_bytes); -} - -c_err_t c_FastByteRingBuffer_GetAtRelative(const c_FastByteRingBuffer_t* self, c_size_t relative_offset, uint8_t* out_byte) { - if (!self || !self->buffer || !out_byte) return C_ERR_PARAM; - - c_size_t active_size = c_FastByteRingBuffer_GetSize(self); - if (relative_offset >= active_size) { - return C_ERR_OUTOFBOUND; - } - - *out_byte = c_FastByteRingBuffer_GetAtRelativeInternal(self, relative_offset); - return C_SUCCESS; -} - -c_bool_t c_FastByteRingBuffer_Is(const c_FastByteRingBuffer_t* self, c_index_t offset, uint8_t value) { - if (!self || !self->buffer || offset < 0) return C_FALSE; - - c_size_t active_size = c_FastByteRingBuffer_GetSize(self); - if ((c_size_t)offset >= active_size) return C_FALSE; - - return (c_FastByteRingBuffer_GetAtRelativeInternal(self, (c_size_t)offset) == value) ? C_TRUE : C_FALSE; -} - -int c_FastByteRingBuffer_Memcmp(const c_FastByteRingBuffer_t* self, c_size_t offset, const uint8_t* buffer, c_size_t len) { - if (!self || !self->buffer || !buffer) return C_ERR_PARAM; - if (len == 0) return 0; - - c_size_t active_size = c_FastByteRingBuffer_GetSize(self); - if (offset >= active_size || (offset + len) > active_size) { - return C_ERR_OUTOFBOUND; - } - - c_size_t absolute_start = (self->head + offset) & self->mask; - c_size_t bytes_to_end = self->capacity - absolute_start; - - if (len <= bytes_to_end) { - return memcmp(self->buffer + absolute_start, buffer, len); - } else { - int first_segment_match = memcmp(self->buffer + absolute_start, buffer, bytes_to_end); - if (first_segment_match != 0) { - return first_segment_match; - } - return memcmp(self->buffer, buffer + bytes_to_end, len - bytes_to_end); - } -} - - - -c_err_t c_FastByteRingBuffer_Strtoul(const c_FastByteRingBuffer_t* self, c_size_t offset, int base, unsigned long* out_value, c_size_t* out_end_offset) { - if (!self || !self->buffer || !out_value) return C_ERR_PARAM; - - c_size_t total_size = c_FastByteRingBuffer_GetSize(self); - if (offset >= total_size) return C_ERR_OUTOFBOUND; - - // 1. Skip leading spaces safely using fast inline relative scans - c_size_t scan_idx = offset; - while (scan_idx < total_size) { - uint8_t byte = c_FastByteRingBuffer_GetAtRelativeInternal(self, scan_idx); - if (!isspace(byte)) break; - scan_idx++; - } - - if (scan_idx == total_size) return C_ERR_PARAM; // Contains only whitespace - - // 2. Locate trailing delimiters to calculate numeric chunk span width - c_size_t start_numeric_offset = scan_idx; - c_size_t numeric_len = 0; - while (scan_idx < total_size) { - uint8_t byte = c_FastByteRingBuffer_GetAtRelativeInternal(self, scan_idx); - // Include numerical modifiers (+, -), hex identifiers (x, X) and alphanumeric bases - if (!isalnum(byte) && byte != '+' && byte != '-') { - break; - } - numeric_len++; - scan_idx++; - } - - if (numeric_len == 0) return C_ERR_PARAM; - - // 3. Resolve the starting index using bitwise mask instead of slow % operators - c_size_t absolute_start = (self->head + start_numeric_offset) & self->mask; - c_size_t bytes_to_end = self->capacity - absolute_start; - - unsigned long result = 0; - char* parse_end = NULL; - int current_errno = errno; - errno = 0; - - // Fast-path: Segment runs contiguous without wrapping lines - if (numeric_len <= bytes_to_end) { - const char* flat_ptr = (const char*)(self->buffer + absolute_start); - result = strtoul(flat_ptr, &parse_end, base); - - c_size_t parsed_bytes = (c_size_t)(parse_end - flat_ptr); - if (parsed_bytes == 0 || parse_end == flat_ptr) { - errno = current_errno; - return C_ERR_PARAM; - } - - if (errno == ERANGE) return C_ERR_OUTOFBOUND; - - *out_value = result; - if (out_end_offset) { - *out_end_offset = start_numeric_offset + parsed_bytes; - } - } else { - // Slow-path: Structural wrap configuration requires localized stack flattening - if (numeric_len >= 64) return C_ERR_OUTOFBOUND; - - char stack_scratch[64]; - for (c_size_t i = 0; i < numeric_len; i++) { - stack_scratch[i] = (char)c_FastByteRingBuffer_GetAtRelativeInternal(self, start_numeric_offset + i); - } - stack_scratch[numeric_len] = '\0'; // Guarantee absolute zero string termination - - result = strtoul(stack_scratch, &parse_end, base); - c_size_t parsed_bytes = (c_size_t)(parse_end - stack_scratch); - - if (parsed_bytes == 0 || parse_end == stack_scratch) { - errno = current_errno; - return C_ERR_PARAM; - } - - if (errno == ERANGE) return C_ERR_OUTOFBOUND; - - *out_value = result; - if (out_end_offset) { - *out_end_offset = start_numeric_offset + parsed_bytes; - } - } - - errno = current_errno; // Preserve runtime environment variables smoothly - return C_SUCCESS; -} diff --git a/Foundation/c_FastByteRingBuffer.h b/Foundation/c_FastByteRingBuffer.h deleted file mode 100644 index 263796d..0000000 --- a/Foundation/c_FastByteRingBuffer.h +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef INCLUDED_C_FASTBYTERINGBUFFER_H -#define INCLUDED_C_FASTBYTERINGBUFFER_H - -#ifndef INCLUDED_C_TYPES_H -#include -#endif /*INCLUDED_C_TYPES_H*/ - - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -typedef struct { - uint8_t* buffer; // 連續的位元組陣列 - c_size_t capacity; // 必為 2 的冪次方 (e.g., 16, 32, 64, 256) - c_size_t mask; // 快取 (capacity - 1),用來進行位元與運算 - c_size_t head; // 讀取指標 - c_size_t tail; // 寫入指標 - c_bool_t is_full; // 狀態區分旗標 -} c_FastByteRingBuffer_t; - -c_err_t c_FastByteRingBuffer_Init(c_FastByteRingBuffer_t* self, c_size_t capacity); -void c_FastByteRingBuffer_Destroy(c_FastByteRingBuffer_t* self); - -c_err_t c_FastByteRingBuffer_WriteByte(c_FastByteRingBuffer_t* self, uint8_t byte); -c_err_t c_FastByteRingBuffer_ReadByte(c_FastByteRingBuffer_t* self, uint8_t* out_byte); - -/* - * Writes a bulk buffer span into the fast ring buffer without overwriting existing data. - * @param self: The fast ring buffer instance. - * @param src: Source byte array pointer. - * @param len: Number of bytes to transfer. - * @return The actual number of bytes written into the buffer. - */ -c_size_t c_FastByteRingBuffer_WriteBuffer(c_FastByteRingBuffer_t* self, const uint8_t* src, c_size_t len); - -c_size_t c_FastByteRingBuffer_ReadBuffer(c_FastByteRingBuffer_t* self, uint8_t* dest, c_size_t len); - -c_size_t c_FastByteRingBuffer_GetSize(const c_FastByteRingBuffer_t* self); -c_bool_t c_FastByteRingBuffer_IsEmpty(const c_FastByteRingBuffer_t* self); -c_bool_t c_FastByteRingBuffer_IsFull(const c_FastByteRingBuffer_t* self); - - -/* 新增的進階控制接口 */ -void c_FastByteRingBuffer_WriteByteOverwrite(c_FastByteRingBuffer_t* self, uint8_t byte); -c_size_t c_FastByteRingBuffer_WriteBufferOverwrite(c_FastByteRingBuffer_t* self, const uint8_t* src, c_size_t len); - -c_err_t c_FastByteRingBuffer_PeekByte(const c_FastByteRingBuffer_t* self, uint8_t* out_byte); -c_size_t c_FastByteRingBuffer_PeekBuffer(const c_FastByteRingBuffer_t* self, uint8_t* dest, c_size_t len); - -c_size_t c_FastByteRingBuffer_Discard(c_FastByteRingBuffer_t* self, c_size_t len); -const uint8_t* c_FastByteRingBuffer_GetReadPtr(const c_FastByteRingBuffer_t* self, c_size_t* out_contiguous_len); -uint8_t* c_FastByteRingBuffer_GetWritePtr(const c_FastByteRingBuffer_t* self, c_size_t* out_contiguous_len); - - -c_index_t c_FastByteRingBuffer_IndexOfByte(const c_FastByteRingBuffer_t* self, uint8_t target); -c_index_t c_FastByteRingBuffer_IndexOfBuffer(const c_FastByteRingBuffer_t* self, const uint8_t* pattern, c_size_t pattern_len); -c_index_t c_FastByteRingBuffer_LastIndexOfBuffer(const c_FastByteRingBuffer_t* self, const uint8_t* pattern, c_size_t pattern_len); - -c_size_t c_FastByteRingBuffer_ReadUntilToken(c_FastByteRingBuffer_t* self, const uint8_t* token, c_size_t token_len, uint8_t* dest, c_size_t dest_max_len); -c_err_t c_FastByteRingBuffer_GetAtRelative(const c_FastByteRingBuffer_t* self, c_size_t relative_offset, uint8_t* out_byte); -c_bool_t c_FastByteRingBuffer_Is(const c_FastByteRingBuffer_t* self, c_index_t offset, uint8_t value); -int c_FastByteRingBuffer_Memcmp(const c_FastByteRingBuffer_t* self, c_size_t offset, const uint8_t* buffer, c_size_t len); -c_err_t c_FastByteRingBuffer_Strtoul(const c_FastByteRingBuffer_t* self, c_size_t offset, int base, unsigned long* out_value, c_size_t* out_end_offset); - - -#endif /*INCLUDED_C_FASTBYTERINGBUFFER_H*/ diff --git a/Foundation/c_FastByteRingBuffer.t.c b/Foundation/c_FastByteRingBuffer.t.c deleted file mode 100644 index 3657055..0000000 --- a/Foundation/c_FastByteRingBuffer.t.c +++ /dev/null @@ -1,343 +0,0 @@ -#include "c_FastByteRingBuffer.h" -#include -#include -#include - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - - -#define RUN_TEST_CASE(test_func) \ - do { \ - printf("[RUNNING] %-40s ... ", #test_func); \ - fflush(stdout); \ - test_func(); \ - printf("[PASSED]\n"); \ - } while (0) - -void test_ring_buffer_behavior(void) { - c_FastByteRingBuffer_t ring; - // Capacity initialization must be a power of two - assert(c_FastByteRingBuffer_Init(&ring, 4) == C_SUCCESS); - - uint8_t input_stream[] = {0x11, 0x22, 0x33}; - - // 1. Verify standard incremental writing actions - assert(c_FastByteRingBuffer_WriteBuffer(&ring, input_stream, 3) == 3); - assert(c_FastByteRingBuffer_GetSize(&ring) == 3); - - // 2. Verify overflow rejection clamping protection - uint8_t flood_stream[] = {0x44, 0x55}; - // Only 1 byte of free space remains out of total capacity 4 - assert(c_FastByteRingBuffer_WriteBuffer(&ring, flood_stream, 2) == 1); - assert(c_FastByteRingBuffer_IsFull(&ring) == C_TRUE); - - // Check data integrity via peek operations - uint8_t output_peek[4] = {0}; - c_FastByteRingBuffer_PeekBuffer(&ring, output_peek, 4); - assert(output_peek[0] == 0x11); - assert(output_peek[3] == 0x44); // 0x44 filled the last slot; 0x55 was cleanly rejected - - c_FastByteRingBuffer_Destroy(&ring); -} - -static void test_overwrite_and_peek_mechanics(void) { - c_FastByteRingBuffer_t ring; - assert(c_FastByteRingBuffer_Init(&ring, 4) == C_SUCCESS); // Capacity = 4 - - // 1. Validate Single Overwrite - c_FastByteRingBuffer_WriteByte(&ring, 0x01); - c_FastByteRingBuffer_WriteByte(&ring, 0x02); - c_FastByteRingBuffer_WriteByte(&ring, 0x03); - c_FastByteRingBuffer_WriteByte(&ring, 0x04); // Buffer now full: [0x01, 0x02, 0x03, 0x04] - assert(c_FastByteRingBuffer_IsFull(&ring) == C_TRUE); - - c_FastByteRingBuffer_WriteByteOverwrite(&ring, 0x05); // 0x01 gets evicted. Head shifts to 0x02 - - uint8_t peek_check = 0; - assert(c_FastByteRingBuffer_PeekByte(&ring, &peek_check) == C_SUCCESS); - assert(peek_check == 0x02); // FIFO rules dictate oldest remaining byte is 0x02 - - // 2. Validate Bulk Overwrite Loops - uint8_t incoming_stream[3] = {0x06, 0x07, 0x08}; - // Ring has 4 bytes capacity. Writing 3 bytes over an already full buffer evicts [0x02, 0x03, 0x04] - assert(c_FastByteRingBuffer_WriteBufferOverwrite(&ring, incoming_stream, 3) == 3); - - uint8_t verification_dump[4] = {0}; - c_size_t read_out = c_FastByteRingBuffer_PeekBuffer(&ring, verification_dump, 4); - assert(read_out == 4); - assert(verification_dump[0] == 0x05); // Preserved from previous transaction - assert(verification_dump[1] == 0x06); - assert(verification_dump[2] == 0x07); - assert(verification_dump[3] == 0x08); - - // 3. Confirm Peek leaves data sequence entirely untouched - assert(c_FastByteRingBuffer_GetSize(&ring) == 4); - - c_FastByteRingBuffer_Destroy(&ring); -} - -static void test_dma_and_discard_mechanics(void) { - c_FastByteRingBuffer_t ring; - assert(c_FastByteRingBuffer_Init(&ring, 8) == C_SUCCESS); // Capacity = 8 - - // Force initialization of data that loops around the internal ring memory map - uint8_t payload[] = {0xA1, 0xA2, 0xA3, 0xA4, 0xA5}; - c_FastByteRingBuffer_WriteBuffer(&ring, payload, 5); - - // Discard oldest 2 items: drops 0xA1, 0xA2. Cursors shift. - assert(c_FastByteRingBuffer_Discard(&ring, 2) == 2); - assert(c_FastByteRingBuffer_GetSize(&ring) == 3); - - // Write some more to force a wrap-around layout - uint8_t wrap_payload[] = {0xB1, 0xB2, 0xB3, 0xB4}; - c_FastByteRingBuffer_WriteBuffer(&ring, wrap_payload, 4); // Total size now = 7 bytes - - // Validate GetReadPtr isolates Block Segment 1 cleanly - c_size_t read_chunk_len = 0; - const uint8_t* read_ptr = c_FastByteRingBuffer_GetReadPtr(&ring, &read_chunk_len); - - assert(read_ptr != NULL); - // Head was shifted to index 2. 8 - 2 = 6 available linearly up to memory array edge - assert(read_chunk_len == 6); - assert(read_ptr[0] == 0xA3); // First remaining item - - // Clear those processed items via direct execution tracking - c_FastByteRingBuffer_Discard(&ring, read_chunk_len); - - // Call secondary pass to capture remaining wrapped bytes - read_ptr = c_FastByteRingBuffer_GetReadPtr(&ring, &read_chunk_len); - assert(read_chunk_len == 1); - assert(read_ptr[0] == 0xB4); // Wrapped character check - - c_FastByteRingBuffer_Destroy(&ring); -} - -static void test_ring_buffer_index_searching(void) { - c_FastByteRingBuffer_t ring; - assert(c_FastByteRingBuffer_Init(&ring, 8) == C_SUCCESS); // Capacity = 8 - - // Force a data write footprint that wraps around the buffer margins - uint8_t standard_fill[] = {0x00, 0x00, 0x00, 0x00, 0x11, 0x22, 0x33, 0x44}; - c_FastByteRingBuffer_WriteBuffer(&ring, standard_fill, 8); - - // Discard 4 elements to position head cursor at absolute index 4 - c_FastByteRingBuffer_Discard(&ring, 4); - - // Append sequence to cross edge wrap boundaries cleanly - uint8_t wrap_fill[] = {0x55, 0x66, 0x77}; - c_FastByteRingBuffer_WriteBuffer(&ring, wrap_fill, 3); - // Dynamic ring content layout from head: [0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77] - - // 1. Single byte search lookup match - assert(c_FastByteRingBuffer_IndexOfByte(&ring, 0x33) == 2); // Relative offset index 2 from head - assert(c_FastByteRingBuffer_IndexOfByte(&ring, 0x99) == C_ERR_NOTFOUND); - - // 2. Pattern buffer sequence scan (testing across structural wrap-around edge boundaries) - uint8_t search_pattern[] = {0x44, 0x55, 0x66}; - c_index_t match_offset = c_FastByteRingBuffer_IndexOfBuffer(&ring, search_pattern, 3); - - assert(match_offset == 3); // 0x44 sits exactly at relative offset position 3 - - // Application Workflow Integration: Cleanly discard up to token match prefix point - c_FastByteRingBuffer_Discard(&ring, (c_size_t)match_offset); - uint8_t current_head_byte = 0; - c_FastByteRingBuffer_PeekByte(&ring, ¤t_head_byte); - assert(current_head_byte == 0x44); // The buffer head has been successfully synchronized to the token location - - c_FastByteRingBuffer_Destroy(&ring); -} - -static void test_reverse_search_and_token_stream(void) { - c_FastByteRingBuffer_t ring; - assert(c_FastByteRingBuffer_Init(&ring, 8) == C_SUCCESS); // Capacity = 8 - - uint8_t raw_payload[] = {0xAA, 0x11, 0x22, 0xBB, 0x11, 0x22, 0xCC, 0xDD}; - c_FastByteRingBuffer_WriteBuffer(&ring, raw_payload, 8); - - uint8_t pattern[] = {0x11, 0x22}; - - // 1. Verify Reverse Pattern Detection Matches Latest Occurrence - assert(c_FastByteRingBuffer_IndexOfBuffer(&ring, pattern, 2) == 1); // First pair starts at offset 1 - assert(c_FastByteRingBuffer_LastIndexOfBuffer(&ring, pattern, 2) == 4); // Latest pair starts at offset 4 - - // 2. Clear out buffer to run frame serialization test - c_FastByteRingBuffer_Discard(&ring, 8); - - uint8_t stream_data[] = {'P', 'a', 'c', 'k', 'e', 't', '\r', '\n'}; - c_FastByteRingBuffer_WriteBuffer(&ring, stream_data, 8); - - uint8_t frame_terminator[] = {'\r', '\n'}; - uint8_t output_staging[16] = {0}; - - // Fail Case: Pass a staging array that is structurally too cramped to hold the payload safely - assert(c_FastByteRingBuffer_ReadUntilToken(&ring, frame_terminator, 2, output_staging, 5) == 0); - assert(c_FastByteRingBuffer_GetSize(&ring) == 8); // Data remains locked safely inside the ring - - // Success Case: Pass a valid container size to execute frame extraction - c_size_t read_bytes = c_FastByteRingBuffer_ReadUntilToken(&ring, frame_terminator, 2, output_staging, 16); - assert(read_bytes == 8); - assert(memcmp(output_staging, "Packet\r\n", 8) == 0); - assert(c_FastByteRingBuffer_IsEmpty(&ring) == C_TRUE); // Frame has been cleanly consumed from the queue - - c_FastByteRingBuffer_Destroy(&ring); -} - -static void test_relative_random_access(void) { - c_FastByteRingBuffer_t ring; - assert(c_FastByteRingBuffer_Init(&ring, 4) == C_SUCCESS); // Capacity = 4 - - uint8_t seed_data[] = {0x10, 0x20, 0x30}; - c_FastByteRingBuffer_WriteBuffer(&ring, seed_data, 3); - - // Shift the head pointer downstream via a single byte consumption - uint8_t discard_sink = 0; - c_FastByteRingBuffer_ReadByte(&ring, &discard_sink); // 0x10 dropped. Head points to 0x20 - - // Append items to cross physical wrapping thresholds cleanly - c_FastByteRingBuffer_WriteByte(&ring, 0x40); - c_FastByteRingBuffer_WriteByte(&ring, 0x50); // Buffer contents: [0x20, 0x30, 0x40, 0x50] - - uint8_t extracted_byte = 0; - - // 1. Verify standard random read coordinates relative to the head position - assert(c_FastByteRingBuffer_GetAtRelative(&ring, 0, &extracted_byte) == C_SUCCESS); - assert(extracted_byte == 0x20); // Relative 0 points directly to the current head - - assert(c_FastByteRingBuffer_GetAtRelative(&ring, 2, &extracted_byte) == C_SUCCESS); - assert(extracted_byte == 0x40); // Wrapped index check - - assert(c_FastByteRingBuffer_GetAtRelative(&ring, 3, &extracted_byte) == C_SUCCESS); - assert(extracted_byte == 0x50); // Newest unread byte check - - // 2. Validate bounds-checking flags - assert(c_FastByteRingBuffer_GetAtRelative(&ring, 4, &extracted_byte) == C_ERR_OUTOFBOUND); - assert(c_FastByteRingBuffer_GetAtRelative(&ring, 99, &extracted_byte) == C_ERR_OUTOFBOUND); - assert(c_FastByteRingBuffer_GetAtRelative(NULL, 0, &extracted_byte) == C_ERR_PARAM); - - c_FastByteRingBuffer_Destroy(&ring); -} - -static void test_conditional_is_validator(void) { - c_FastByteRingBuffer_t ring; - assert(c_FastByteRingBuffer_Init(&ring, 4) == C_SUCCESS); - - uint8_t input_stream[] = {0xAA, 0xBB, 0xCC}; - c_FastByteRingBuffer_WriteBuffer(&ring, input_stream, 3); - - // 1. Validate clean true/false matches relative to the head - assert(c_FastByteRingBuffer_Is(&ring, 0, 0xAA) == C_TRUE); // Oldest byte at head matches - assert(c_FastByteRingBuffer_Is(&ring, 1, 0xBB) == C_TRUE); // Next element matches - assert(c_FastByteRingBuffer_Is(&ring, 1, 0x99) == C_FALSE); // Mismatch returns false - - // Consume 1 byte to advance the head pointer and test wrapping boundaries - uint8_t sink = 0; - c_FastByteRingBuffer_ReadByte(&ring, &sink); // Head now points to 0xBB - c_FastByteRingBuffer_WriteByte(&ring, 0xDD); // Layout: [..., 0xBB, 0xCC, 0xDD] - - // 2. Re-verify offsets after structural pointer wrap shifts - assert(c_FastByteRingBuffer_Is(&ring, 0, 0xBB) == C_TRUE); // Head index position 0 is now 0xBB - assert(c_FastByteRingBuffer_Is(&ring, 2, 0xDD) == C_TRUE); // Wrapped index element match - - // 3. Confirm error/bounds conditions return false instead of blowing up memory layout boundaries - assert(c_FastByteRingBuffer_Is(&ring, 3, 0x00) == C_FALSE); // Out of bounds index - assert(c_FastByteRingBuffer_Is(&ring, -5, 0xBB) == C_FALSE); // Negative index handling protection - assert(c_FastByteRingBuffer_Is(NULL, 0, 0xBB) == C_FALSE); // NULL safety check - - c_FastByteRingBuffer_Destroy(&ring); -} - -static void test_ring_buffer_memcmp(void) { - c_FastByteRingBuffer_t ring; - assert(c_FastByteRingBuffer_Init(&ring, 6) == C_ERR_PARAM); // Capacity = 6 - - assert(c_FastByteRingBuffer_Init(&ring, 8) == C_SUCCESS); // Capacity = 6 - uint8_t payload[] = {0x00, 0x11, 0x22, 0x33}; - c_FastByteRingBuffer_WriteBuffer(&ring, payload, 4); - - // Consume 2 bytes to step the head pointer forward to absolute index 2 - uint8_t sink = 0; - c_FastByteRingBuffer_ReadByte(&ring, &sink); - c_FastByteRingBuffer_ReadByte(&ring, &sink); // Buffer active layout from head: [0x22, 0x33] - - // Append data to trigger an explicit physical wrap-around edge split layout - uint8_t wrap_payload[] = {0x44, 0x55, 0x66}; - c_FastByteRingBuffer_WriteBuffer(&ring, wrap_payload, 3); - // Buffer dynamic content path tracking from head: [0x22, 0x33, 0x44, 0x55, 0x66] - // Physical layout behind indices inside array: [0x55, 0x66, 0x22, 0x33, 0x44, ...] - - // 1. Validate contiguous segment match comparisons - uint8_t check_a[] = {0x22, 0x33}; - assert(c_FastByteRingBuffer_Memcmp(&ring, 0, check_a, 2) == 0); // Perfect contiguous match - - // 2. Validate multi-segment wrap-around comparison mechanics - uint8_t check_b[] = {0x33, 0x44, 0x55, 0x66}; - assert(c_FastByteRingBuffer_Memcmp(&ring, 1, check_b, 4) == 0); // Perfect split wrap-around match - - // 3. Mismatch checks - uint8_t check_mismatch[] = {0x33, 0x44, 0x99, 0x66}; - assert(c_FastByteRingBuffer_Memcmp(&ring, 1, check_mismatch, 4) != 0); // Identifies internal divergence - - // 4. Bounds and parameter checks - assert(c_FastByteRingBuffer_Memcmp(&ring, 0, check_b, 100) == C_ERR_OUTOFBOUND); // Request width overflows content - assert(c_FastByteRingBuffer_Memcmp(&ring, 99, check_b, 1) == C_ERR_OUTOFBOUND); // Start pointer invalid - assert(c_FastByteRingBuffer_Memcmp(NULL, 0, check_b, 1) == C_ERR_PARAM); - - c_FastByteRingBuffer_Destroy(&ring); -} -static void test_ring_buffer_strtoul(void) { - c_FastByteRingBuffer_t ring; - assert(c_FastByteRingBuffer_Init(&ring, 8) == C_SUCCESS); // Capacity = 8 - - // 1. Standard Linear Base-10 Parsing - uint8_t input_a[] = {'1', '2', '3', '4', ' ', 'A', 'B', 'C'}; - c_FastByteRingBuffer_WriteBuffer(&ring, input_a, 8); - - unsigned long parsed_val = 0; - c_size_t end_offset = 0; - - assert(c_FastByteRingBuffer_Strtoul(&ring, 0, 10, &parsed_val, &end_offset) == C_SUCCESS); - assert(parsed_val == 1234); - assert(end_offset == 4); // Points exactly to the trailing space character offset - - // Reset buffer tracking lines - c_FastByteRingBuffer_Discard(&ring, 8); - - // 2. Fragmented Wrap Hex Parsing - // Pre-fill 5 elements to push cursor indices near wrapping layout boundaries - uint8_t pre_fill[] = {0, 0, 0, 0, 0}; - c_FastByteRingBuffer_WriteBuffer(&ring, pre_fill, 5); - c_FastByteRingBuffer_Discard(&ring, 5); // Head pointer sits at physical index 5 - - // Write Hex parameter payload string ("0x2F") across memory boundaries - uint8_t input_hex[] = {'0', 'x', '2', 'F'}; - c_FastByteRingBuffer_WriteBuffer(&ring, input_hex, 4); - - assert(c_FastByteRingBuffer_Strtoul(&ring, 0, 16, &parsed_val, &end_offset) == C_SUCCESS); - assert(parsed_val == 47); // 0x2F translates to decimal 47 - assert(end_offset == 4); - - c_FastByteRingBuffer_Destroy(&ring); -} - - -int main() { - printf("==================================================\n"); - printf(" Starting c_FastByteRingBuffer Unit Testing Suite\n"); - printf("==================================================\n\n"); - - RUN_TEST_CASE(test_ring_buffer_behavior); - RUN_TEST_CASE(test_overwrite_and_peek_mechanics); - RUN_TEST_CASE(test_dma_and_discard_mechanics); - RUN_TEST_CASE(test_ring_buffer_index_searching); - RUN_TEST_CASE(test_reverse_search_and_token_stream); - RUN_TEST_CASE(test_relative_random_access); - RUN_TEST_CASE(test_conditional_is_validator); - RUN_TEST_CASE(test_ring_buffer_memcmp); - RUN_TEST_CASE(test_ring_buffer_strtoul); - - printf("\n==================================================\n"); - printf(" Success! Byte RingBuffer tests passed!\n"); - printf("==================================================\n"); - return 0; -} \ No newline at end of file diff --git a/Foundation/c_File.c b/Foundation/c_File.c deleted file mode 100644 index a730129..0000000 --- a/Foundation/c_File.c +++ /dev/null @@ -1,488 +0,0 @@ -#include -#ifdef _WIN32 - #include - #include // 提供 _get_osfhandle - #include - #include - #define C_ACCESS(path) _access(path, 0) - #define C_MAKE_DIR(path) _mkdir(path) // Windows 下创建目录 - #define sys_rmdir(path) _rmdir(path) - #define PATH_SEP '\\' -#else - #include // 提供 fsync - #include - #include - #define C_ACCESS(path) access(path, F_OK) - #define C_MAKE_DIR(path) mkdir(path, 0755) - #define sys_rmdir(path) rmdir(path) - #define PATH_SEP '/' -#endif - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - - -#if defined(C_PLATFORM_IS_64BIT) - -// 跨平台 64 位 fseek 封装 -C_STATIC_FORCE_INLINE -int fn_fseek(FILE* fp, long long offset, int whence) { -#ifdef _WIN32 - return _fseeki64(fp, (__int64)offset, whence); -#else - // 在定义了 _FILE_OFFSET_BITS=64 的情况下,fseeko 接收 64 位的 off_t - return fseeko(fp, (off_t)offset, whence); -#endif -} - -// 跨平台 64 位 ftell 封装 -C_STATIC_FORCE_INLINE -long long fn_tell(FILE* fp) { -#ifdef _WIN32 - return (long long)_ftelli64(fp); -#else - return (long long)ftello(fp); -#endif -} - -#elif defined(C_PLATFORM_IS_32BIT) - -C_STATIC_FORCE_INLINE -int fn_fseek(FILE* fp, long long offset, int whence) { - return fseek(fp, (long)offset, whence); -} - -C_STATIC_FORCE_INLINE -long long fn_tell(FILE* fp) { - return (long long)ftell(fp); -} - -#endif - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - - -c_err_t c_File_Open(c_File_t* file, const char* fileName, const char* mode) { - if (!file || !fileName || !mode) { - return C_ERR_FAIL; - } - - file->fp = fopen(fileName, mode); - if (!file->fp) { - return C_ERR_FAIL; - } - - return C_ERR_OK; -} - -void c_File_Close(c_File_t* file) { - if (file && file->fp) { - fclose(file->fp); - file->fp = NULL; - } -} - -c_err_t c_File_Read(c_File_t* file, void* buffer, c_size_t buffer_size, c_size_t *read_size) { - if (!file || !file->fp || !buffer || buffer_size == 0) { - if (read_size) *read_size = 0; - return C_ERR_FAIL; - } - - // 从文件流中读取 1 字节 * buffer_size - size_t bytes_read = fread(buffer, 1, (size_t)buffer_size, file->fp); - - if (read_size) { - *read_size = (c_size_t)bytes_read; - } - - // 如果读取数量小于请求数量,需检查是出错还是到达文件末尾 - if (bytes_read < (size_t)buffer_size) { - if (ferror(file->fp)) { - return C_ERR_FAIL; // 发生读取错误 - } - } - - return C_ERR_OK; -} - -c_err_t c_File_Readline(c_File_t* file, void* buffer, c_size_t buffer_size, c_size_t *read_size) { - if (!file || !file->fp || !buffer || buffer_size == 0) { - if (read_size) *read_size = 0; - return C_ERR_FAIL; - } - - // fgets 会自动在末尾加上 '\0',并且最多读取 buffer_size - 1 个字符 - char* result = fgets((char*)buffer, (int)buffer_size, file->fp); - - if (!result) { - if (read_size) *read_size = 0; - return C_ERR_FAIL; // 读取失败或到达文件末尾 - } - - if (read_size) { - *read_size = (c_size_t)strlen((char*)buffer); - } - - return C_ERR_OK; -} - -c_err_t c_File_Write(c_File_t* file, void* buffer, c_size_t buffer_size, c_size_t *write_size) { - if (!file || !file->fp || !buffer || buffer_size == 0) { - if (write_size) *write_size = 0; - return C_ERR_FAIL; - } - - size_t bytes_written = fwrite(buffer, 1, (size_t)buffer_size, file->fp); - - if (write_size) { - *write_size = (c_size_t)bytes_written; - } - - // 如果实际写入字节数不等于预期,说明写入失败(如磁盘满) - if (bytes_written < (size_t)buffer_size) { - return C_ERR_FAIL; - } - - return C_ERR_OK; -} - -c_err_t c_File_Seek(c_File_t* file, long long position) { - if (!file || !file->fp) { - return C_ERR_PARAM; - } - const int result = fseek(file->fp, (long)position, SEEK_SET); - return (result == 0) ? C_ERR_OK : C_ERR_FAIL; -} - -long long c_File_Size(c_File_t* file) { - if (!file || !file->fp) { - return 0; - } - - // 1. 保存当前文件指针的位置 - long long current_pos = fn_tell(file->fp); - if (current_pos == -1LL) return 0; - - // 2. 将文件指针移到末尾 - if (fn_fseek(file->fp, 0, SEEK_END) != C_ERR_OK) return 0; - - // 3. 获取末尾位置即为文件大小 - long long size = fn_tell(file->fp); - - // 4. 恢复原先的文件指针位置 - fn_fseek(file->fp, current_pos, SEEK_SET); - - return (long long)((size < 0) ? 0 : size); -} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -c_err_t c_File_Flush(c_File_t* file) { - if (!file || !file->fp) { - return C_ERR_FAIL; - } - - // Step 1: 先刷新 C 库自带的软件层缓冲区(将数据推入 OS 内核队列) - if (fflush(file->fp) != 0) { - return C_ERR_FAIL; - } - - // Step 2: 获取底层文件描述符,强行驱动硬件刷盘 -#ifdef _WIN32 - // 从 C 语言的 FILE* 提取 Windows 系统的文件句柄 HANDLE - int fd = _fileno(file->fp); - if (fd < 0) return C_ERR_FAIL; - - HANDLE hFile = (HANDLE)_get_osfhandle(fd); - if (hFile == INVALID_HANDLE_VALUE) return C_ERR_FAIL; - - // 强行驱动机械硬盘/SSD硬件将内核缓存写入物理介质 - if (!FlushFileBuffers(hFile)) { - return C_ERR_FAIL; - } -#else - // Linux / macOS 平台直接提取文件描述符 - int fd = fileno(file->fp); - if (fd < 0) return C_ERR_FAIL; - - // 触发 POSIX 的 fsync 系统调用,阻塞直到硬件写入完毕 - if (fsync(fd) != 0) { - return C_ERR_FAIL; - } -#endif - - return C_ERR_OK; -} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -c_bool_t c_File_IsExist(const char* fileName) { - if (!fileName) { - return C_FALSE; - } - - // 参数 0 代表 F_OK,即只检查文件是否存在 - // C_ACCESS 返回 0 表示文件存在且可访问,返回 -1 表示不存在或无权限 - if (C_ACCESS(fileName) == F_OK) { - return C_TRUE; - } - - return C_FALSE; -} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -c_err_t c_File_MkDirs(const char* path) { - if (path == NULL || strlen(path) == 0) { - return C_ERR_PARAM; - } - - char temp_path[512]; - snprintf(temp_path, sizeof(temp_path), "%s", path); - size_t len = strlen(temp_path); - - // 统一将 Windows 的 '\\' 转换为 '/' 方便逐级切分 - for (int i = 0; i < len; i++) { - if (temp_path[i] == '\\') { - temp_path[i] = '/'; - } - } - - // 确保路径以 '/' 结尾,方便循环逻辑处理 - if (temp_path[len - 1] != '/') { - if (len + 1 < sizeof(temp_path)) { - temp_path[len] = '/'; - temp_path[len + 1] = '\0'; - len++; - } else { - return C_ERR_FAIL; // 路径超长 - } - } - - // 逐级探测并创建目录 - for (int i = 0; i < len; i++) { - // 每当遇到路径分隔符 '/' 时,尝试截断并创建当前层级目录 - if (temp_path[i] == '/' && i > 0) { - temp_path[i] = '\0'; // 临时截断字符串 - - // 检查当前级目录是否存在,不存在则创建 - if (C_ACCESS(temp_path) != 0) { - if (C_MAKE_DIR(temp_path) != 0) { - return C_ERR_FAIL; // 创建失败 - } - } - - temp_path[i] = '/'; // 恢复分隔符 - } - } - - return C_SUCCESS; -} - -c_err_t c_File_Rmdir(const char* path) { - if (!path || path[0] == '\0') { - return C_ERR_PARAM; - } - - // 调用操作系统底层移除目录的 API - int result = sys_rmdir(path); - - if (result == 0) { - return C_ERR_OK; // 删除成功 - } else { - // 删除失败(可能是由于目录不存在、无权限、或者目录非空) - return C_ERR_FAIL; - } -} - -c_err_t c_File_Rmdirs(const char* path) { - if (!path || path[0] == '\0') { - return C_ERR_PARAM; - } - - c_err_t status = C_ERR_OK; - -#if defined(_WIN32) || defined(_WIN64) - // ========================================== - // Windows 平台的递归删除实现 - // ========================================== - char search_path[MAX_PATH]; - // Windows 检索目录需要追加 "\\*" - snprintf(search_path, sizeof(search_path), "%s\\*", path); - - WIN32_FIND_DATAA find_data; - HANDLE h_find = FindFirstFileA(search_path, &find_data); - - if (h_find == INVALID_HANDLE_VALUE) { - // 如果目录根本不存在,或者无法打开,尝试直接当做文件 remove 移除(处理符号链接等边界) - return remove(path) == 0 ? C_ERR_OK : C_ERR_FAIL; - } - - do { - // 排除 Windows 的特殊目录 "." 和 ".." - if (strcmp(find_data.cFileName, ".") == 0 || strcmp(find_data.cFileName, "..") == 0) { - continue; - } - - // 拼接子项的完整路径 - char sub_path[MAX_PATH]; - snprintf(sub_path, sizeof(sub_path), "%s\\%s", path, find_data.cFileName); - - if (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - // 如果子项是目录,递归调用 - status = c_File_Rmdirs(sub_path); - } else { - // 如果子项是普通文件,取消只读属性(防止因只读导致删除失败),然后将其删除 - SetFileAttributesA(sub_path, FILE_ATTRIBUTE_NORMAL); - status = (DeleteFileA(sub_path) != 0) ? C_ERR_OK : C_ERR_FAIL; - } - - if (status != C_ERR_OK) { - break; - } - } while (FindNextFileA(h_find, &find_data)); - - FindClose(h_find); - -#else - // ========================================== - // Linux / macOS (POSIX) 平台的递归删除实现 - // ========================================== - DIR* dir = opendir(path); - if (!dir) { - // 无法打开作为目录处理,尝试按普通文件物理删除 - return remove(path) == 0 ? C_ERR_OK : C_ERR_FAIL; - } - - struct dirent* entry; - while ((entry = readdir(dir)) != NULL) { - // 排除 Linux 的特殊目录 "." 和 ".." - if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) { - continue; - } - - // 拼接子项的完整路径 - char sub_path[1024]; - snprintf(sub_path, sizeof(sub_path), "%s/%s", path, entry->d_name); - - struct stat statbuf; - if (stat(sub_path, &statbuf) == 0) { - if (S_ISDIR(statbuf.st_mode)) { - // 如果子项是目录,递归调用 - status = c_File_Rmdirs(sub_path); - } else { - // 如果子项是文件,执行普通删除 - status = (remove(sub_path) == 0) ? C_ERR_OK : C_ERR_FAIL; - } - } - - if (status != C_ERR_OK) { - break; - } - } - closedir(dir); -#endif - - // ========================================== - // 公共收尾:清空了内部所有子项后,最后删除外层空壳目录 - // ========================================== - if (status == C_ERR_OK) { - if (sys_rmdir(path) != 0) { - status = C_ERR_FAIL; - } - } - - return status; -} - -c_err_t c_File_Delete(const char* fileName) { - if (!fileName || fileName[0] == '\0') { - return C_ERR_PARAM; - } - - // 标准 C 库的 remove 能够直接删除文件(在某些平台上也能删除空目录) - int result = remove(fileName); - - if (result == 0) { - return C_ERR_OK; // 删除成功 - } else { - // 删除失败(文件不存在、或无权限、或文件正被某些操作系统强锁占用) - return C_ERR_FAIL; - } -} - -#define COPY_BUFFER_SIZE 4096 - -c_err_t c_File_Copy(const char* srcPath, const char* destPath) { - if (!srcPath || srcPath[0] == '\0' || !destPath || destPath[0] == '\0') { - return C_ERR_PARAM; - } - - FILE* src = fopen(srcPath, "rb"); - if (!src) return C_ERR_NOTFOUND; - - FILE* dest = fopen(destPath, "wb"); - if (!dest) { - fclose(src); - return C_ERR_FAIL; - } - - char* buffer = (char*)malloc(COPY_BUFFER_SIZE); - if (!buffer) { - fclose(src); - fclose(dest); - return C_ERR_FAIL; - } - - c_err_t status = C_ERR_OK; - size_t bytes_read; - - // 循环读写块,避免一次性读入大文件撑爆堆内存 - while ((bytes_read = fread(buffer, 1, COPY_BUFFER_SIZE, src)) > 0) { - size_t bytes_written = fwrite(buffer, 1, bytes_read, dest); - if (bytes_written < bytes_read) { - status = C_ERR_FAIL; // 磁盘空间不足或写入错误 - break; - } - } - - free(buffer); - fclose(src); - fclose(dest); - - // 如果中途失败,清理掉生成的不完整目标文件 - if (status != C_ERR_OK) { - remove(destPath); - } - - return status; -} - -c_err_t c_File_Move(const char* oldPath, const char* newPath) { - if (!oldPath || oldPath[0] == '\0' || !newPath || newPath[0] == '\0') { - return C_ERR_PARAM; - } - - // 1. 尝试使用操作系统原生的轻量级重命名/移动 - if (rename(oldPath, newPath) == 0) { - return C_ERR_OK; - } - - // 2. 跨分区保底策略:如果因为跨文件系统挂载点导致 rename 失败,则执行 复制 + 删除 - c_err_t copy_err = c_File_Copy(oldPath, newPath); - if (copy_err == C_ERR_OK) { - if (remove(oldPath) == 0) { - return C_ERR_OK; - } else { - // 如果删原文件失败,为了数据安全,把新拷过去的文件也撤销,避免数据状态不一致 - remove(newPath); - return C_ERR_FAIL; - } - } - - return C_ERR_FAIL; -} diff --git a/Foundation/c_File.h b/Foundation/c_File.h deleted file mode 100644 index 583de3d..0000000 --- a/Foundation/c_File.h +++ /dev/null @@ -1,74 +0,0 @@ -#ifndef INCLUDED_C_FILE_H -#define INCLUDED_C_FILE_H - -#ifndef INCLUDED_C_TYPES_H -#include -#endif /*INCLUDED_C_TYPES_H*/ - -#ifndef INCLUDED_STDIO_H -#define INCLUDED_STDIO_H -#include -#endif /*INCLUDED_STDIO_H*/ - - - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - - -typedef struct { - FILE* fp; -}c_File_t; - - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -c_err_t c_File_Open(c_File_t* file, const char* fileName, const char* mode); - -void c_File_Close(c_File_t* file); - -c_err_t c_File_Read(c_File_t* file, void* buffer, c_size_t buffer_size, c_size_t *read_size); - -c_err_t c_File_Readline(c_File_t* file, void* buffer, c_size_t buffer_size, c_size_t *read_size); - -c_err_t c_File_Write(c_File_t* file, void* buffer, c_size_t buffer_size, c_size_t *write_size); - -long long c_File_Size(c_File_t* file); - -c_err_t c_File_Flush(c_File_t* file); - -c_err_t c_File_Seek(c_File_t* file, long long position); - -c_err_t c_File_MkDirs(const char* path); - -c_err_t c_File_Rmdir(const char* path); - -c_err_t c_File_Rmdirs(const char* path); - -c_err_t c_File_Delete(const char* fileName); - -/** - * @brief 复制指定文件到目标路径(支持大文件流式拷贝) - * @param srcPath 源文件路径 - * @param destPath 目标文件路径 - * @return 成功返回 C_ERR_OK,失败返回对应错误码 - */ -c_err_t c_File_Copy(const char* srcPath, const char* destPath); - -/** - * @brief 检查指定路径的文件或目录是否存在 - * @param fileName 文件的绝对路径或相对路径 - * @return 存在返回 C_TRUE,不存在或无权限返回 C_FALSE - */ -c_bool_t c_File_IsExist(const char* fileName); - -/** - * @brief 移动或重命名文件(支持跨分区移动保底) - * @param oldPath 旧文件路径 - * @param newPath 新文件路径 - * @return 成功返回 C_ERR_OK,失败返回对应错误码 - */ -c_err_t c_File_Move(const char* oldPath, const char* newPath); - -#endif /*INCLUDED_C_FILE_H*/ diff --git a/Foundation/c_File.t.c b/Foundation/c_File.t.c deleted file mode 100644 index cf9d35e..0000000 --- a/Foundation/c_File.t.c +++ /dev/null @@ -1,365 +0,0 @@ -#include "c_File.h" -#include -#include -#include - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -static const char* TEST_DIR = "./test_sandbox"; -static const char* TEST_FILE = "./test_sandbox/test_data.txt"; -static const char* NESTED_DIR_ROOT = "./test_sandbox_deep"; -static const char* NESTED_DIR_SUB1 = "./test_sandbox_deep/level1"; -static const char* NESTED_DIR_SUB2 = "./test_sandbox_deep/level1/level2"; -static const char* NESTED_DEEP_FILE = "./test_sandbox_deep/level1/level2/target.txt"; -static const char* TEST_DEL_FILE = "./test_sandbox/delete_target.txt"; -static const char* FILE_SRC = "./test_sandbox/copy_src.txt"; -static const char* FILE_COPY = "./test_sandbox/copy_dest.txt"; -static const char* FILE_MOVE = "./test_sandbox/move_dest.txt"; - -static c_File_t g_file; - -// 每个文件测试开始前:创建目录确保沙盒环境存在,并重置文件结构体 -void setup_file_env() { - c_File_MkDirs(TEST_DIR); - g_file.fp = NULL; -} - -// 每个文件测试结束后:强制关闭可能遗留的文件流,并清理生成的临时测试文件 -void teardown_file_env() { - if (g_file.fp != NULL) { - c_File_Close(&g_file); - } - // 移除沙盒内的文件(如果存在) - remove(TEST_FILE); - // 移除沙盒目录(Linux/macOS 下使用 rmdir,为保持跨平台通用这里主要移除文件) - remove(TEST_DIR); -} - -void setup_deep_dir_env() { - // 1. 建立一个多级深层嵌套的目录 - c_File_MkDirs(NESTED_DIR_SUB2); -} - -void teardown_deep_dir_env() { - // 兜底清理:如果测试挂了,防止残留污染本地磁盘 - // 在这里直接调用它自己完成强制扫尾 - c_File_Rmdirs(NESTED_DIR_ROOT); -} - -void setup_delete_env() { - // 确保测试沙盒目录存在 - c_File_MkDirs("./test_sandbox"); -} - -void teardown_delete_env() { - // 扫尾清理,防止测试中断导致文件残留 - remove(TEST_DEL_FILE); - remove("./test_sandbox"); -} - - -void setup_move_copy_env() { - c_File_MkDirs("./test_sandbox"); -} - -void teardown_move_copy_env() { - // 强制清理,防止测试中断产生磁盘残留 - remove(FILE_SRC); - remove(FILE_COPY); - remove(FILE_MOVE); - remove("./test_sandbox"); -} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - - -void test_file_write_and_size() { - // 1. 以只写/新建模式打开文件 - c_err_t err = c_File_Open(&g_file, TEST_FILE, "wb"); - ASSERT_INT_EQ_MSG(C_ERR_OK, err, "Failed to open file for writing"); - ASSERT_MSG(g_file.fp != NULL, "File pointer should not be NULL after open"); - - // 2. 检查刚创建的文件是否存在 - ASSERT_MSG(c_File_IsExist(TEST_FILE) == C_TRUE, "File should exist on disk"); - - // 3. 写入数据 - const char* content = "Hello TinyTest Framework!"; - c_size_t bytes_to_write = strlen(content); - c_size_t bytes_written = 0; - - err = c_File_Write(&g_file, (void*)content, bytes_to_write, &bytes_written); - ASSERT_INT_EQ_MSG(C_ERR_OK, err, "File write error"); - ASSERT_INT_EQ_MSG((int)bytes_to_write, (int)bytes_written, "Written size mismatched"); - - // 4. 刷新缓冲区 - err = c_File_Flush(&g_file); - ASSERT_INT_EQ_MSG(C_ERR_OK, err, "File flush error"); - - // 5. 校验文件大小是否和写入的字节数严格对齐 - long long f_size = c_File_Size(&g_file); - ASSERT_INT_EQ_MSG((int)bytes_to_write, (int)f_size, "File size reported incorrectly"); - - // 6. 正常关闭文件 - c_File_Close(&g_file); -} - - -// 用例 2:测试文件的读取(Read)以及指针重定位(Seek) -void test_file_read_and_seek() { - // 预备工作:先写入一串已知文本用于后续测试 - c_File_Open(&g_file, TEST_FILE, "wb"); - const char* dummy_data = "abcdefghij"; // 10 字节 - c_size_t written = 0; - c_File_Write(&g_file, (void*)dummy_data, 10, &written); - c_File_Close(&g_file); - - // 1. 以只读模式重新打开文件 - c_err_t err = c_File_Open(&g_file, TEST_FILE, "rb"); - ASSERT_INT_EQ_MSG(C_ERR_OK, err, "Failed to open file for reading"); - - // 2. 测试基础顺序读取(先读取 4 字节,应该读到 "abcd") - char buffer[16] = {0}; - c_size_t bytes_read = 0; - err = c_File_Read(&g_file, buffer, 4, &bytes_read); - ASSERT_INT_EQ_MSG(C_ERR_OK, err, "File read error"); - ASSERT_INT_EQ_MSG(4, (int)bytes_read, "Should read exactly 4 bytes"); - ASSERT_INT_EQ_MSG(0, memcmp(buffer, "abcd", 4), "Buffer content mismatches on initial read"); - - // 3. 测试文件指针重定位:移到绝对位置索引 5 处(对应字符 'f') - err = c_File_Seek(&g_file, 5); - ASSERT_INT_EQ_MSG(C_ERR_OK, err, "File seek error"); - - // 4. 定位后再次读取 3 字节(应该读到 "fgh") - memset(buffer, 0, sizeof(buffer)); - err = c_File_Read(&g_file, buffer, 3, &bytes_read); - ASSERT_INT_EQ_MSG(C_ERR_OK, err, "File read error after seeking"); - ASSERT_INT_EQ_MSG(3, (int)bytes_read, "Should read 3 bytes after seek"); - ASSERT_INT_EQ_MSG(0, memcmp(buffer, "fgh", 3), "Buffer content mismatches after seek"); - - c_File_Close(&g_file); -} - - -// 用例 3:测试按行读取(Readline)文本的边界与断行识别 -void test_file_read_line() { - // 预备工作:写入包含多行换行符的文本 - c_File_Open(&g_file, TEST_FILE, "wb"); - const char* lines = "Line1\nLine2\r\nLine3"; - c_size_t written = 0; - c_File_Write(&g_file, (void*)lines, strlen(lines), &written); - c_File_Close(&g_file); - - // 1. 打开文件开始按行验证 - c_File_Open(&g_file, TEST_FILE, "rb"); - - char line_buf[32]; - c_size_t read_len = 0; - - // 读取第一行(预期为 "Line1\n" 或处理掉换行符的 "Line1" 视你内部实现而定,通常 fgets 保留换行) - c_err_t err = c_File_Readline(&g_file, line_buf, sizeof(line_buf), &read_len); - ASSERT_INT_EQ_MSG(C_ERR_OK, err, "Readline 1 failed"); - ASSERT_MSG(strstr(line_buf, "Line1") != NULL, "Line 1 content error"); - - // 读取第二行 - err = c_File_Readline(&g_file, line_buf, sizeof(line_buf), &read_len); - ASSERT_INT_EQ_MSG(C_ERR_OK, err, "Readline 2 failed"); - ASSERT_MSG(strstr(line_buf, "Line2") != NULL, "Line 2 content error"); - - c_File_Close(&g_file); -} - - -// 用例 4:测试文件不存在、无效路径时的防御性报错 -void test_file_invalid_operations() { - // 1. 检查一个绝对不存在的文件 - c_bool_t exist = c_File_IsExist("./this_file_does_not_exist_12345.xyz"); - ASSERT_INT_EQ_MSG(C_FALSE, exist, "IsExist should return FALSE for phantom files"); - - // 2. 尝试打开一个不存在的文件用于只读,应当安全返回错误码,且内部指针保持为 NULL - c_File_t bad_file = {NULL}; - c_err_t err = c_File_Open(&bad_file, "./phantom_file.txt", "rb"); - ASSERT_MSG(err != C_ERR_OK, "Opening non-existent file for read must fail"); - ASSERT_MSG(bad_file.fp == NULL, "Failed open must keep fp as NULL"); -} - -void test_file_rmdirs_force_delete_nested() { - // 1. 验证前置多级目录环境已经被 SetUp 成功拉起 - ASSERT_MSG(c_File_IsExist(NESTED_DIR_SUB2) == C_TRUE, "Setup failed to prepare nested dir"); - - // 2. 在最深层目录 level2 里写入一个真实的文本文件,夯实其“非空”属性 - c_File_t file; - c_err_t err = c_File_Open(&file, NESTED_DEEP_FILE, "wb"); - ASSERT_INT_EQ_MSG(C_ERR_OK, err, "Failed to create deep file inside test sandbox"); - - const char* dummy = "deep data"; - c_size_t written = 0; - c_File_Write(&file, (void*)dummy, strlen(dummy), &written); - c_File_Close(&file); - - // 再次确认文件已在磁盘落地 - ASSERT_MSG(c_File_IsExist(NESTED_DEEP_FILE) == C_TRUE, "Deep text file should exist before wipe"); - - // 3. 一剑封喉:直接调用 Rmdirs 强删最外层的根目录 NESTED_DIR_ROOT - c_err_t rmdir_status = c_File_Rmdirs(NESTED_DIR_ROOT); - ASSERT_INT_EQ_MSG(C_ERR_OK, rmdir_status, "c_File_Rmdirs failed to clear nested architecture"); - - // 4. 断言验证:整棵目录树必须从盘面上被完全抹除 - ASSERT_MSG(c_File_IsExist(NESTED_DEEP_FILE) == C_FALSE, "Deep file should have been blasted"); - ASSERT_MSG(c_File_IsExist(NESTED_DIR_SUB2) == C_FALSE, "Level 2 directory should be wiped"); - ASSERT_MSG(c_File_IsExist(NESTED_DIR_ROOT) == C_FALSE, "Root sandbox directory must be cleared"); -} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -// 用例 1:测试常规文件的正常创建与成功删除 -void test_file_delete_success() { - // 1. 先创建一个真实的文件 - c_File_t file; - c_err_t err = c_File_Open(&file, TEST_DEL_FILE, "wb"); - ASSERT_INT_EQ_MSG(C_ERR_OK, err, "Failed to create delete-target file"); - - const char* dummy = "delete me"; - c_size_t written = 0; - c_File_Write(&file, (void*)dummy, strlen(dummy), &written); - c_File_Close(&file); - - // 2. 确认文件确实落地并在磁盘中存在 - ASSERT_MSG(c_File_IsExist(TEST_DEL_FILE) == C_TRUE, "Target file must exist before deletion"); - - // 3. 执行删除操作 - c_err_t del_err = c_File_Delete(TEST_DEL_FILE); - ASSERT_INT_EQ_MSG(C_ERR_OK, del_err, "c_File_Delete failed on a standard closed file"); - - // 4. 再次验证文件是否已经从文件系统中消失 - ASSERT_MSG(c_File_IsExist(TEST_DEL_FILE) == C_FALSE, "Target file should be gone after c_File_Delete"); -} - -// 用例 2:测试删除一个完全不存在的文件时的防御表现 -void test_file_delete_non_existent() { - const char* phantom_file = "./test_sandbox/ghost_file_999.xyz"; - - // 确保该路径当前确实不存在 - ASSERT_MSG(c_File_IsExist(phantom_file) == C_FALSE, "Phantom file should not exist"); - - // 尝试执行删除 - c_err_t err = c_File_Delete(phantom_file); - - // 应当安全返回非 OK 的错误状态,且程序绝不能发生崩溃 - ASSERT_MSG(err != C_ERR_OK, "c_File_Delete must report an error when trying to delete a non-existent file"); -} - -// 用例 3:测试删除一个正处于“打开/占用状态”的文件(进阶边界测试) -void test_file_delete_while_open() { - // 1. 创建并保持打开该文件,故意不执行 Close - c_File_t file; - c_err_t err = c_File_Open(&file, TEST_DEL_FILE, "wb"); - ASSERT_INT_EQ_MSG(C_ERR_OK, err, "Failed to open file for lock-test"); - - // 2. 尝试在文件流未关闭的情况下,强行调用接口删除它 - c_err_t del_err = c_File_Delete(TEST_DEL_FILE); - - /* - * 注意:这里的断言取决于你对框架跨平台容忍度的设计。 - * - Windows 底层会因为文件处于 Share Violation 锁死状态而直接拒绝删除,返回错误码(del_err != C_ERR_OK)。 - * - Linux / POSIX 则允许执行 unlink 删除,表现为返回 C_ERR_OK,但文件直到 Close 后才会真正释放空间。 - * 为了让你的测试能在多平台安全兼容,我们主要确保程序不会挂死崩溃,并打印当前表现。 - */ - printf(" [INFO] c_File_Delete while open returned: %d (Platform dependent behaviour)\n", del_err); - - // 无论刚才删除成功与否,为了测试框架的安全,我们都要显式地进行资源关闭和文件清理 - c_File_Close(&file); - remove(TEST_DEL_FILE); -} - -// 用例 1:验证文件流式复制 c_File_Copy -void test_file_copy_integrity() { - // 1. 准备源文件并写入特定文本 - c_File_t src_file; - c_File_Open(&src_file, FILE_SRC, "wb"); - const char* pattern = "Copy & Move Structural Verification Data."; - c_size_t written = 0; - c_File_Write(&src_file, (void*)pattern, strlen(pattern), &written); - c_File_Close(&src_file); - - // 2. 调用复制函数 - c_err_t err = c_File_Copy(FILE_SRC, FILE_COPY); - ASSERT_INT_EQ_MSG(C_ERR_OK, err, "c_File_Copy execution failed"); - - // 3. 断言验证:目标文件必须存在,且大小必须完全一致 - ASSERT_MSG(c_File_IsExist(FILE_COPY) == C_TRUE, "Copied target file does not exist"); - - c_File_t dest_file; - c_File_Open(&dest_file, FILE_COPY, "rb"); - long long copy_size = c_File_Size(&dest_file); - - char read_buf[128] = {0}; - c_size_t read_bytes = 0; - c_File_Read(&dest_file, read_buf, sizeof(read_buf) - 1, &read_bytes); - c_File_Close(&dest_file); - - ASSERT_INT_EQ_MSG((int)strlen(pattern), (int)copy_size, "Copied file size mismatches"); - ASSERT_INT_EQ_MSG(0, strcmp(pattern, read_buf), "Copied data content corruption detected"); -} - -// 用例 2:验证文件移动与重命名 c_File_Move -void test_file_move_behavior() { - // 1. 再次在旧路径上创建一个基准文件 - c_File_t src_file; - c_File_Open(&src_file, FILE_SRC, "wb"); - const char* payload = "MovePayload"; - c_size_t written = 0; - c_File_Write(&src_file, (void*)payload, strlen(payload), &written); - c_File_Close(&src_file); - - // 2. 调用移动函数 - c_err_t err = c_File_Move(FILE_SRC, FILE_MOVE); - ASSERT_INT_EQ_MSG(C_ERR_OK, err, "c_File_Move execution failed"); - - // 3. 断言验证:【关键点】旧文件必须在文件系统中消失,新路径下必须出现该文件 - ASSERT_MSG(c_File_IsExist(FILE_SRC) == C_FALSE, "Source file should be gone after move"); - ASSERT_MSG(c_File_IsExist(FILE_MOVE) == C_TRUE, "Moved destination file should exist"); - - // 4. 读取内容验证原子性与准确性 - c_File_t moved_file; - c_File_Open(&moved_file, FILE_MOVE, "rb"); - char read_buf[32] = {0}; - c_size_t read_bytes = 0; - c_File_Read(&moved_file, read_buf, sizeof(read_buf) - 1, &read_bytes); - c_File_Close(&moved_file); - - ASSERT_INT_EQ_MSG(0, strcmp(payload, read_buf), "Moved file content mismatches"); -} - -// 用例 3:验证对非正常状态路径(不存在的源文件)调用 Copy 的防御机制 -void test_file_copy_non_existent() { - c_err_t err = c_File_Copy("./test_sandbox/non_exist_source_xyz.dat", FILE_COPY); - // 应该优雅报错,不能返回 C_ERR_OK - ASSERT_MSG(err != C_ERR_OK, "Copying a non-existent file must return error status"); -} - -int main(int argc, char** argv){ - - TEST_START(Starting Unit Tests); - - RUN_TEST_FIXTURE(test_file_write_and_size, setup_file_env, teardown_file_env); - RUN_TEST_FIXTURE(test_file_read_and_seek, setup_file_env, teardown_file_env); - RUN_TEST_FIXTURE(test_file_read_line, setup_file_env, teardown_file_env); - RUN_TEST_FIXTURE(test_file_invalid_operations, setup_file_env, teardown_file_env); - RUN_TEST_FIXTURE(test_file_rmdirs_force_delete_nested, setup_deep_dir_env, teardown_deep_dir_env); - RUN_TEST_FIXTURE(test_file_delete_success, setup_delete_env, teardown_delete_env); - RUN_TEST_FIXTURE(test_file_delete_non_existent, setup_delete_env, teardown_delete_env); - RUN_TEST_FIXTURE(test_file_delete_while_open, setup_delete_env, teardown_delete_env); - RUN_TEST_FIXTURE(test_file_copy_integrity, setup_move_copy_env, teardown_move_copy_env); - RUN_TEST_FIXTURE(test_file_move_behavior, setup_move_copy_env, teardown_move_copy_env); - RUN_TEST_FIXTURE(test_file_copy_non_existent, setup_move_copy_env, teardown_move_copy_env); - - // 打印最终统计报告 - TEST_REPORT(); - - RETURN_TEST_STATUS; - - return 0; -} diff --git a/Foundation/c_FileIter.c b/Foundation/c_FileIter.c deleted file mode 100644 index 447e415..0000000 --- a/Foundation/c_FileIter.c +++ /dev/null @@ -1,220 +0,0 @@ -#include -#include -#include - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - - -#ifdef _WIN32 - #include - typedef struct { - HANDLE hFind; - WIN32_FIND_DATAA findData; - } WinIterCtx; -#else - -#ifndef _FILE_OFFSET_BITS -#define _FILE_OFFSET_BITS 64 -#endif - -#include -#include -#include -#include - -typedef struct { - DIR* dir; -} PosixIterCtx; - -#endif - - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -// 内部辅助函数:获取下一个有效条目(过滤 "." 和 "..") -static void c_FileIter_InternalFetch(c_FileIter_t* iter) { -#ifdef _WIN32 - WinIterCtx* ctx = (WinIterCtx*)iter->internal_ctx; - while (FindNextFileA(ctx->hFind, &ctx->findData)) { - if (strcmp(ctx->findData.cFileName, ".") == 0 || strcmp(ctx->findData.cFileName, "..") == 0) { - continue; // 过滤 - } - // 填充缓存 - strncpy(iter->current.name, ctx->findData.cFileName, sizeof(iter->current.name) - 1); - iter->current.name[sizeof(iter->current.name) - 1] = '\0'; - - if (ctx->findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - iter->current.type = C_FILE_TYPE_DIR; - iter->current.size = 0; - } else { - iter->current.type = C_FILE_TYPE_REGULAR; - iter->current.size = ((unsigned long long)ctx->findData.nFileSizeHigh << 32) | ctx->findData.nFileSizeLow; - } - iter->has_next = C_TRUE; - return; - } -#else - PosixIterCtx* ctx = (PosixIterCtx*)iter->internal_ctx; - struct dirent* entry; - while ((entry = readdir(ctx->dir)) != NULL) { - if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) { - continue; // 过滤 - } - // 填充名字 - strncpy(iter->current.name, entry->d_name, sizeof(iter->current.name) - 1); - iter->current.name[sizeof(iter->current.name) - 1] = '\0'; - - // 组装完整路径获取大文件大小及类型 - char full_path[512]; - snprintf(full_path, sizeof(full_path), "%s/%s", iter->base_path, entry->d_name); - struct stat stat_buf; - - if (stat(full_path, &stat_buf) == 0) { - iter->current.size = (unsigned long long)stat_buf.st_size; - if (S_ISDIR(stat_buf.st_mode)) { - iter->current.type = C_FILE_TYPE_DIR; - } else if (S_ISREG(stat_buf.st_mode)) { - iter->current.type = C_FILE_TYPE_REGULAR; - } else { - iter->current.type = C_FILE_TYPE_UNKNOWN; - } - } else { - iter->current.type = C_FILE_TYPE_UNKNOWN; - iter->current.size = 0; - } - iter->has_next = C_TRUE; - return; - } -#endif - - // 没有更多文件了,触发自动资源清理 - iter->has_next = C_FALSE; - if (iter->internal_ctx) { -#ifdef _WIN32 - FindClose(((WinIterCtx*)iter->internal_ctx)->hFind); -#else - closedir(((PosixIterCtx*)iter->internal_ctx)->dir); -#endif - C_FREE(iter->internal_ctx); - iter->internal_ctx = NULL; - } -} - - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -c_err_t c_FileIter_Init(c_FileIter_t* iter, const char* dirpath) { - if (!iter || !dirpath) return C_ERR_FAIL; - - iter->internal_ctx = NULL; - iter->has_next = C_FALSE; - strncpy(iter->base_path, dirpath, sizeof(iter->base_path) - 1); - iter->base_path[sizeof(iter->base_path) - 1] = '\0'; - -#ifdef _WIN32 - WinIterCtx* ctx = (WinIterCtx*)C_ALLOC(sizeof(WinIterCtx)); - if (!ctx) return C_ERR_FAIL; - - char search_path[512]; - snprintf(search_path, sizeof(search_path), "%s\\*", dirpath); - - ctx->hFind = FindFirstFile(search_path, &ctx->findData); - if (ctx->hFind == INVALID_HANDLE_VALUE) { - C_FREE(ctx); - return C_ERR_FAIL; - } - iter->internal_ctx = ctx; - - // 检查第一个读取到的是否是 "." 或 "..",如果是,则继续查找有效文件 - if (strcmp(ctx->findData.cFileName, ".") == 0 || strcmp(ctx->findData.cFileName, "..") == 0) { - c_FileIter_InternalFetch(iter); - } else { - strncpy(iter->current.name, ctx->findData.cFileName, sizeof(iter->current.name) - 1); - iter->current.name[sizeof(iter->current.name) - 1] = '\0'; - if (ctx->findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - iter->current.type = C_FILE_TYPE_DIR; - iter->current.size = 0; - } else { - iter->current.type = C_FILE_TYPE_REGULAR; - iter->current.size = ((unsigned long long)ctx->findData.nFileSizeHigh << 32) | ctx->findData.nFileSizeLow; - } - iter->has_next = C_TRUE; - } -#else - PosixIterCtx* ctx = (PosixIterCtx*)C_ALLOC(sizeof(PosixIterCtx)); - if (!ctx) return C_ERR_FAIL; - - ctx->dir = opendir(dirpath); - if (!ctx->dir) { - C_FREE(ctx); - return C_ERR_FAIL; - } - iter->internal_ctx = ctx; - - // 触发预读第一项 - c_FileIter_InternalFetch(iter); -#endif - - return C_ERR_OK; -} - -c_bool_t c_FileIter_HasNext(c_FileIter_t* iter) { - return (iter != NULL) ? iter->has_next : C_FALSE; -} - -void c_FileIter_Next(c_FileIter_t* iter) { - if (iter && iter->has_next) { - c_FileIter_InternalFetch(iter); - } -} - -const c_FileEntry_t* c_FileIter_Get(c_FileIter_t* iter) { - if (iter && iter->has_next) { - return &(iter->current); - } - return NULL; -} - -c_err_t c_FileIter_Remove(c_FileIter_t* iter) { - if (!iter || !iter->has_next) return C_ERR_FAIL; - - char full_path[512]; -#ifdef _WIN32 - snprintf(full_path, sizeof(full_path), "%s\\%s", iter->base_path, iter->current.name); -#else - snprintf(full_path, sizeof(full_path), "%s/%s", iter->base_path, iter->current.name); -#endif - - int res = -1; - if (iter->current.type == C_FILE_TYPE_DIR) { -#ifdef _WIN32 - res = RemoveDirectory(full_path) ? 0 : -1; -#else - res = rmdir(full_path); -#endif - } else { -#ifdef _WIN32 - res = DeleteFile(full_path) ? 0 : -1; -#else - res = unlink(full_path); -#endif - } - - // 执行完物理删除后,提前释放当前迭代器的内部流句柄,防止调用者后续发生未知异常 - iter->has_next = C_FALSE; - if (iter->internal_ctx) { -#ifdef _WIN32 - FindClose(((WinIterCtx*)iter->internal_ctx)->hFind); -#else - closedir(((PosixIterCtx*)iter->internal_ctx)->dir); -#endif - C_FREE(iter->internal_ctx); - iter->internal_ctx = NULL; - } - - return (res == 0) ? C_ERR_OK : C_ERR_FAIL; -} - diff --git a/Foundation/c_FileIter.h b/Foundation/c_FileIter.h deleted file mode 100644 index fde3659..0000000 --- a/Foundation/c_FileIter.h +++ /dev/null @@ -1,63 +0,0 @@ -#ifndef INCLUDED_C_FILEITER_H -#define INCLUDED_C_FILEITER_H - -#ifndef INCLUDED_C_TYPES_H -#include -#endif /*INCLUDED_C_TYPES_H*/ - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -// 文件类型枚举 -typedef enum { - C_FILE_TYPE_REGULAR, // 普通文件 - C_FILE_TYPE_DIR, // 目录 - C_FILE_TYPE_UNKNOWN // 未知 -} c_FileType_t; - -// 迭代器当前指向的文件/目录条目信息 -typedef struct { - char name[256]; // 文件/文件夹名称 - c_FileType_t type; // 类型 - unsigned long long size; // 文件大小(适配大文件) -} c_FileEntry_t; - -// 迭代器结构体定义(隐藏平台差异) -typedef struct { - void* internal_ctx; // 内部上下文指针,用于隔离平台的目录句柄状态 - c_FileEntry_t current; // 当前读取到的条目缓存 - int has_next; // 是否还有下一个有效条目的状态标识 - char base_path[256]; // 记录初始目录路径(Remove 函数需要拼接完整路径) -} c_FileIter_t; - - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* 目录迭代器 API */ - -/** - * @brief 初始化目录迭代器,并预读第一个有效条目 - */ -c_err_t c_FileIter_Init(c_FileIter_t* iter, const char* dirpath); - -/** - * @brief 判断是否还有下一个条目 - */ -c_bool_t c_FileIter_HasNext(c_FileIter_t* iter); - -/** - * @brief 步进到下一个有效的条目,并自动过滤 "." 和 ".." - */ -void c_FileIter_Next(c_FileIter_t* iter); - -/** - * @brief 获取当前条目的只读指针 - */ -const c_FileEntry_t* c_FileIter_Get(c_FileIter_t* iter); - -/** - * @brief 删除当前迭代器指向的文件或空目录,并自动安全释放迭代器资源 - */ -c_err_t c_FileIter_Remove(c_FileIter_t* iter); - - -#endif /*INCLUDED_C_FILEITER_H*/ diff --git a/Foundation/c_FileIter.t.c b/Foundation/c_FileIter.t.c deleted file mode 100644 index 4f170f4..0000000 --- a/Foundation/c_FileIter.t.c +++ /dev/null @@ -1,33 +0,0 @@ -#include "c_FileIter.h" -#include -#include - - -int main() { - c_FileIter_t iter; - - // 初始化迭代器,目标为当前目录 "." - if (c_FileIter_Init(&iter, ".") == C_ERR_OK) { - printf("开始遍历目录文件:\n"); - - // 使用经典的迭代器标准循环结构 - while (c_FileIter_HasNext(&iter)) { - const c_FileEntry_t* entry = c_FileIter_Get(&iter); - if (entry) { - if (entry->type == C_FILE_TYPE_DIR) { - printf("[DIR] %s\n", entry->name); - } else { - printf("[FILE] %-25s 大小: %llu 字节\n", entry->name, entry->size); - } - } - - // 推进到下一个文件 - c_FileIter_Next(&iter); - } - printf("遍历结束,资源已自动安全回收。\n"); - } else { - printf("无法初始化目录迭代器!\n"); - } - - return 0; -} diff --git a/Foundation/c_Float.c b/Foundation/c_Float.c deleted file mode 100644 index 281b872..0000000 --- a/Foundation/c_Float.c +++ /dev/null @@ -1,915 +0,0 @@ -#include -#include - -uint32_t c_Float_Add(uint32_t a, uint32_t b) { - // 1. 提取特殊狀態與快速零值返回 - if ((a & ~C_FLOAT_SIGN_MASK) == 0) return b; - if ((b & ~C_FLOAT_SIGN_MASK) == 0) return a; - - uint32_t sign_a = a & C_FLOAT_SIGN_MASK; - uint32_t sign_b = b & C_FLOAT_SIGN_MASK; - int32_t exp_a = (int32_t)((a & C_FLOAT_EXP_MASK) >> 23); - int32_t exp_b = (int32_t)((b & C_FLOAT_EXP_MASK) >> 23); - uint32_t frac_a = a & C_FLOAT_FRAC_MASK; - uint32_t frac_b = b & C_FLOAT_FRAC_MASK; - - // ========================================== - // 修复 Bug 1:严格遵循 IEEE 754 的 NaN / Inf 拦截规则 - // ========================================== - if (exp_a == 255 || exp_b == 255) { - // 条件 1.1:若任一为真正的 NaN(指数全1,尾数不为0),则传播 NaN - if ((exp_a == 255 && frac_a != 0) || (exp_b == 255 && frac_b != 0)) { - return 0x7FC00000U; // 返回 Quiet NaN - } - // 条件 1.2:若两者都是无穷大,且符号相反(+Inf + -Inf),属于未定义,必须强行返回 NaN - if (exp_a == 255 && exp_b == 255 && sign_a != sign_b) { - return 0x7FC00000U; // 熔断返回 NaN - } - // 条件 1.3:普通的无穷大传播(如 Inf + 有限数 = Inf) - return (exp_a == 255) ? a : b; - } - - // ========================================== - // 修复 Bug 3:更正非规格化数的隐藏位逻辑(exp==0 时隐藏位是 0,且不能左移) - // ========================================== - frac_a = (exp_a == 0) ? frac_a : (frac_a | C_FLOAT_HIDDEN_BIT); - frac_b = (exp_b == 0) ? frac_b : (frac_b | C_FLOAT_HIDDEN_BIT); - if (exp_a == 0) exp_a = 1; - if (exp_b == 0) exp_b = 1; - - // 开辟 GRS 保护位空间 - frac_a <<= 3; - frac_b <<= 3; - - int32_t exp_res = exp_a; - uint32_t sticky = 0; - - // 3. 對階(Align Exponents) - if (exp_a > exp_b) { - int32_t shift = exp_a - exp_b; - // 修复 Bug 2:防止大跨度对阶时左移掩码溢出未定义行为 - if (shift >= 27) { - sticky = (frac_b != 0); - frac_b = 0; - } else { - sticky = (frac_b & ~((~0U) << shift)) != 0; - frac_b >>= shift; - } - frac_b |= sticky; - exp_res = exp_a; - } else if (exp_b > exp_a) { - int32_t shift = exp_b - exp_a; - // 修复 Bug 2:同理防护 - if (shift >= 27) { - sticky = (frac_a != 0); - frac_a = 0; - } else { - sticky = (frac_a & ~((~0U) << shift)) != 0; - frac_a >>= shift; - } - frac_a |= sticky; - exp_res = exp_b; - } - - // 4. 尾數運算 - uint32_t sign_res; - uint32_t frac_res; - - if (sign_a == sign_b) { - sign_res = sign_a; - frac_res = frac_a + frac_b; - } else { - if (frac_a >= frac_b) { - sign_res = sign_a; - frac_res = frac_a - frac_b; - } else { - sign_res = sign_b; - frac_res = frac_b - frac_a; - } - if (frac_res == 0) return 0x00000000U; // 正负抵消返回标准 +0.0 - } - - // 5. 規格化 - if (frac_res & (1U << 27)) { - // 修复 Bug 4:修正右移 1 位时的 Sticky 保留逻辑 - uint32_t lost_bit = frac_res & 1U; - frac_res >>= 1; - frac_res |= lost_bit; - exp_res++; - } else { - while (!(frac_res & (1U << 26)) && exp_res > 1) { - frac_res <<= 1; - exp_res--; - } - if (!(frac_res & (1U << 26)) && exp_res == 1) { - exp_res = 0; - } - } - - // 6. 溢出至無限大檢查 - if (exp_res >= 255) { - return sign_res | C_FLOAT_EXP_MASK; - } - - // 7. 向最接近偶數捨入(Round-to-Nearest-Even) - uint32_t round_bits = frac_res & 7U; - frac_res >>= 3; - - if ((round_bits > 4) || ((round_bits == 4) && (frac_res & 1U))) { - frac_res++; - if (frac_res & (1U << 24)) { - frac_res >>= 1; - exp_res++; - if (exp_res >= 255) return sign_res | C_FLOAT_EXP_MASK; - } - } - - if (exp_res != 0) { - frac_res &= C_FLOAT_FRAC_MASK; - } - - // 8. 拼裝返回 - return sign_res | ((uint32_t)exp_res << 23) | frac_res; -} - - -uint32_t c_Float_Mul(uint32_t a, uint32_t b) { - // 使用你定义的快捷提取宏 - uint32_t sign_a = C_FLOAT_GET_SIGN(a); - uint32_t sign_b = C_FLOAT_GET_SIGN(b); - uint32_t exp_a = C_FLOAT_GET_EXP(a); - uint32_t exp_b = C_FLOAT_GET_EXP(b); - uint32_t frac_a = C_FLOAT_GET_FRAC(a); - uint32_t frac_b = C_FLOAT_GET_FRAC(b); - - uint32_t sign_res = sign_a ^ sign_b; // 异或决定结果符号 - - // ========================================== - // 边界条件 1:处理 NaN 和 无穷大 (Inf) 的传播与熔断 - // ========================================== - if (exp_a == 255 || exp_b == 255) { - // 条件 1.1:若任一输入为真正的 NaN,直接传播 Quiet NaN - if ((exp_a == 255 && frac_a != 0) || (exp_b == 255 && frac_b != 0)) { - return 0x7FC00000U; - } - // 条件 1.2:0.0 * 无穷大 (0.0 * Inf) 属于未定义,必须强行熔断返回 NaN - bool is_a_zero = (exp_a == 0 && frac_a == 0); - bool is_b_zero = (exp_b == 0 && frac_b == 0); - if ((exp_a == 255 && is_b_zero) || (exp_b == 255 && is_a_zero)) { - return 0x7FC00000U; // 熔断返回 NaN - } - // 条件 1.3:普通的无穷大传播(Inf * 有限非零数 = Inf) - return c_Float_Pack(sign_res, 255, 0); - } - - // ========================================== - // 边界条件 2:处理纯零快速返回 - // ========================================== - if ((exp_a == 0 && frac_a == 0) || (exp_b == 0 && frac_b == 0)) { - return c_Float_Pack(sign_res, 0, 0); // 0.0 * 有限数 -> 产生带有正确符号的 ±0.0 - } - - // ========================================== - // 2. 补齐隐藏位并处理非规格化数 - // ========================================== - frac_a = (exp_a == 0) ? frac_a : (frac_a | C_FLOAT_HIDDEN_BIT); - frac_b = (exp_b == 0) ? frac_b : (frac_b | C_FLOAT_HIDDEN_BIT); - - if (exp_a == 0) exp_a = 1; - if (exp_b == 0) exp_b = 1; - - int32_t exp_res = (int32_t)exp_a + (int32_t)exp_b - C_FLOAT_EXP_BIAS; - - // ========================================== - // 3. 执行核心尾数相乘(24位 * 24位 = 48位超长整数) - // ========================================== - uint64_t prod = (uint64_t)frac_a * (uint64_t)frac_b; - - // ========================================== - // 4. 将 48 位乘积向右压缩,腾出低 3 位作为 GRS 保护位空间 - // ========================================== - // 正常规格化数相乘后,结果 `prod` 的最高位 1 应该在第 46 位或第 47 位(从0数起)。 - // 为了最终留下 24 位标准尾数和 3 位保护位,我们需要让规格化后的目标保留在 27 位。 - // 因此,我们先固定将原本 48 位的低 20 位挤出去,并把这 20 位中任意的 1 凝聚为 Sticky 位。 - uint32_t sticky = (prod & 0xFFFFF) != 0; - uint32_t frac_res = (uint32_t)(prod >> 20); // 压缩至大约 27~28 位 - frac_res |= sticky; // 将物理挤出去的所有小数信息固化在最低位 - - // ========================================== - // 5. 规格化积(Normalization) - // ========================================== - // 如果最高有效位 1 溢出到了第 27 位 (1U << 27),说明乘积结果 >= 2.0,需要右移 1 位,指数加 1 - if (frac_res & (1U << 27)) { - uint32_t lost_bit = frac_res & 1U; - frac_res >>= 1; - frac_res |= lost_bit; // 保持最低位 Sticky 不丢失 - exp_res++; - } else { - // 如果隐藏位没落到第 26 位,说明乘积较小 (< 1.0),需要左移直到最高有效位 1 回归第 26 位 - while (!(frac_res & (1U << 26)) && exp_res > 1) { - uint32_t sticky_backup = frac_res & 1U; - frac_res <<= 1; - frac_res |= sticky_backup; // 锁死 Sticky 状态 - exp_res--; - } - // 下溢退化为非规格化数 - if (!(frac_res & (1U << 26)) && exp_res == 1) { - exp_res = 0; - } - } - - // 上下溢出安全拦截 - if (exp_res >= 255) return c_Float_Pack(sign_res, 255, 0); // 上溢至 ±Inf - if (exp_res <= 0) return c_Float_Pack(sign_res, 0, 0); // 下溢至 ±0.0 - - // ========================================== - // 6. 激活 IEEE 754 标准:向最接近偶数舍入(Round-to-Nearest-Even) - // ========================================== - uint32_t round_bits = frac_res & 7U; // 捕获低 3 位的 GRS 数据 - frac_res >>= 3; // 移除保护位,回归标准 24 位尾数 - - if ((round_bits > 4) || ((round_bits == 4) && (frac_res & 1U))) { - frac_res++; - // 舍入导致的二次溢出处理 - if (frac_res & (1U << 24)) { - frac_res >>= 1; - exp_res++; - if (exp_res >= 255) return c_Float_Pack(sign_res, 255, 0); - } - } - - // 剥离规格化数中用于拼装的高位隐藏位 1 - if (exp_res != 0) { - frac_res &= C_FLOAT_FRAC_MASK; - } - - // 7. 最终位打包返回 - return c_Float_Pack(sign_res, exp_res, frac_res); -} - - -uint32_t c_Float_Div(uint32_t a, uint32_t b) { - // 使用你定义的快捷提取宏 - uint32_t sign_a = C_FLOAT_GET_SIGN(a); - uint32_t sign_b = C_FLOAT_GET_SIGN(b); - uint32_t exp_a = C_FLOAT_GET_EXP(a); - uint32_t exp_b = C_FLOAT_GET_EXP(b); - uint32_t frac_a = C_FLOAT_GET_FRAC(a); - uint32_t frac_b = C_FLOAT_GET_FRAC(b); - - uint32_t sign_res = sign_a ^ sign_b; - - // ========================================================================= - // 修复 Bug 1 & 2:严密拦截 IEEE 754 规定的所有 NaN、Inf、特殊零边界 - // ========================================================================= - - // 1. 拦截输入本身为 NaN 或 无穷大 (exp == 255) 的异常传播 - if (exp_a == 255 || exp_b == 255) { - // 条件 A: 任一为真正的 NaN(尾数非0),直接传播 Quiet NaN - if ((exp_a == 255 && frac_a != 0) || (exp_b == 255 && frac_b != 0)) { - return 0x7FC00000U; - } - // 条件 B: 无穷大除以无穷大 (Inf / Inf) 属于严重未定义,强熔断返回 NaN - if (exp_a == 255 && exp_b == 255) { - return 0x7FC00000U; - } - // 条件 C: 无穷大除以普通有限数 = 无穷大 - if (exp_a == 255) { - return c_Float_Pack(sign_res, 255, 0); - } - // 条件 D: 普通有限数除以无穷大 = 0 - return c_Float_Pack(sign_res, 0, 0); - } - - // 2. 剥离符号位,准确捕捉纯零值 (+/-0.0) 状态下的防御拦截 - bool is_a_zero = (exp_a == 0 && frac_a == 0); - bool is_b_zero = (exp_b == 0 && frac_b == 0); - - if (is_b_zero) { - // 0.0 / 0.0 必须熔断返回 NaN - if (is_a_zero) { - return 0x7FC00000U; - } - // 有限数 / 0.0 -> 产生标准的 ±Infinity - return c_Float_Pack(sign_res, 255, 0); - } - // 0.0 / 非零数 -> 产生标准的 ±0.0 - if (is_a_zero) { - return c_Float_Pack(sign_res, 0, 0); - } - - // ========================================================================= - // 修复 Bug 4:正确补齐隐藏位(非规格化数的隐藏位是 0) - // ========================================================================= - frac_a = (exp_a == 0) ? frac_a : (frac_a | C_FLOAT_HIDDEN_BIT); - frac_b = (exp_b == 0) ? frac_b : (frac_b | C_FLOAT_HIDDEN_BIT); - - if (exp_a == 0) exp_a = 1; - if (exp_b == 0) exp_b = 1; - - int32_t exp_res = (int32_t)exp_a - (int32_t)exp_b + C_FLOAT_EXP_BIAS; - - // ========================================================================= - // 修复 Bug 3:向左偏移 27 位做长除法,为 GRS 三保护位和 Sticky 腾出精度空间 - // ========================================================================= - uint64_t num = (uint64_t)frac_a << 26; // 24位标准商 + 3位保护位空间 - uint64_t den = (uint64_t)frac_b; - - uint32_t quot = (uint32_t)(num / den); - uint64_t rem = num % den; - - // 【除法 Sticky 核心点】只要整数除法除不尽有余数,无条件将商的最低位置 1,激活 Sticky 状态 - if (rem != 0) { - quot |= 1U; - } - - // 规格化商:正常情况下隐藏位应该落在第 26 位 (C_FLOAT_HIDDEN_BIT << 3) - if (quot & (1U << 27)) { - uint32_t lost = quot & 1U; - quot >>= 1; - quot |= lost; - exp_res++; - } else { - // 如果隐藏位没能落在第 26 位,说明商太小,需要左移规格化 - while (!(quot & (1U << 26)) && exp_res > 1) { - uint32_t sticky_backup = quot & 1U; - quot <<= 1; - quot |= sticky_backup; // 锁住最低位的 sticky 特征不丢失 - exp_res--; - } - if (!(quot & (1U << 26)) && exp_res == 1) { - exp_res = 0; // 退化为非规格化数 - } - } - - // 上下溢出检测 - if (exp_res >= 255) return c_Float_Pack(sign_res, 255, 0); // 上溢至 ±Inf - if (exp_res <= 0) return c_Float_Pack(sign_res, 0, 0); // 下溢至 ±0 - - // ========================================================================= - // 5. 激活 IEEE 754 标准:向最接近偶数舍入(Round-to-Nearest-Even) - // ========================================================================= - uint32_t round_bits = quot & 7U; // 提取最后 3 位的 GRS 数据 - quot >>= 3; // 移除保护位,回归标准 24 位商 - - if ((round_bits > 4) || ((round_bits == 4) && (quot & 1U))) { - quot++; - // 舍入可能导致再次溢出,进行二次规格化微调 - if (quot & (1U << 24)) { - quot >>= 1; - exp_res++; - if (exp_res >= 255) return c_Float_Pack(sign_res, 255, 0); - } - } - - // 剥离规格化数中用于拼装的高位隐藏位 1 - if (exp_res != 0) { - quot &= C_FLOAT_FRAC_MASK; - } - - return c_Float_Pack(sign_res, exp_res, quot); -} - - -int c_Float_Cmp(uint32_t a, uint32_t b) { - // 1. 处理 NaN:依据 IEEE 754,NaN 参与比较永远返回不相等(或未定义) - if (c_Float_IsNAN(a) || c_Float_IsNAN(b)) { - return 0; // 软浮点库通常在此处设置不合法比较标志位 - } - - // 2. 特殊情况:+0.0 (0x00000000) 和 -0.0 (0x80000000) 在逻辑上是相等的 - if (((a | b) & ~C_FLOAT_SIGN_MASK) == 0) { - return 0; - } - - // 提取符号位 - uint32_t sign_a = a & C_FLOAT_SIGN_MASK; - uint32_t sign_b = b & C_FLOAT_SIGN_MASK; - - // 3. 符号不同 - if (sign_a != sign_b) { - // a 是负数,b 是正数 => a < b - // a 是正数,b 是负数 => a > b - return sign_a ? -1 : 1; - } - - // 4. 符号相同:将原始二进制位转换为有符号 32 位整型进行直观比较 - int32_t ia = (int32_t)a; - int32_t ib = (int32_t)b; - - if (sign_a) { - // 如果都是负数,二进制数值越大,其代表的实际浮点数反而越小 (例如 -2.0 的二进制码大于 -1.0) - if (ia > ib) return -1; - if (ia < ib) return 1; - return 0; - } else { - // 如果都是正数,二进制数值越大,其实际浮点数就越大 - if (ia > ib) return 1; - if (ia < ib) return -1; - return 0; - } -} - -int c_Double_Cmp(uint64_t a, uint64_t b) { - // 1. 处理 NaN - if (c_Double_IsNAN(a) || c_Double_IsNAN(b)) { - return 0; - } - - // 2. 处理 +0.0 与 -0.0 相等的情况 - if (((a | b) & ~C_DOUBLE_SIGN_MASK) == 0) { - return 0; - } - - uint64_t sign_a = a & C_DOUBLE_SIGN_MASK; - uint64_t sign_b = b & C_DOUBLE_SIGN_MASK; - - // 3. 符号不同 - if (sign_a != sign_b) { - return sign_a ? -1 : 1; - } - - // 4. 符号相同:转为有符号 64 位整型比较 - int64_t ia = (int64_t)a; - int64_t ib = (int64_t)b; - - if (sign_a) { - // 均为负数 - if (ia > ib) return -1; - if (ia < ib) return 1; - return 0; - } else { - // 均为正数 - if (ia > ib) return 1; - if (ia < ib) return -1; - return 0; - } -} - -/** - * @brief 软浮点双精度打包函数 - * @param sign 符号位 (0 或 1) - * @param exp 解包/运算后的有符号指数 (已减去或未加上 Bias 均可,此处传入带 Bias 的期望值) - * @param frac64 运算后暂存在 64 位整型中的高精度尾数 (假设规格化后隐含位在第 52 位,低位留有舍入残余) - * @return 组合好的 IEEE 754 64位无符号整数 (可直接对应 double) - */ -uint64_t c_Double_Pack(uint32_t sign, int32_t exp, uint64_t frac64) { - - // 1. 动态规格化:若运算导致尾数高位溢出 (例如第 53 位为 1),需要右移尾数并增加指数 - if (frac64 & (C_DOUBLE_HIDDEN_BIT << 1)) { - frac64 >>= 1; - exp++; - } - - // 2. 下溢处理:指数太小,转换为非规格化数 - if (exp <= 0) { - // 如果指数极小,直接移出范围,变回 0 - if (exp < -52) { - frac64 = 0; - } else { - // 右移尾数以对齐非规格化数的指数位置 (exp = 0) - int32_t shift = 1 - exp; - frac64 >>= shift; - } - exp = 0; // 非规格化数的指数域强制为 0 - } - - // 3. 执行 IEEE 754 默认的“向最接近偶数舍入 (Round-to-Nearest-Even)” - // 假设经过上述操作后,标准 52 位尾数在 frac64 的低 52 位,若有更低位则是运算残留 - // 为了演示标准舍入,假设传入的 frac64 在低位保留了扩充精度(例如左移了 3 位留给 GRS) - // 此处简化演示:基于常规截断进行最邻近舍入处理 - // 在工业级库中,通常传入 frac 时会带有额外的 round_bits 变量 - - // 4. 上溢检查:指数超过最大限制 (2047),打包为无穷大 - if (exp >= 0x7FF) { - return ((uint64_t)sign << 63) | C_DOUBLE_EXP_MASK; // 返回 +/- Inf - } - - // 5. 最终清除尾数域外的隐含 1 (因为 IEEE 754 编码中不存储规格化数的最高位 1) - uint64_t final_frac = frac64 & C_DOUBLE_FRAC_MASK; - - // 6. 位移拼接 - uint64_t packed_value = ((uint64_t)sign << 63) | - ((uint64_t)exp << 52) | - final_frac; - - return packed_value; -} - - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -// 輔助函數:處理 64 位元尾數與 3 位元 GRS 捨入殘餘 -static uint64_t round_and_pack_double(uint64_t sign, int32_t exp, uint64_t frac64) { - uint32_t round_bits = frac64 & 7U; - frac64 >>= 3; // 移除 GRS 位,恢復為包含隱含位的 53 位元尾數 - - // 向最接近偶數捨入 - if ((round_bits > 4) || ((round_bits == 4) && (frac64 & 1ULL))) { - frac64++; - if (frac64 & (C_DOUBLE_HIDDEN_BIT << 1)) { - frac64 >>= 1; - exp++; - } - } - - if (exp >= 2047) return sign | C_DOUBLE_EXP_MASK; // 溢出至無限大 - if (exp <= 0) return sign; // 下溢至 0 - - return sign | ((uint64_t)exp << 52) | (frac64 & C_DOUBLE_FRAC_MASK); -} - -uint64_t c_Double_Add(uint64_t a, uint64_t b) { - c_Double_t f1 = { .raw = a }; - c_Double_t f2 = { .raw = b }; - c_Double_t result = { .raw = 0 }; - - // 1. Handle Special Cases: NaNs and Infinities - bool f1_is_nan_or_inf = (f1.parts.exponent == 0x7FF); - bool f2_is_nan_or_inf = (f2.parts.exponent == 0x7FF); - - if (f1_is_nan_or_inf || f2_is_nan_or_inf) { - // Handle NaNs - if ((f1_is_nan_or_inf && f1.parts.fraction != 0) || - (f2_is_nan_or_inf && f2.parts.fraction != 0)) { - result.parts.exponent = 0x7FF; - result.parts.fraction = 0x1; // Quiet NaN - return result.raw; - } - // Handle Inf + Inf variations - if (f1_is_nan_or_inf && f2_is_nan_or_inf) { - if (f1.parts.sign != f2.parts.sign) { - // (+Inf) + (-Inf) or (-Inf) + (+Inf) is invalid -> NaN - result.parts.exponent = 0x7FF; - result.parts.fraction = 0x1; - return result.raw; - } - return f1.raw; // Return either infinity if signs match - } - // One operand is Infinity, the other is finite - return f1_is_nan_or_inf ? f1.raw : f2.raw; - } - - // 2. Handle Zero Shortcuts - bool f1_is_zero = (f1.parts.exponent == 0 && f1.parts.fraction == 0); - bool f2_is_zero = (f2.parts.exponent == 0 && f2.parts.fraction == 0); - if (f1_is_zero && f2_is_zero) { - // If both are zero and signs differ, standard rule yields +0.0 in round-to-nearest - result.parts.sign = (f1.parts.sign == f2.parts.sign) ? f1.parts.sign : 0; - return result.raw; - } - if (f1_is_zero) return f2.raw; - if (f2_is_zero) return f1.raw; - - // 3. Extract Exponents and Mantissas (with implicit leading 1 bit) - int32_t exp1 = f1.parts.exponent; - int32_t exp2 = f2.parts.exponent; - - uint64_t m1 = (1ULL << 52) | f1.parts.fraction; - uint64_t m2 = (1ULL << 52) | f2.parts.fraction; - - // 4. Align Exponents (Shift mantissas to three extra bits of precision: Guard, Round, Sticky) - // We scale the mantissas left by 3 bits initially to capture shifting errors. - uint64_t m_large = 0, m_small = 0; - int32_t exp_res = 0; - bool sign_large = 0, sign_small = 0; - - if (exp1 >= exp2) { - m_large = m1 << 3; - sign_large = f1.parts.sign; - exp_res = exp1; - - int32_t shift = exp1 - exp2; - if (shift == 0) { - m_small = m2 << 3; - } else if (shift > 55) { - m_small = 1; // Everything shifted out becomes a sticky bit - } else { - uint64_t lost_bits = m2 & ((1ULL << shift) - 1); - m_small = (m2 << 3) >> shift; - if (lost_bits != 0) m_small |= 1; // Fold lost bits into sticky bit - } - sign_small = f2.parts.sign; - } else { - m_large = m2 << 3; - sign_large = f2.parts.sign; - exp_res = exp2; - - int32_t shift = exp2 - exp1; - if (shift > 55) { - m_small = 1; - } else { - uint64_t lost_bits = m1 & ((1ULL << shift) - 1); - m_small = (m1 << 3) >> shift; - if (lost_bits != 0) m_small |= 1; - } - sign_small = f1.parts.sign; - } - - // 5. Perform Magnitude Addition or Subtraction - uint64_t m_res = 0; - bool result_sign = sign_large; - - if (sign_large == sign_small) { - // True addition - m_res = m_large + m_small; - - // Handle carry out: if bit 56 is set (original 52 shifted left 3 plus 1 carry bit) - if (m_res & (1ULL << 56)) { - uint64_t sticky = m_res & 1; - m_res >>= 1; - m_res |= sticky; // preserve sticky bit tracking - exp_res += 1; - } - } else { - // True subtraction (Large magnitude minus Small magnitude) - // If magnitudes are completely equal, they cancel out to 0 - if (m_large == m_small) { - return 0; // standard +0.0 - } - m_res = m_large - m_small; - - // Normalize cancellation shifts (shift left until bit 55 is 1) - while ((m_res & (1ULL << 55)) == 0 && exp_res > 0) { - uint64_t sticky = m_res & 1; - m_res = (m_res << 1) | sticky; - exp_res -= 1; - } - } - - // 6. Apply IEEE 754 Round-to-Nearest, Ties-to-Even - // Currently, bit 55 is the implicit 1. Bits [2:0] are Guard, Round, Sticky. - // The target fraction belongs in bits [54:3]. - uint64_t final_fraction = (m_res >> 3) & 0xFFFFFFFFFFFFFLL; - - bool round_bit = (m_res & 4) != 0; // Bit 2 - bool sticky_bit = (m_res & 3) != 0; // Bits 1 and 0 combined - bool lsb = (final_fraction & 1) != 0; - - if (round_bit && (sticky_bit || lsb)) { - final_fraction++; - if (final_fraction > 0xFFFFFFFFFFFFFLL) { // Handle carry out from rounding - final_fraction = 0; - exp_res += 1; - } - } - - // 7. Check for Overflow / Underflow Boundaries - if (exp_res >= 0x7FF) { - result.parts.sign = result_sign; - result.parts.exponent = 0x7FF; - result.parts.fraction = 0; // Overflow to Infinity - } else if (exp_res <= 0) { - // Flush underflow to zero - result.parts.sign = result_sign; - result.parts.exponent = 0; - result.parts.fraction = 0; - } else { - result.parts.sign = result_sign; - result.parts.exponent = (uint64_t)exp_res; - result.parts.fraction = final_fraction; - } - - return result.raw; -} - - -// 內部輔助函數:32位交叉相乘,手動模擬 64x64->128位元乘法 -C_STATIC_FORCE_INLINE -void mul64_to_128(uint64_t a, uint64_t b, uint64_t *res_hi, uint64_t *res_lo) { - uint64_t a_hi = a >> 32, a_lo = a & 0xFFFFFFFFULL; - uint64_t b_hi = b >> 32, b_lo = b & 0xFFFFFFFFULL; - - uint64_t p0 = a_lo * b_lo; - uint64_t p1 = a_hi * b_lo; - uint64_t p2 = a_lo * b_hi; - uint64_t p3 = a_hi * b_hi; - - uint64_t mid = p1 + (p0 >> 32) + (p2 & 0xFFFFFFFFULL); - *res_lo = (mid << 32) | (p0 & 0xFFFFFFFFULL); - *res_hi = p3 + (mid >> 32) + (p2 >> 32); -} - -uint64_t c_Double_Mul(uint64_t a, uint64_t b) { - c_Double_t f1 = { .raw = a }; - c_Double_t f2 = { .raw = b }; - c_Double_t result = { .raw = 0 }; - - // 1. Determine the result sign (XOR of input signs) - result.parts.sign = f1.parts.sign ^ f2.parts.sign; - - // 2. Handle Zero / Special Cases (Inf, NaN) - // Shortcut if either operand is zero - bool f1_is_inf_or_nan = (f1.parts.exponent == 0x7FF); - bool f2_is_inf_or_nan = (f2.parts.exponent == 0x7FF); - bool f1_is_zero = (f1.parts.exponent == 0 && f1.parts.fraction == 0); - bool f2_is_zero = (f2.parts.exponent == 0 && f2.parts.fraction == 0); - - - - // Shortcut for Infinities or NaNs - if (f1_is_inf_or_nan || f2_is_inf_or_nan) { - // If either is an actual NaN, OR we are multiplying 0 * Inf, it MUST be NaN - if ((f1_is_inf_or_nan && f1.parts.fraction != 0) || - (f2_is_inf_or_nan && f2.parts.fraction != 0) || - (f1_is_zero && f2_is_inf_or_nan) || - (f2_is_zero && f1_is_inf_or_nan)) { - - result.parts.exponent = 0x7FF; - result.parts.fraction = 0x1; // Quiet NaN - return result.raw; - } - // Otherwise, it's a valid Infinity multiplication (e.g., 5.0 * Inf = Inf) - result.parts.exponent = 0x7FF; - result.parts.fraction = 0; - return result.raw; - } - - // Now it is safe to evaluate the normal zero shortcut - if (f1_is_zero || f2_is_zero) { - result.parts.exponent = 0; - result.parts.fraction = 0; - return result.raw; // Returns correctly signed zero - } - - // 3. Extract Mantissas and append the implicit leading 1 bit (Bit 52) - // Note: This implementation assumes normalized numbers. - uint64_t m1 = (1ULL << 52) | f1.parts.fraction; - uint64_t m2 = (1ULL << 52) | f2.parts.fraction; - - // 4. Calculate raw exponent sum (subtract the double bias of 1023) - int32_t exp_res = (int32_t)f1.parts.exponent + (int32_t)f2.parts.exponent - 1023; - - // 5. Multiply the mantissas using 128-bit precision to prevent overflow - // Multiplying two 53-bit integers results in a 105-bit or 106-bit product - unsigned __int128 prod = (unsigned __int128)m1 * m2; - - // 6. Normalize the product - // The product has its radix point at bit 104 (52 fractional bits * 2) - // We want the resulting leading bit to sit at bit 52. - if (prod & ((unsigned __int128)1 << 105)) { - // Product is >= 2.0 (bit 105 is set). Shift down by 53 and increment exponent. - exp_res += 1; - // Simple round-to-nearest-even approximation via bit shift - result.parts.fraction = (uint64_t)((prod >> 53) & 0xFFFFFFFFFFFFFLL); - } else { - // Product is < 2.0 (bit 104 is set). Shift down by 52. - result.parts.fraction = (uint64_t)((prod >> 52) & 0xFFFFFFFFFFFFFLL); - } - - // 7. Check for Overflow / Underflow boundaries - if (exp_res >= 0x7FF) { - // Overflow to Infinity - result.parts.exponent = 0x7FF; - result.parts.fraction = 0; - } else if (exp_res <= 0) { - // Underflow to Zero (Flushing subnormals to zero for simplicity) - result.parts.exponent = 0; - result.parts.fraction = 0; - } else { - // Valid normalized exponent range - result.parts.exponent = (uint64_t)exp_res; - } - - return result.raw; -} - - -uint64_t c_Double_Div(uint64_t a, uint64_t b) { - c_Double_t f1 = { .raw = a }; - c_Double_t f2 = { .raw = b }; - c_Double_t result = { .raw = 0 }; - - // 1. Determine the result sign (XOR of input signs) - result.parts.sign = f1.parts.sign ^ f2.parts.sign; - - // 2. Handle Special Cases: Zero, Infinity, and NaN - bool f1_is_nan_or_inf = (f1.parts.exponent == 0x7FF); - bool f2_is_nan_or_inf = (f2.parts.exponent == 0x7FF); - bool f1_is_zero = (f1.parts.exponent == 0 && f1.parts.fraction == 0); - bool f2_is_zero = (f2.parts.exponent == 0 && f2.parts.fraction == 0); - - // Case 2a: Either input is NaN, or invalid combinations (0/0, Inf/Inf) - if ((f1_is_nan_or_inf && f1.parts.fraction != 0) || - (f2_is_nan_or_inf && f2.parts.fraction != 0) || - (f1_is_zero && f2_is_zero) || - (f1_is_nan_or_inf && f2_is_nan_or_inf)) { - result.parts.exponent = 0x7FF; - result.parts.fraction = 0x1; // Quiet NaN - return result.raw; - } - - // Case 2b: Division by Zero (X / 0 = Inf) - if (f2_is_zero) { - result.parts.exponent = 0x7FF; // Infinity - result.parts.fraction = 0; - return result.raw; - } - - // Case 2c: Numerator is Zero or Denominator is Infinity (0 / X = 0, X / Inf = 0) - if (f1_is_zero || f2_is_nan_or_inf) { - result.parts.exponent = 0; - result.parts.fraction = 0; - return result.raw; - } - - // Case 2d: Numerator is Infinity (Inf / X = Inf) - if (f1_is_nan_or_inf) { - result.parts.exponent = 0x7FF; - result.parts.fraction = 0; - return result.raw; - } - - // 3. Extract Mantissas and append the implicit leading 1 bit (Bit 52) - // Assumes normalized inputs - uint64_t m1 = (1ULL << 52) | f1.parts.fraction; - uint64_t m2 = (1ULL << 52) | f2.parts.fraction; - - // 4. Calculate raw biased exponent (Subtract exponents and restore bias) - int32_t exp_res = (int32_t)f1.parts.exponent - (int32_t)f2.parts.exponent + 1023; - - // 5. Divide the mantissas - // Since m1 and m2 are roughly equal, m1 / m2 would yield 0 or 1. - // We upscale m1 to 128 bits and shift it left by 52 positions first. - // This allows integer division to compute the correct 53-bit fraction. - unsigned __int128 dividend = (unsigned __int128)m1 << 53; - unsigned __int128 quot = dividend / m2; - unsigned __int128 remainder = dividend % m2; - - // 6. Normalize the quotient - // In binary division, if m1 < m2, the quotient's implicit 1 drops to bit 51. - // If m1 >= m2, the quotient's implicit 1 naturally sits at bit 52. - uint64_t final_fraction = 0; - - // Check if the implicit bit sits at bit 53 (corresponds to m1 >= m2) - if (quot & ((unsigned __int128)1 << 53)) { - // Extract the 52-bit fraction - final_fraction = (uint64_t)((quot >> 1) & 0xFFFFFFFFFFFFFLL); - - // Rounding bits - bool round_bit = (quot & 1) != 0; - bool sticky_bit = (remainder != 0); - bool lsb = (final_fraction & 1) != 0; - - // IEEE 754 standard Round-to-Nearest, Ties-to-Even rule - if (round_bit && (sticky_bit || lsb)) { - final_fraction++; - if (final_fraction > 0xFFFFFFFFFFFFFLL) { // Handle carry-out - final_fraction = 0; - exp_res += 1; - } - } - } else { - // Implicit bit sits at bit 52 (corresponds to m1 < m2) - // No right shift needed for the fraction, but we need the sticky bit updated - final_fraction = (uint64_t)(quot & 0xFFFFFFFFFFFFFLL); - - // We shifted left by 53 instead of 52, so bit 0 of quot is the actual round bit - // However, since we didn't shift right, we must look at the remainder for the true sticky status - // For the m1 < m2 case, we effectively need to look at what would happen if we didn't shift as far. - // Let's re-align it perfectly: - - // To make it straightforward, let's normalize the 54-bit temporary quotient first: - // If bit 53 is not set, we shift the entire quotient up by 1 bit to force the implicit bit to 53, - // but we must adjust the remainder logic. Let's use a cleaner normalization pattern: - - // Shift left by 1 to align the implicit bit to bit 53 - quot <<= 1; - exp_res -= 1; - - final_fraction = (uint64_t)((quot >> 1) & 0xFFFFFFFFFFFFFLL); - bool round_bit = (quot & 1) != 0; - bool sticky_bit = (remainder != 0); - bool lsb = (final_fraction & 1) != 0; - - if (round_bit && (sticky_bit || lsb)) { - final_fraction++; - if (final_fraction > 0xFFFFFFFFFFFFFLL) { - final_fraction = 0; - exp_res += 1; - } - } - } - - result.parts.fraction = final_fraction; - - // 7. Check for Overflow / Underflow boundaries - if (exp_res >= 0x7FF) { - // Overflow to Infinity - result.parts.exponent = 0x7FF; - result.parts.fraction = 0; - } else if (exp_res <= 0) { - // Underflow to Zero (Flushing subnormal results to zero) - result.parts.exponent = 0; - result.parts.fraction = 0; - } else { - // Valid normalized exponent - result.parts.exponent = (uint64_t)exp_res; - } - - return result.raw; -} - - - diff --git a/Foundation/c_Float.h b/Foundation/c_Float.h deleted file mode 100644 index 93b6ff0..0000000 --- a/Foundation/c_Float.h +++ /dev/null @@ -1,211 +0,0 @@ -#ifndef INCLUDED_C_FLOAT_H -#define INCLUDED_C_FLOAT_H - -#ifndef INCLUDED_C_TYPES_H -#include -#endif /*INCLUDED_C_TYPES_H*/ - -#ifndef INCLUDED_MATH_H -#define INCLUDED_MATH_H -#include -#endif /*INCLUDED_MATH_H*/ - -#ifndef INCLUDED_FLOAT_H -#define INCLUDED_FLOAT_H -#include -#endif /*INCLUDED_FLOAT_H*/ - - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -typedef union { - float f; - uint32_t raw; - struct { - uint32_t fraction : 23; // 尾数 (M) - uint32_t exponent : 8; // 指数 (E) - uint32_t sign : 1; // 符号位 (S) - } parts; -} c_Float_t; - -typedef union { - double d; - uint64_t raw; - struct { - uint64_t fraction : 52; // 尾数 - uint64_t exponent : 11; // 指数 - uint64_t sign : 1; // 符号 - } parts; -} c_Double_t; - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -// 32位单精度常量定义 -#define C_FLOAT_SIGN_MASK 0x80000000U -#define C_FLOAT_EXP_MASK 0x7F800000U -#define C_FLOAT_FRAC_MASK 0x007FFFFFU -#define C_FLOAT_HIDDEN_BIT 0x00800000U // 隐藏的最高位1 -#define C_FLOAT_EXP_BIAS 127 - -#define C_FLOAT_NEG_INF 0xFF800000U -#define C_FLOAT_POS_INF 0x7F800000U - -// 快捷提取宏 -#define C_FLOAT_GET_SIGN(u) (((u) & C_FLOAT_SIGN_MASK) >> 31) -#define C_FLOAT_GET_EXP(u) (((u) & C_FLOAT_EXP_MASK) >> 23) -#define C_FLOAT_GET_FRAC(u) ((u) & C_FLOAT_FRAC_MASK) - -#define C_DOUBLE_SIGN_MASK 0x8000000000000000ULL -#define C_DOUBLE_EXP_MASK 0x7FF0000000000000ULL -#define C_DOUBLE_FRAC_MASK 0x000FFFFFFFFFFFFFULL -#define C_DOUBLE_HIDDEN_BIT 0x0010000000000000ULL // 第52位(从0开始算) - -#define C_DOUBLE_POS_INF 0x7FF0000000000000ULL -#define C_DOUBLE_NEG_INF 0xFFF0000000000000ULL - -#define C_DOUBLE_GET_SIGN(u) (((u) & C_DOUBLE_SIGN_MASK) >> 63) -#define C_DOUBLE_GET_EXP(u) (((u) & C_DOUBLE_EXP_MASK) >> 52) -#define C_DOUBLE_GET_FRAC(u) ((u) & C_DOUBLE_FRAC_MASK) - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -C_STATIC_FORCE_INLINE -uint32_t c_Float_Pack(const uint32_t sign, const uint32_t exp, const uint32_t frac) { - return ((sign << 31) & C_FLOAT_SIGN_MASK) | - ((exp << 23) & C_FLOAT_EXP_MASK) | - (frac & C_FLOAT_FRAC_MASK); -} - -C_STATIC_FORCE_INLINE -int c_Float_IsNAN(uint32_t raw) { - return ((raw & C_FLOAT_EXP_MASK) == C_FLOAT_EXP_MASK) && ((raw & C_FLOAT_FRAC_MASK) != 0); -} - -C_STATIC_FORCE_INLINE -int c_Double_IsNAN(uint64_t raw) { - return ((raw & C_DOUBLE_EXP_MASK) == C_DOUBLE_EXP_MASK) && ((raw & C_DOUBLE_FRAC_MASK) != 0); -} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -uint32_t c_Float_Add(uint32_t a, uint32_t b); - -uint32_t c_Float_Mul(uint32_t a, uint32_t b); - -uint32_t c_Float_Div(uint32_t a, uint32_t b); - -int c_Float_Cmp(uint32_t a, uint32_t b); - -C_STATIC_FORCE_INLINE -uint32_t c_Float_Sub(uint32_t a, uint32_t b) { - // 透過與 0x80000000 進行 XOR,直接將 b 的符號位元取反 (0->1, 1->0) - // 隨後將 A - B 轉換為 A + (-B) 傳入加法器 - return c_Float_Add(a, b ^ C_FLOAT_SIGN_MASK); -} - -C_STATIC_FORCE_INLINE -bool c_Float_IsZero(uint32_t raw) { - // Strip away the sign bit; check if the remaining 31 bits are 0 - return (raw & ~C_FLOAT_SIGN_MASK) == 0U; -} - -C_STATIC_FORCE_INLINE -bool c_Float_IsInf(uint32_t raw) { - // Strip the sign bit and check if it exactly matches the exponent mask. - // If any fraction bits were set, it would be a NaN instead of Infinity. - return (raw & ~0x80000000U) == C_FLOAT_EXP_MASK; -} - -/** - * @brief Determines if the float is specifically Negative Infinity (-Inf). - */ -C_STATIC_FORCE_INLINE -bool c_Float_IsNegInf(uint32_t raw) { - return raw == C_FLOAT_NEG_INF; -} - -/** - * @brief Determines if the float is specifically Positive Infinity (+Inf). - */ -C_STATIC_FORCE_INLINE -bool c_Float_IsPosInf(uint32_t raw) { - return raw == C_FLOAT_POS_INF; -} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -uint64_t c_Double_Pack(uint32_t sign, int32_t exp, uint64_t frac64); - -int c_Double_Cmp(uint64_t a, uint64_t b); - -uint64_t c_Double_Add(uint64_t a, uint64_t b); - -C_STATIC_FORCE_INLINE -uint64_t c_Double_Sub(uint64_t a, uint64_t b) { - // A - B == A + (-B) - return c_Double_Add(a, b ^ C_DOUBLE_SIGN_MASK); -} - -uint64_t c_Double_Mul(uint64_t a, uint64_t b); - -uint64_t c_Double_Div(uint64_t a, uint64_t b); - - -C_STATIC_FORCE_INLINE -bool c_Double_IsZero(const uint64_t raw) { - // Strip away the sign bit; check if the remaining 63 bits are 0 - return (raw & ~C_DOUBLE_SIGN_MASK) == 0ULL; -} - -C_STATIC_FORCE_INLINE -bool c_Double_IsInf(uint64_t raw) { - // Strip the sign bit and check if it exactly matches the exponent mask. - // If any fraction bits were set, it would be a NaN instead of Infinity. - return (raw & ~C_DOUBLE_SIGN_MASK) == C_DOUBLE_EXP_MASK; -} - -/** - * @brief Determines if the double is specifically Negative Infinity (-Inf). - */ -C_STATIC_FORCE_INLINE -bool c_Double_IsNegInf(uint64_t raw) { - return raw == C_DOUBLE_NEG_INF; -} - -/** - * @brief Determines if the double is specifically Positive Infinity (+Inf). - */ -C_STATIC_FORCE_INLINE -bool c_Double_IsPosInf(uint64_t raw) { - return raw == C_DOUBLE_POS_INF; -} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -C_STATIC_FORCE_INLINE -int c_float_cmp(const float a, const float b) { - c_Float_t va; - c_Float_t vb; - va.f = a; - vb.f = b; - return c_Float_Cmp(va.raw, vb.raw); -} - -C_STATIC_FORCE_INLINE -int c_double_cmp(const double a, const double b) { - c_Double_t va; - c_Double_t vb; - va.d = a; - vb.d = b; - return c_Double_Cmp(va.raw, vb.raw); -} - - - -#endif /*INCLUDED_C_FLOAT_H*/ diff --git a/Foundation/c_Float.t.c b/Foundation/c_Float.t.c deleted file mode 100644 index d77c90d..0000000 --- a/Foundation/c_Float.t.c +++ /dev/null @@ -1,381 +0,0 @@ -#include "c_float.h" -#include -#include -#include - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -/** - * @brief 辅助工具:将 C 语言原生双精度 double 转换为 64 位原始位码 (uint64_t) - */ -static uint64_t to_raw64(double d) { - c_Double_t u; - u.d = d; - return u.raw; -} - -/** - * @brief 辅助工具:将 64 位原始位码 (uint64_t) 还原为 C 语言原生双精度 double - */ -static double to_double(uint64_t raw) { - c_Double_t u; - u.raw = raw; - return u.d; -} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -// 用例 1:测试 Float 分类状态识别函数(IsZero, IsInf, IsNAN 等基本位打包判定) -void test_float_classification_and_pack() { - c_Float_t val; - - // 1. 测试 Pack 是否能准确组装成标准浮点位 - // 符号=0, 指数=127(偏移后为0), 尾数=0 -> 应该代表 1.0f - uint32_t packed = c_Float_Pack(0, 127, 0); - val.raw = packed; - ASSERT_MSG(val.f == 1.0f, "c_Float_Pack failed to assemble 1.0f"); - - // 2. 测试 正负零 (0.0f 和 -0.0f) - val.f = 0.0f; - ASSERT_MSG(c_Float_IsZero(val.raw) == true, "0.0f should be identified as zero"); - val.f = -0.0f; - ASSERT_MSG(c_Float_IsZero(val.raw) == true, "-0.0f should be identified as zero"); - - // 3. 测试 正负无穷大 (Inf) - val.raw = C_FLOAT_POS_INF; - ASSERT_MSG(c_Float_IsInf(val.raw) == true, "POS_INF must be Inf"); - ASSERT_MSG(c_Float_IsPosInf(val.raw) == true, "POS_INF must be PosInf"); - - val.raw = C_FLOAT_NEG_INF; - ASSERT_MSG(c_Float_IsInf(val.raw) == true, "NEG_INF must be Inf"); - ASSERT_MSG(c_Float_IsNegInf(val.raw) == true, "NEG_INF must be NegInf"); - - // 4. 测试 NaN(指数全为1,尾数不为0) - val.raw = C_FLOAT_EXP_MASK | 0x00000001U; // 制造一个 NaN - ASSERT_MSG(c_Float_IsNAN(val.raw) == 1, "Should be recognized as NaN"); - - val.raw = C_FLOAT_POS_INF; // 无穷大的尾数是0,不属于 NaN - ASSERT_MSG(c_Float_IsNAN(val.raw) == 0, "Infinity is NOT NaN"); -} - - -// 用例 2:测试 Float 基础数学四则运算(数值运算准确性) -void test_float_math_operations() { - c_Float_t res, out_add, out_sub, out_mul, out_div; - c_Float_t a, b; - - a.f = 5.5f; - b.f = 2.25f; - - // 1. 加法测试 5.5 + 2.25 = 7.75 - out_add.raw = c_Float_Add(a.raw, b.raw); - res.f = 7.75f; - ASSERT_INT_EQ_MSG(res.raw, out_add.raw, "Soft-Float Add failed (5.5 + 2.25)"); - - // 2. 减法测试 5.5 - 2.25 = 3.25 - out_sub.raw = c_Float_Sub(a.raw, b.raw); - res.f = 3.25f; - ASSERT_INT_EQ_MSG(res.raw, out_sub.raw, "Soft-Float Sub failed (5.5 - 2.25)"); - - // 3. 乘法测试 5.5 * 2.25 = 12.375 - out_mul.raw = c_Float_Mul(a.raw, b.raw); - res.f = 12.375f; - ASSERT_INT_EQ_MSG(res.raw, out_mul.raw, "Soft-Float Mul failed (5.5 * 2.25)"); - - // 4. 除法测试 5.5 / 2.25 = 2.444444... (通过联合体转换进行交叉对比) - out_div.raw = c_Float_Div(a.raw, b.raw); - float expected_div = 5.5f / 2.25f; - uint32_t expected_raw = ((c_Float_t){.f = expected_div}).raw; - - // 经过软除法精度升级后,这里预期可以做到每一个二进制位都完全绝对对齐(0 ULP 误差) - ASSERT_INT_EQ_MSG((int)expected_raw, (int)out_div.raw, "Soft-Float Div Round-to-Nearest-Even failed to align with hardware bits"); -} - -void test_float_div_complete() { - c_Float_t a, b, out; - - // ------------------------------------------------------------- - // 测试 1:常规数值除法 (15.5 / 2.0 = 7.75) - // ------------------------------------------------------------- - a.f = 15.5f; - b.f = 2.0f; - out.raw = c_Float_Div(a.raw, b.raw); - ASSERT_MSG(fabsf(7.75f - out.f) b 返回正数 - a.d = 100.5; - b.d = 200.5; - ASSERT_MSG(c_Double_Cmp(a.raw, b.raw) < 0, "100.5 should be less than 200.5"); - ASSERT_MSG(c_Double_Cmp(b.raw, a.raw) > 0, "200.5 should be greater than 100.5"); - ASSERT_MSG(c_Double_Cmp(a.raw, a.raw) == 0, "100.5 should be equal to itself"); - - // 3. 原生内联函数的包装测试 (c_double_cmp) - ASSERT_MSG(c_double_cmp(10.0, 20.0) < 0, "Inline double compare wrapper failed"); -} - -void test_float_isnan_pure_bits() { - // 场景 1:制造标准常规数值(如 1.0f)—— 预期:非 NaN (0) - // 符号=0, 指数=127, 尾数=0 - uint32_t normal_num = c_Float_Pack(0, 127, 0); - ASSERT_INT_EQ_MSG(0, c_Float_IsNAN(normal_num), "Normal number 1.0f must NOT be NaN"); - - // 场景 2:正无穷大 (C_FLOAT_POS_INF) —— 预期:非 NaN (0) - // 它的指数全为 1,但尾数严格为 0 - ASSERT_INT_EQ_MSG(0, c_Float_IsNAN(C_FLOAT_POS_INF), "Positive Infinity must NOT be NaN"); - ASSERT_INT_EQ_MSG(0, c_Float_IsNAN(C_FLOAT_NEG_INF), "Negative Infinity must NOT be NaN"); - - // 场景 3:制造一个最微小的 Quiet NaN (QNaN) —— 预期:是 NaN (1) - // 指数全为 1 (0xFF),尾数最高位为 1 (0x400000) - uint32_t qnan_bits = c_Float_Pack(0, 0xFF, 0x400000U); - ASSERT_MSG(c_Float_IsNAN(qnan_bits), "Quiet NaN bits must be recognized as NaN"); - - // 场景 4:制造一个最微小的 Signaling NaN (SNaN) —— 预期:是 NaN (1) - // 指数全为 1 (0xFF),尾数最低位为 1 (0x000001) - uint32_t snan_bits = c_Float_Pack(0, 0xFF, 0x000001U); - ASSERT_MSG(c_Float_IsNAN(snan_bits), "Signaling NaN bits must be recognized as NaN"); - - // 场景 5:测试带有符号位的 NaN (负 NaN) —— 预期:是 NaN (1) - // IEEE 754 规范中,NaN 的符号位不影响它是 NaN 的事实 - uint32_t neg_nan_bits = c_Float_Pack(1, 0xFF, 0x7FFFFFU); - ASSERT_MSG(c_Float_IsNAN(neg_nan_bits), "Negative NaN bits must also be recognized as NaN"); -} - -void test_float_inf_plus_neginf() { - // 1. 获取正无穷大与负无穷大的位表示 - uint32_t pos_inf = C_FLOAT_POS_INF; // 0x7F800000 - uint32_t neg_inf = C_FLOAT_NEG_INF; // 0xFF800000 - - // 2. 执行待测的软浮点加法:(+Inf) + (-Inf) - uint32_t result_raw = c_Float_Add(pos_inf, neg_inf); - - // 3. 核心断言:结果必须是 NaN - // 使用 c_Float_IsNAN 验证其特征是否为:指数全 1,尾数非 0 - ASSERT_MSG(c_Float_IsNAN(result_raw), "IEEE 754 standard: (+Inf) + (-Inf) must produce NaN"); - - // 4. 反向验证:它绝对不能再被误判为任何形式的无穷大或零 - ASSERT_MSG(!c_Float_IsInf(result_raw), "Result NaN must not be classified as Infinity"); - ASSERT_MSG(!c_Float_IsZero(result_raw), "Result NaN must not be classified as Zero"); - - // 5. 跨双精度对称验证:(+Inf) + (-Inf) 同样适用于 64 位双精度 - uint64_t d_pos_inf = C_DOUBLE_POS_INF; - uint64_t d_neg_inf = C_DOUBLE_NEG_INF; - uint64_t d_result_raw = c_Double_Add(d_pos_inf, d_neg_inf); - - ASSERT_MSG(c_Double_IsNAN(d_result_raw), "IEEE 754 standard: Double (+Inf) + (-Inf) must produce NaN"); -} - -void test_double_mul_and_div_complete() { - c_Double_t da, db, dout; - - // ----------------------------------------------------------------- - // 测试 1:验证跨 64 位大整数相乘的精确偶数舍入 - // ----------------------------------------------------------------- - da.d = 1.23456789012345; - db.d = -9.87654321098765; - dout.raw = c_Double_Mul(da.raw, db.raw); - - double expected_mul = 1.23456789012345 * -9.87654321098765; - c_Double_t native_mul = {.d = expected_mul}; - - // 【终极断言升级】:杜绝 int 转换截断,对双精度 64 位全局原始编码进行无差错硬核对齐 - ASSERT_MSG(native_mul.raw == dout.raw, - "c_Double_Mul 64-bit full-width precision failed to align with hardware FPU"); - - - // ----------------------------------------------------------------- - // 测试 2:验证双精度无限循环小数除法的长窗口状态机精度 - // ----------------------------------------------------------------- - da.d = 1.0; - db.d = 3.0; // 1.0 / 3.0 - dout.raw = c_Double_Div(da.raw, db.raw); - - double expected_div = 1.0 / 3.0; - c_Double_t native_div = {.d = expected_div}; - ASSERT_INT_EQ_MSG((int)native_div.parts.fraction, (int)dout.parts.fraction, "c_Double_Div bit-level precision error at 1.0/3.0"); - - // ----------------------------------------------------------------- - // 测试 3:验证双精度 0.0 与 无穷大的复合熔断边界 - // ----------------------------------------------------------------- - // 边界 A:0.0 * Inf -> 必须返回 NaN - uint64_t zero_mul_inf = c_Double_Mul(to_raw64(0.0), C_DOUBLE_POS_INF); - ASSERT_MSG(c_Double_IsNAN(zero_mul_inf), "Double 0.0 * +Inf must result in NaN"); - - // 边界 B:0.0 / 0.0 -> 必须返回 NaN - uint64_t zero_div_zero = c_Double_Div(to_raw64(0.0), to_raw64(-0.0)); - ASSERT_MSG(c_Double_IsNAN(zero_div_zero), "Double 0.0 / -0.0 must result in NaN"); - - // 边界 C:常规有限双精度数除以 0.0 -> 产生无穷大 - da.d = -55.5; - uint64_t div_zero = c_Double_Div(to_raw64(da.d), to_raw64(0.0)); - ASSERT_MSG(c_Double_IsNegInf(div_zero), "Negative double divided by 0.0 must result in -Inf"); -} - -void test_double_add_complete() { - c_Double_t da, db, dout; - - // ----------------------------------------------------------------- - // 测试 1:常规双精度数值加减(50.25 + 25.5 = 75.75) - // ----------------------------------------------------------------- - da.d = 50.25; - db.d = 25.5; - dout.raw = c_Double_Add(da.raw, db.raw); - - // 使用真值进行精度验证 - ASSERT_MSG(fabs(dout.d - 75.75) < 1e-9, "Regular Double Add numerical verification failed"); - - // ----------------------------------------------------------------- - // 测试 2:验证正负无穷大冲抵边界熔断(+Inf + -Inf = NaN) - // ----------------------------------------------------------------- - uint64_t res_nan = c_Double_Add(C_DOUBLE_POS_INF, C_DOUBLE_NEG_INF); - ASSERT_MSG(c_Double_IsNAN(res_nan), "IEEE 754: Double (+Inf) + (-Inf) must produce NaN"); - - // ----------------------------------------------------------------- - // 测试 3:验证异号数值完全抵消(5.5 + -5.5 = +0.0) - // ----------------------------------------------------------------- - da.d = 5.5; - db.d = -5.5; - dout.raw = c_Double_Add(da.raw, db.raw); - // 验证返回的是否是干净的、符号位为0的正零 (0x0000000000000000) - ASSERT_INT_EQ_MSG(0, (int)dout.raw, "Opposite numbers sum must strictly result in +0.0 bits"); - - // ----------------------------------------------------------------- - // 测试 4:大跨度对阶精度测试(1.0 + 1e-17 触发全移出边界) - // ----------------------------------------------------------------- - da.d = 1.0; - db.d = 1e-17; // 这个值太小了,在双精度 53 位尾数对阶时会被完全移出去,但会触发 sticky 位置 1 - dout.raw = c_Double_Add(da.raw, db.raw); - // 按照偶数舍入规则,sticky=1,GRS=001 <= 4,将被舍去,结果应该严格保持为 1.0 - ASSERT_MSG(dout.d == 1.0, "Large exponent gap shift processing failed"); - - // ----------------------------------------------------------------- - // 测试 5:向最近偶数舍入的 0 ULP 硬件级绝对对齐校验 - // ----------------------------------------------------------------- - da.d = 1.23456789012345; - db.d = 9.87654321098765; - dout.raw = c_Double_Add(da.raw, db.raw); - - double native_expected = 1.23456789012345 + 9.87654321098765; - c_Double_t native_val = {.d = native_expected}; - - // 通过对比尾数域,验证是否做到了 100% 硬件位对齐 - ASSERT_INT_EQ_MSG((int)native_val.parts.fraction, (int)dout.parts.fraction, - "Soft-Double Add failed to align with hardware FPU bits"); -} - -int main(int argc, char** argv){ - TEST_START(Starting Unit Tests); - - // 运行需要内存环境的用例 - RUN_TEST(test_float_classification_and_pack); - RUN_TEST(test_float_math_operations); - RUN_TEST(test_float_edge_cases); - RUN_TEST(test_double_operations_and_compare); - RUN_TEST(test_float_isnan_pure_bits); - RUN_TEST(test_float_inf_plus_neginf); - RUN_TEST(test_float_div_complete); - RUN_TEST(test_double_mul_and_div_complete); - RUN_TEST(test_double_add_complete); - - - // 打印最终统计报告 - TEST_REPORT(); - - RETURN_TEST_STATUS; -} diff --git a/Foundation/c_Fmt.c b/Foundation/c_Fmt.c deleted file mode 100644 index 7dbcbce..0000000 --- a/Foundation/c_Fmt.c +++ /dev/null @@ -1,393 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define T c_Fmt_t - -struct buf { - char *buf; - char *bp; - int size; -}; - -#define pad(n,c) do { int nn = (n); \ - while (nn-- > 0) \ - put((c), cl); } while (0) - -static void cvt_s(int code, va_list_box *box, - int put(int c, void *cl), void *cl, - unsigned char flags[], int width, int precision) { - char *str = va_arg(box->ap, char *); - assert(str); - c_Fmt_puts(str, (int)strlen(str), put, cl, flags, - width, precision); -} - -static void cvt_d(int code, va_list_box *box, - int put(int c, void *cl), void *cl, - unsigned char flags[], int width, int precision) { - int val = va_arg(box->ap, int); - unsigned m; - char buf[43]; - char *p = buf + sizeof buf; - if (val == INT_MIN) - m = INT_MAX + 1U; - else if (val < 0) - m = -val; - else - m = val; - do - *--p = m%10 + '0'; - while ((m /= 10) > 0); - if (val < 0) - *--p = '-'; - c_Fmt_putd(p, (buf + sizeof buf) - p, put, cl, flags, - width, precision); -} - -static void cvt_u(int code, va_list_box *box, - int put(int c, void *cl), void *cl, - unsigned char flags[], int width, int precision) { - unsigned m = va_arg(box->ap, unsigned); - char buf[43]; - char *p = buf + sizeof buf; - do - *--p = m%10 + '0'; - while ((m /= 10) > 0); - c_Fmt_putd(p, (buf + sizeof buf) - p, put, cl, flags, - width, precision); -} - -static void cvt_o(int code, va_list_box *box, - int put(int c, void *cl), void *cl, - unsigned char flags[], int width, int precision) { - unsigned m = va_arg(box->ap, unsigned); - char buf[43]; - char *p = buf + sizeof buf; - do - *--p = (m&0x7) + '0'; - while ((m>>= 3) != 0); - c_Fmt_putd(p, (buf + sizeof buf) - p, put, cl, flags, - width, precision); -} - -static void cvt_x(int code, va_list_box *box, - int put(int c, void *cl), void *cl, - unsigned char flags[], int width, int precision) { - unsigned m = va_arg(box->ap, unsigned); - char buf[43]; - char *p = buf + sizeof buf; - do - *--p = "0123456789abcdef"[m&0xf]; - while ((m>>= 4) != 0); - c_Fmt_putd(p, (buf + sizeof buf) - p, put, cl, flags, - width, precision); -} - -static void cvt_p(int code, va_list_box *box, - int put(int c, void *cl), void *cl, - unsigned char flags[], int width, int precision) { - c_uintptr_t m = (c_uintptr_t)va_arg(box->ap, void*); - char buf[43]; - char *p = buf + sizeof buf; - precision = INT_MIN; - do { - *--p = "0123456789abcdef"[m&0xf]; - }while ((m>>= 4) != 0); - c_Fmt_putd(p, (buf + sizeof buf) - p, put, cl, flags, - width, precision); -} - -static void cvt_c(int code, va_list_box *box, - int put(int c, void *cl), void *cl, - unsigned char flags[], int width, int precision) { - if (width == INT_MIN) - width = 0; - if (width < 0) { - flags['-'] = 1; - width = -width; - } - if (!flags['-']) - pad(width - 1, ' '); - put((unsigned char)va_arg(box->ap, int), cl); - if ( flags['-']) - pad(width - 1, ' '); -} - -static void cvt_f(int code, va_list_box *box, - int put(int c, void *cl), void *cl, - unsigned char flags[], int width, int precision) { - char buf[DBL_MAX_10_EXP+1+1+99+1]; - if (precision < 0) - precision = 6; - if (code == 'g' && precision == 0) - precision = 1; - { - static char fmt[] = "%.dd?"; - assert(precision <= 99); - fmt[4] = code; - fmt[3] = precision%10 + '0'; - fmt[2] = (precision/10)%10 + '0'; - sprintf(buf, fmt, va_arg(box->ap, double)); - } - c_Fmt_putd(buf, strlen(buf), put, cl, flags, - width, precision); -} - -static T cvt[256] = { - /* 0- 7 */ 0, 0, 0, 0, 0, 0, 0, 0, - /* 8- 15 */ 0, 0, 0, 0, 0, 0, 0, 0, - /* 16- 23 */ 0, 0, 0, 0, 0, 0, 0, 0, - /* 24- 31 */ 0, 0, 0, 0, 0, 0, 0, 0, - /* 32- 39 */ 0, 0, 0, 0, 0, 0, 0, 0, - /* 40- 47 */ 0, 0, 0, 0, 0, 0, 0, 0, - /* 48- 55 */ 0, 0, 0, 0, 0, 0, 0, 0, - /* 56- 63 */ 0, 0, 0, 0, 0, 0, 0, 0, - /* 64- 71 */ 0, 0, 0, 0, 0, 0, 0, 0, - /* 72- 79 */ 0, 0, 0, 0, 0, 0, 0, 0, - /* 80- 87 */ 0, 0, 0, 0, 0, 0, 0, 0, - /* 88- 95 */ 0, 0, 0, 0, 0, 0, 0, 0, - /* 96-103 */ 0, 0, 0, cvt_c, cvt_d, cvt_f, cvt_f, cvt_f, - /* 104-111 */ 0, 0, 0, 0, 0, 0, 0, cvt_o, - /* 112-119 */ cvt_p, 0, 0, cvt_s, 0, cvt_u, 0, 0, - /* 120-127 */ cvt_x, 0, 0, 0, 0, 0, 0, 0 -}; - -static char *c_Fmt_flags = "-+ 0"; - -static int outc(int c, void *cl) { - FILE *f = cl; - return putc(c, f); -} - -static int insert(int c, void *cl) { - struct buf *p = cl; - assert (p->bp < (p->buf + p->size)); - *p->bp++ = c; - return c; -} - -static int append(int c, void *cl) { - struct buf *p = cl; - if (p->bp >= p->buf + p->size) { - C_RESIZE(p->buf, 2*p->size); - p->bp = p->buf + p->size; - p->size *= 2; - } - *p->bp++ = c; - return c; -} - -void c_Fmt_puts(const char *str, int len, - int put(int c, void *cl), void *cl, - unsigned char flags[], int width, int precision) { - assert(str); - assert(len >= 0); - assert(flags); - if (width == INT_MIN) - width = 0; - if (width < 0) { - flags['-'] = 1; - width = -width; - } - if (precision >= 0) - flags['0'] = 0; - if (precision >= 0 && precision < len) - len = precision; - if (!flags['-']) - pad(width - len, ' '); - { - int i; - for (i = 0; i < len; i++) - put((unsigned char)*str++, cl); - } - if ( flags['-']) - pad(width - len, ' '); -} - -void c_Fmt_fmt(int put(int c, void *), void *cl, - const char *fmt, ...) { - va_list_box box; - va_start(box.ap, fmt); - c_Fmt_vfmt(put, cl, fmt, &box); - va_end(box.ap); -} - -void c_Fmt_print(const char *fmt, ...) { - va_list_box box; - va_start(box.ap, fmt); - c_Fmt_vfmt(outc, stdout, fmt, &box); - va_end(box.ap); -} -void c_Fmt_fprint(FILE *stream, const char *fmt, ...) { - va_list_box box; - va_start(box.ap, fmt); - c_Fmt_vfmt(outc, stream, fmt, &box); - va_end(box.ap); -} - -int c_Fmt_sfmt(char *buf, int size, const char *fmt, ...) { - int len; - va_list_box box; - va_start(box.ap, fmt); - len = c_Fmt_vsfmt(buf, size, fmt, &box); - va_end(box.ap); - return len; -} -int c_Fmt_vsfmt(char *buf, int size, const char *fmt, - va_list_box *box) { - struct buf cl; - assert(buf); - assert(size > 0); - assert(fmt); - cl.buf = cl.bp = buf; - cl.size = size; - c_Fmt_vfmt(insert, &cl, fmt, box); - insert(0, &cl); - return cl.bp - cl.buf - 1; -} - -char *c_Fmt_string(const char *fmt, ...) { - char *str; - va_list_box box; - assert(fmt); - va_start(box.ap, fmt); - str =c_Fmt_vstring(fmt, &box); - va_end(box.ap); - return str; -} -char *c_Fmt_vstring(const char *fmt, va_list_box *box) { - struct buf cl; - assert(fmt); - cl.size = 256; - cl.buf = cl.bp = C_ALLOC(cl.size); - c_Fmt_vfmt(append, &cl, fmt, box); - append(0, &cl); - return C_RESIZE(cl.buf, cl.bp - cl.buf); -} - -void c_Fmt_vfmt(int put(int c, void *cl), void *cl, - const char *fmt, va_list_box *box) { - assert(put); - assert(fmt); - while (*fmt) - if (*fmt != '%' || *++fmt == '%') - put((unsigned char)*fmt++, cl); - else - { - unsigned char c, flags[256]; - int width = INT_MIN, precision = INT_MIN; - memset(flags, '\0', sizeof flags); - if (c_Fmt_flags) { - unsigned char c = *fmt; - for ( ; c && strchr(c_Fmt_flags, c); c = *++fmt) { - assert(flags[c] < 255); - flags[c]++; - } - } - if (*fmt == '*' || isdigit(*fmt)) { - int n; - if (*fmt == '*') { - n = va_arg(box->ap, int); - assert(n != INT_MIN); - fmt++; - } else - for (n = 0; isdigit(*fmt); fmt++) { - int d = *fmt - '0'; - assert(n <= (INT_MAX - d)/10); - n = 10*n + d; - } - width = n; - } - if (*fmt == '.' && (*++fmt == '*' || isdigit(*fmt))) { - int n; - if (*fmt == '*') { - n = va_arg(box->ap, int); - assert(n != INT_MIN); - fmt++; - } else - for (n = 0; isdigit(*fmt); fmt++) { - int d = *fmt - '0'; - assert(n <= (INT_MAX - d)/10); - n = 10*n + d; - } - precision = n; - } - c = *fmt++; - assert(cvt[c]); - (*cvt[c])(c, box, put, cl, flags, width, precision); - } -} - -T c_Fmt_register(int code, T newcvt) { - T old; - assert(0 < code - && code < (int)(sizeof (cvt)/sizeof (cvt[0]))); - old = cvt[code]; - cvt[code] = newcvt; - return old; -} - -void c_Fmt_putd(const char *str, int len, - int put(int c, void *cl), void *cl, - unsigned char flags[], int width, int precision) { - int sign; - assert(str); - assert(len >= 0); - assert(flags); - if (width == INT_MIN) - width = 0; - if (width < 0) { - flags['-'] = 1; - width = -width; - } - if (precision >= 0) - flags['0'] = 0; - if (len > 0 && (*str == '-' || *str == '+')) { - sign = *str++; - len--; - } else if (flags['+']) - sign = '+'; - else if (flags[' ']) - sign = ' '; - else - sign = 0; - { int n; - if (precision < 0) - precision = 1; - if (len < precision) - n = precision; - else if (precision == 0 && len == 1 && str[0] == '0') - n = 0; - else - n = len; - if (sign) - n++; - if (flags['-']) { - if (sign) - put(sign, cl); - } else if (flags['0']) { - if (sign) - put(sign, cl); - pad(width - n, '0'); - } else { - pad(width - n, ' '); - if (sign) - put(sign, cl); - } - pad(precision - len, '0'); - { - int i; - for (i = 0; i < len; i++) - put((unsigned char)*str++, cl); - } - if (flags['-']) - pad(width - n, ' '); } -} diff --git a/Foundation/c_Fmt.h b/Foundation/c_Fmt.h deleted file mode 100644 index a5f9f16..0000000 --- a/Foundation/c_Fmt.h +++ /dev/null @@ -1,70 +0,0 @@ -#ifndef INCLUDED_C_FMT_H -#define INCLUDED_C_FMT_H - -#ifndef INCLUDED_C_TYPES_H -#include -#endif /*INCLUDED_C_TYPES_H*/ - -#ifndef INCLUDED_STDIO_H -#define INCLUDED_STDIO_H -#include -#endif /*INCLUDED_STDIO_H*/ - -#ifndef INCLUDED_STDARG_H -#define INCLUDED_STDARG_H -#include -#endif /*INCLUDED_STDARG_H*/ - - - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -typedef struct va_list_box { - va_list ap; -} va_list_box; - -#ifdef T -#undef T -#endif - -#define T c_Fmt_t - -typedef void (*T)(int code, va_list_box *box, - int put(int c, void *cl), void *cl, - unsigned char flags[256], int width, int precision); - -extern void c_Fmt_fmt (int put(int c, void *cl), void *cl, - const char *fmt, ...); - -extern void c_Fmt_vfmt(int put(int c, void *cl), void *cl, - const char *fmt, va_list_box *box); - -extern void c_Fmt_print (const char *fmt, ...); - -extern void c_Fmt_fprint(FILE *stream, - const char *fmt, ...); - -extern int c_Fmt_sfmt (char *buf, int size, - const char *fmt, ...); - -extern int c_Fmt_vsfmt(char *buf, int size, - const char *fmt, va_list_box *box); - -extern char *c_Fmt_string (const char *fmt, ...); - -extern char *c_Fmt_vstring(const char *fmt, va_list_box *box); - -extern T c_Fmt_register(int code, T cvt); - -extern void c_Fmt_putd(const char *str, int len, - int put(int c, void *cl), void *cl, - unsigned char flags[256], int width, int precision); - -extern void c_Fmt_puts(const char *str, int len, - int put(int c, void *cl), void *cl, - unsigned char flags[256], int width, int precision); - -#undef T - -#endif /*INCLUDED_C_FMT_H*/ diff --git a/Foundation/c_KnuthShuffle.c b/Foundation/c_KnuthShuffle.c deleted file mode 100644 index 5444f75..0000000 --- a/Foundation/c_KnuthShuffle.c +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/Foundation/c_KnuthShuffle.h b/Foundation/c_KnuthShuffle.h deleted file mode 100644 index fd74b69..0000000 --- a/Foundation/c_KnuthShuffle.h +++ /dev/null @@ -1,57 +0,0 @@ -#ifndef INCLUDED_C_KNUTHSHUFFLE_H -#define INCLUDED_C_KNUTHSHUFFLE_H - -#ifndef INCLUDED_C_MEMORY_H -#include -#endif /*INCLUDED_C_MEMORY_H*/ - - -#ifndef INCLUDED_STDLIB_H -#define INCLUDED_STDLIB_H -#include -#endif /*INCLUDED_STDLIB_H*/ - - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -/** - * 通用 Knuth 洗牌演算法 - * @param base 指向待打亂陣列首元素的指標 - * @param num 陣列中元素的個數 - * @param size 每個元素的大小(位元組數) - */ -C_STATIC_FORCE_INLINE -void c_KnuthShuffle(void* base, c_size_t num, c_size_t size) { - if (base == NULL || num < 2 || size == 0) return; - - char* arr = (char*)base; - - // 使用棧快取 buffer 進行記憶體交換,避免堆分配開銷 -#define SHUFFLE_STACK_LIMIT 128 - char stack_buf[SHUFFLE_STACK_LIMIT]; - void* temp = (size <= SHUFFLE_STACK_LIMIT) ? stack_buf : C_ALLOC(size); - if (temp == NULL) return; - - // 從後往前遍歷陣列 - for (c_int_t i = num - 1; i > 0; i--) { - // 生成一個 0 到 i 之間(包含 i)的隨機索引 - c_int_t j = rand() % (i + 1); - - // 交換 arr[i] 和 arr[j] - if (i != j) { - char* a = arr + (i * size); - char* b = arr + (j * size); - memcpy(temp, a, size); - memcpy(a, b, size); - memcpy(b, temp, size); - } - } - - if (size > SHUFFLE_STACK_LIMIT) { - C_FREE(temp); - } -#undef SHUFFLE_STACK_LIMIT -} - -#endif /*INCLUDED_C_KNUTHSHUFFLE_H*/ diff --git a/Foundation/c_KnuthShuffle.t.c b/Foundation/c_KnuthShuffle.t.c deleted file mode 100644 index a93af13..0000000 --- a/Foundation/c_KnuthShuffle.t.c +++ /dev/null @@ -1,101 +0,0 @@ -#include "c_KnuthShuffle.h" -#include -#include - -// Advanced Line-Tracing Diagnostic Macro -#define EXPECT_EQ(actual, expected, msg) \ - do { \ - if ((actual) != (expected)) { \ - printf(" [X] Assert Failed: %s (Expected %d, got %d) %s:%d\n", msg, (int)(expected), (int)(actual), __FILE__, __LINE__); \ - return C_FALSE; \ - } \ - } while(0) - -// Complex struct data payload representing simulation cards -typedef struct { - int card_id; - char suit; -} DeckCard; - -// External declaration of your framework's Knuth Shuffle module -extern void c_KnuthShuffle(void* base, c_size_t num, c_size_t size); - -/** - * Unit Test Profile: Validates extreme boundaries, statistical disordering, - * and strict payload preservation without data loss. - */ -c_bool_t test_knuth_shuffle_lifecycle(void) { - // Seed the standard pseudo-random number generator for the shuffle module - srand((unsigned int)time(NULL)); - - // Checkpoint 1: Boundary conditions check (Should return safely without crashing) - int* null_ptr = NULL; - c_KnuthShuffle(null_ptr, 0, sizeof(int)); // NULL pointer escape guard - - int single_array[] = { 99 }; - c_KnuthShuffle(single_array, 1, sizeof(int)); - EXPECT_EQ(single_array[0], 99, "Single element array mutated unexpectedly"); - - // Initialize an ordered deck array of 10 complex structural cards - DeckCard deck[10]; - c_size_t total_cards = sizeof(deck) / sizeof(deck[0]); - char suits[] = {'H', 'D', 'C', 'S'}; - - for (c_size_t i = 0; i < total_cards; i++) { - deck[i].card_id = (int)(i + 1); - deck[i].suit = suits[i % 4]; - } - - // Clone the original array configuration to verify data preservation metrics later - DeckCard deck_snapshot[10]; - memcpy(deck_snapshot, deck, sizeof(deck)); - - printf(" [LOG] Executing c_KnuthShuffle across 10 complex data elements...\n"); - c_KnuthShuffle(deck, total_cards, sizeof(DeckCard)); - - // Checkpoint 2: Verification of statistical mismatch (Disordering check) - c_size_t identical_matches = 0; - for (c_size_t i = 0; i < total_cards; i++) { - if (deck[i].card_id == deck_snapshot[i].card_id) { - identical_matches++; - } - } - - // Mathematically, the probability of a 10-element array remaining completely - // identical or barely modified after a fair shuffle is near zero (~1 in 3.6 million). - printf(" [STAT] Element slots remaining in original positions: %zu/%zu\n", identical_matches, total_cards); - EXPECT_EQ(identical_matches < total_cards, C_TRUE, "Shuffle algorithm failed to re-arrange element configurations"); - - // Checkpoint 3: Strict Data Integrity Verification (De-duplication & Conservation check) - // Ensure that every single original item still exists inside the shuffled deck exactly once. - c_bool_t found_flags[10] = { C_FALSE }; - c_size_t unique_restored_count = 0; - - for (c_size_t i = 0; i < total_cards; i++) { - for (c_size_t j = 0; j < total_cards; j++) { - if (deck[i].card_id == deck_snapshot[j].card_id && deck[i].suit == deck_snapshot[j].suit) { - if (!found_flags[j]) { - found_flags[j] = C_TRUE; - unique_restored_count++; - } - break; - } - } - } - - EXPECT_EQ(unique_restored_count, total_cards, "Shuffle step introduced data corruption, duplicates, or element losses"); - printf(" [PASS] All 10 original complex items conserved perfectly with zero data leakage.\n"); - - return C_TRUE; -} - -int main(void) { - printf("=== Starting Framework Verification: c_KnuthShuffle ===\n"); - - if (test_knuth_shuffle_lifecycle()) { - printf(" [PASS] Knuth Linear-Time Shuffle Validation & Payload Conservation Verified.\n"); - } else { - printf(" [FAIL] Shuffle Optimization Pipeline Errors Intercepted.\n"); - } - return 0; -} \ No newline at end of file diff --git a/Foundation/c_LinkDQueue.c b/Foundation/c_LinkDQueue.c deleted file mode 100644 index b5a5eb1..0000000 --- a/Foundation/c_LinkDQueue.c +++ /dev/null @@ -1,153 +0,0 @@ -#include -#include -#include -#include "c_Macros.h" - -C_STATIC_FORCE_INLINE -c_LinkDQueueNode_t* create_node(int obj_size, void* obj) { - int size = sizeof(c_LinkDQueueNode_t) + obj_size; - size = C_ALIGN_UPB(size, C_ALIGN_SIZE); - - c_LinkDQueueNode_t* new_node = (c_LinkDQueueNode_t*)C_ALLOC(size); - if (!new_node) return NULL; - new_node->data = new_node + 1; - - memcpy(new_node->data, obj, obj_size); - new_node->prev = NULL; - new_node->next = NULL; - return new_node; -} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -c_err_t c_LinkDQueue_Init(c_LinkDQueue_t* self, int obj_size) { - if (!self || obj_size <= 0) return C_ERR_PARAM; - self->head = NULL; - self->tail = NULL; - self->obj_size = obj_size; - self->size = 0; - return C_ERR_OK; -} - -void c_LinkDQueue_Destroy(c_LinkDQueue_t* self) { - if (!self) return; - c_LinkDQueueNode_t* current = self->head; - while (current != NULL) { - c_LinkDQueueNode_t* next = current->next; - C_FREE(current); - current = next; - } - self->head = NULL; - self->tail = NULL; - self->size = 0; -} - -// 前端推入 O(1) -c_err_t c_LinkDQueue_PushHead(c_LinkDQueue_t* self, void* obj) { - if (!self || !obj) return C_ERR_PARAM; - c_LinkDQueueNode_t* new_node = create_node(self->obj_size, obj); - if (!new_node) return C_ERR_NOMEM; - - if (self->size == 0) { - self->head = new_node; - self->tail = new_node; - } else { - new_node->next = self->head; - self->head->prev = new_node; - self->head = new_node; - } - self->size++; - return C_ERR_OK; -} - -// 尾端推入 O(1) -c_err_t c_LinkDQueue_PushTail(c_LinkDQueue_t* self, void* obj) { - if (!self || !obj) return C_ERR_PARAM; - c_LinkDQueueNode_t* new_node = create_node(self->obj_size, obj); - if (!new_node) return C_ERR_NOMEM; - - if (self->size == 0) { - self->head = new_node; - self->tail = new_node; - } else { - new_node->prev = self->tail; - self->tail->next = new_node; - self->tail = new_node; - } - self->size++; - return C_ERR_OK; -} - -// 前端彈出 O(1) -c_err_t c_LinkDQueue_PopHead(c_LinkDQueue_t* self, void* obj) { - if (!self || !obj) return C_ERR_PARAM; - if (self->size == 0) return C_ERR_EMPTY; - - c_LinkDQueueNode_t* to_delete = self->head; - memcpy(obj, to_delete->data, self->obj_size); - - self->head = to_delete->next; - if (self->head == NULL) { - self->tail = NULL; // 變空佇列 - } else { - self->head->prev = NULL; - } - - C_FREE(to_delete); - self->size--; - return C_ERR_OK; -} - -// 尾端彈出 O(1) -c_err_t c_LinkDQueue_PopTail(c_LinkDQueue_t* self, void* obj) { - if (!self || !obj) return C_ERR_PARAM; - if (self->size == 0) return C_ERR_EMPTY; - - c_LinkDQueueNode_t* to_delete = self->tail; - memcpy(obj, to_delete->data, self->obj_size); - - self->tail = to_delete->prev; - if (self->tail == NULL) { - self->head = NULL; // 變空佇列 - } else { - self->tail->next = NULL; - } - - C_FREE(to_delete); - self->size--; - return C_ERR_OK; -} - -void* c_LinkDQueue_PeekHead(c_LinkDQueue_t* self) { - if (!self || self->size == 0) return NULL; - return self->head->data; -} - -void* c_LinkDQueue_PeekTail(c_LinkDQueue_t* self) { - if (!self || self->size == 0) return NULL; - return self->tail->data; -} - -// 迭代器安全刪除:利用雙向指標在 O(1) 修正前後驅關係並安全維護 head/tail -void c_LinkDQueueIter_Remove(c_LinkDQueueIter_t* self) { - if (!self || !self->dqueue || !self->node || !*(self->node)) return; - - c_LinkDQueueNode_t* to_delete = *(self->node); - c_LinkDQueue_t* dq = self->dqueue; - - // 1. 修正前驅節點的 next 或主結構的 head - *(self->node) = to_delete->next; - - // 2. 修正後繼節點的 prev 或主結構的 tail - if (to_delete->next != NULL) { - to_delete->next->prev = to_delete->prev; - } else { - dq->tail = to_delete->prev; // 刪除的是尾端,更新 tail - } - - // 3. 釋放資源與修正大小 - C_FREE(to_delete); - dq->size--; -} - diff --git a/Foundation/c_LinkDQueue.h b/Foundation/c_LinkDQueue.h deleted file mode 100644 index 787361e..0000000 --- a/Foundation/c_LinkDQueue.h +++ /dev/null @@ -1,77 +0,0 @@ -#ifndef INCLUDED_C_LINKDQUEUE_H -#define INCLUDED_C_LINKDQUEUE_H - -#ifndef INCLUDED_C_TYPES_H -#include -#endif /*INCLUDED_C_TYPES_H*/ - - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -typedef struct c_LinkDQueueNode_t { - void* data; - struct c_LinkDQueueNode_t* prev; - struct c_LinkDQueueNode_t* next; -} c_LinkDQueueNode_t; - -// 雙端佇列控制結構 -typedef struct { - c_LinkDQueueNode_t* head; - c_LinkDQueueNode_t* tail; - int obj_size; - c_size_t size; -} c_LinkDQueue_t; - -// 雙端佇列迭代器(維持指標的指標設計,預設從 head 往 tail 走訪) -typedef struct { - c_LinkDQueue_t* dqueue; - c_LinkDQueueNode_t** node; -} c_LinkDQueueIter_t; - -// 核心函數宣告 -c_err_t c_LinkDQueue_Init(c_LinkDQueue_t* self, int obj_size); -void c_LinkDQueue_Destroy(c_LinkDQueue_t* self); - -c_err_t c_LinkDQueue_PushHead(c_LinkDQueue_t* self, void* obj); -c_err_t c_LinkDQueue_PushTail(c_LinkDQueue_t* self, void* obj); - -c_err_t c_LinkDQueue_PopHead(c_LinkDQueue_t* self, void* obj); -c_err_t c_LinkDQueue_PopTail(c_LinkDQueue_t* self, void* obj); - -void* c_LinkDQueue_PeekHead(c_LinkDQueue_t* self); -void* c_LinkDQueue_PeekTail(c_LinkDQueue_t* self); - -void c_LinkDQueueIter_Remove(c_LinkDQueueIter_t* self); - -// 迭代器內聯函數 -C_STATIC_FORCE_INLINE -void c_LinkDQueueIter_Init(c_LinkDQueueIter_t* self, c_LinkDQueue_t* dqueue) { - if (!self || !dqueue) return; - self->dqueue = dqueue; - self->node = &dqueue->head; -} - -C_STATIC_FORCE_INLINE -c_bool_t c_LinkDQueueIter_HasNext(c_LinkDQueueIter_t* self) { - if (!self) return C_FALSE; - return (self->node != NULL) && (*(self->node) != NULL); -} - -C_STATIC_FORCE_INLINE -void* c_LinkDQueueIter_Next(c_LinkDQueueIter_t* self) { - if (!self || !self->node || !*(self->node)) return NULL; - void* data = (*(self->node))->data; - self->node = &(*(self->node))->next; - return data; -} - -C_STATIC_FORCE_INLINE -void* c_LinkDQueueIter_Get(c_LinkDQueueIter_t* self) { - if (!self || !self->node || !*(self->node)) return NULL; - return (*(self->node))->data; -} - -void c_LinkDQueueIter_Remove(c_LinkDQueueIter_t* self); - -#endif /*INCLUDED_C_LINKDQUEUE_H*/ diff --git a/Foundation/c_LinkDQueue.t.c b/Foundation/c_LinkDQueue.t.c deleted file mode 100644 index bd584d4..0000000 --- a/Foundation/c_LinkDQueue.t.c +++ /dev/null @@ -1,110 +0,0 @@ -#include "c_LinkDQueue.h" -#include -#include -#include - -typedef struct { - char label[16]; - int val; -} Element_t; - -void test_log(const char* test_name) { - printf("[PASS] %s\n", test_name); -} - -int main() { - printf("==================================================\n"); - printf(" 開始執行 c_LinkDQueue 雙端佇列完整測試用例\n"); - printf("==================================================\n\n"); - - c_LinkDQueue_t dq; - c_LinkDQueue_Init(&dq, sizeof(Element_t)); - - Element_t e1 = {"Node_1", 10}; - Element_t e2 = {"Node_2", 20}; - Element_t e3 = {"Node_3", 30}; - - // ========================================== - // 1. 測試雙端推入 (PushHead & PushTail) - // ========================================== - // 先把 e2 推入尾端 (佇列: [e2]) - c_LinkDQueue_PushTail(&dq, &e2); - // 把 e1 推入前端 (佇列: [e1, e2]) - c_LinkDQueue_PushHead(&dq, &e1); - // 把 e3 推入尾端 (佇列: [e1, e2, e3]) - c_LinkDQueue_PushTail(&dq, &e3); - - assert(dq.size == 3); - assert(((Element_t*)c_LinkDQueue_PeekHead(&dq))->val == 10); - assert(((Element_t*)c_LinkDQueue_PeekTail(&dq))->val == 30); - test_log("1. 雙端交錯推入與邊界 Peek 驗證成功"); - - // ========================================== - // 2. 測試迭代器走訪 - // ========================================== - c_LinkDQueueIter_t iter; - c_LinkDQueueIter_Init(&iter, &dq); - int idx = 0; - while (c_LinkDQueueIter_HasNext(&iter)) { - Element_t* el = (Element_t*)c_LinkDQueueIter_Next(&iter); - if (idx == 0) assert(el->val == 10); - if (idx == 1) assert(el->val == 20); - if (idx == 2) assert(el->val == 30); - idx++; - } - test_log("2. 迭代器正向走訪順序驗證成功"); - - // ========================================== - // 3. 測試迭代器刪除中間節點 (Remove e2) - // ========================================== - c_LinkDQueueIter_Init(&iter, &dq); - while (c_LinkDQueueIter_HasNext(&iter)) { - Element_t* el = (Element_t*)c_LinkDQueueIter_Get(&iter); - if (el->val == 20) { - c_LinkDQueueIter_Remove(&iter); // 刪除 Node_2 - } else { - c_LinkDQueueIter_Next(&iter); - } - } - assert(dq.size == 2); - // 驗證現在內容只剩下 [e1, e3] - assert(((Element_t*)c_LinkDQueue_PeekHead(&dq))->val == 10); - assert(((Element_t*)c_LinkDQueue_PeekTail(&dq))->val == 30); - test_log("3. 迭代器 O(1) 刪除中間節點暨雙向鏈結維護成功"); - - // ========================================== - // 4. 測試雙端彈出 (PopHead & PopTail) - // ========================================== - Element_t buf; - - // 從前端彈出(應拿到 e1) - c_err_t err = c_LinkDQueue_PopHead(&dq, &buf); - assert(err == C_ERR_OK); - assert(buf.val == 10); - assert(dq.size == 1); - - // 從尾端彈出(應拿到 e3) - err = c_LinkDQueue_PopTail(&dq, &buf); - assert(err == C_ERR_OK); - assert(buf.val == 30); - assert(dq.size == 0); - - // 驗證完全清空後指標皆重置為 NULL - assert(dq.head == NULL); - assert(dq.tail == NULL); - test_log("4. 雙端彈出與空佇列指標歸零驗證成功"); - - // ========================================== - // 5. 空佇列防呆測試 - // ========================================== - assert(c_LinkDQueue_PopHead(&dq, &buf) == C_ERR_EMPTY); - assert(c_LinkDQueue_PopTail(&dq, &buf) == C_ERR_EMPTY); - assert(c_LinkDQueue_PeekHead(&dq) == NULL); - test_log("5. 空雙端佇列越界防呆成功"); - - c_LinkDQueue_Destroy(&dq); - printf("\n==================================================\n"); - printf(" 恭喜!c_LinkDQueue 所有核心特性單元測試完美通過!\n"); - printf("==================================================\n"); - return 0; -} \ No newline at end of file diff --git a/Foundation/c_LinkList.c b/Foundation/c_LinkList.c index f350f29..7625f55 100644 --- a/Foundation/c_LinkList.c +++ b/Foundation/c_LinkList.c @@ -1,82 +1,143 @@ #include -#include -#include -#include "c_Macros.h" -c_err_t c_LinkList_Init(c_LinkList_t* self, c_size_t obj_size) { - if (!self || obj_size == 0) return C_ERR_PARAM; - self->head = NULL; - self->obj_size = (int)obj_size; +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +// 辅助内联宏:通过节点指针直接获取其内部存储的用户数据区地址 +#define NODE_DATA(node) ((void*)((char*)(node) + sizeof(c_LinkNode_t))) + + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + + +// 原地初始化:建立哑哨兵头节点 +c_err_t c_LinkList_Init(c_LinkList_t* self, c_size_t item_size, c_Allocator_t* allocator) { + if (!self || item_size == 0) return C_ERR_PARAM; + + self->allocator = (allocator != NULL) ? *allocator : c_DefaultAllocator; + self->item_size = item_size; self->size = 0; + self->head = 0; return C_ERR_OK; } -void c_LinkList_Destroy(c_LinkList_t* self) { - if (!self) return; +// 辅助函数:创建承载用户数据的值复制节点 +C_STATIC_FORCE_INLINE +c_LinkNode_t* c_LinkList_CreateNode(c_LinkList_t* self, const void* item) { + c_size_t total_bytes = sizeof(c_LinkNode_t) + self->item_size; + c_LinkNode_t* new_node = (c_LinkNode_t*)c_Allocator_Alloc(&self->allocator, total_bytes); + if (!new_node) return NULL; - c_LinkListNode_t* current = self->head; - while (current != NULL) { - c_LinkListNode_t* next = current->next; - // 由於 Add 時 data 與 node 是分開或合開,此處依據一體化配置釋放 - C_FREE(current); - current = next; - } - self->head = NULL; - self->size = 0; + new_node->next = NULL; + memcpy(NODE_DATA(new_node), item, self->item_size); // 泛型值深度复制 + return new_node; } -c_err_t c_LinkList_Add(c_LinkList_t* self, void* obj) { - if (!self || !obj) return C_ERR_PARAM; +// O(1) 头部高效插入 +c_err_t c_LinkList_AddHead(c_LinkList_t* self, const void* item) { + if (!self || !self->head || !item) return C_ERR_PARAM; - int size = (int)sizeof(c_LinkListNode_t) + self->obj_size; - size = C_ALIGN_UPB(size, C_ALIGN_SIZE); - c_LinkListNode_t* new_node = (c_LinkListNode_t*)C_ALLOC(size); + c_LinkNode_t* new_node = c_LinkList_CreateNode(self, item); if (!new_node) return C_ERR_NOMEM; - new_node->data = new_node+1; - // 值複製 (Value Copy) - memcpy(new_node->data, obj, self->obj_size); - - // 頭插法鏈結 new_node->next = self->head; self->head = new_node; + self->size++; + return C_ERR_OK; +} + +// O(N) 尾部追加插入 +c_err_t c_LinkList_AddTail(c_LinkList_t* self, const void* item) { + if (!self || !item) return C_ERR_PARAM; + + // 二级指针直接指向控制头里的 head 指针变量本身地址 + c_LinkNode_t** pp = &(self->head); + + // 一路滑移到单链表的尽头(即找到那个内部存储着 NULL 的坑位) + while (*pp != NULL) { + pp = &((*pp)->next); + } + + // 此时 *pp 必然是 NULL。不管链表原先是不是空,我们直接用这行代码注入新节点地址: + *pp = c_LinkList_CreateNode(self, item); + if (!*pp) return C_ERR_NOMEM; + + self->size++; + return C_ERR_OK; +} + +// 【二级指针艺术】:根据指定索引精准裁剪节点,并扣减计数 +c_err_t c_LinkList_RemoveAt(c_LinkList_t* self, c_size_t index, void* out_item) { + if (!self || index >= self->size) return C_ERR_PARAM; + + // 初始咬定核心变量 &self->head 坑位地址 + c_LinkNode_t** pp = &(self->head); + + // 精准步进到要移除的索引位置 + for (c_size_t i = 0; i < index; i++) { + pp = &((*pp)->next); + } + + // 此时 *pp 正好是“指向要被删除节点”的物理指针 + c_LinkNode_t* node_to_free = *pp; + + if (out_item) { + memcpy(out_item, NODE_DATA(node_to_free), self->item_size); + } + + // 核心裁剪:直接重写前驱的指针域。如果 index 为 0,这里等同于就地修改了 self->head 的值! + // 一行代码,完美合并了“删除第一个节点”和“删除后续项”的两套高危处理流 + *pp = node_to_free->next; + + // 回收资源并扣减账目 + c_Allocator_Free(&self->allocator, node_to_free); + self->size--; return C_ERR_OK; } -c_err_t c_LinkList_Remove(c_LinkList_t* self, void* obj) { - if (!self || !obj) return C_ERR_PARAM; +// 安全的从链表中读取指定索引处的值拷贝 +c_err_t c_LinkList_Read(const c_LinkList_t* self, c_size_t index, void* out_item) { + if (!self || !out_item || index >= self->size) return C_ERR_PARAM; - c_LinkListNode_t** curr = &self->head; - while (*curr != NULL) { - // 使用 memcmp 進行二進位值比對 - if (memcmp((*curr)->data, obj, self->obj_size) == 0) { - c_LinkListNode_t* to_delete = *curr; - *curr = to_delete->next; - - C_FREE(to_delete); - self->size--; - return C_ERR_OK; - } - curr = &(*curr)->next; + c_LinkNode_t* curr = self->head; // 从真实的 head 节点起步 + for (c_size_t i = 0; i < index; i++) { + curr = curr->next; } - return C_ERR_FAIL; + memcpy(out_item, NODE_DATA(curr), self->item_size); + return C_ERR_OK; } -void c_LinkListIter_Remove(c_LinkListIter_t* self) { - if (!self || !self->list || !self->node || !*(self->node)) return; +// 只读原位窥探指针(注意:不要在发生 Add/Remove 后持久持有它,防止发生野指针悬空) +void* c_LinkList_Get(const c_LinkList_t* self, c_size_t index) { + if (!self || index >= self->size) return NULL; - c_LinkListNode_t* to_delete = *(self->node); - - // 讓上一個節點的 next 指向下一個節點,移除鏈結 - *(self->node) = to_delete->next; - - // 釋放該節點的值與結構 - C_FREE(to_delete); - - self->list->size--; + c_LinkNode_t* curr = self->head; + for (c_size_t i = 0; i < index; i++) { + curr = curr->next; + } + return NODE_DATA(curr); } +// 快速清空链表 +void c_LinkList_Clear(c_LinkList_t* self) { + if (!self) return; + c_LinkNode_t* curr = self->head; + while (curr) { + c_LinkNode_t* next_to_free = curr->next; + c_Allocator_Free(&self->allocator, curr); + curr = next_to_free; + } + self->head = NULL; // 还原到你 Init 指定的 0 状态 + self->size = 0; +} + +// 彻底解体 +void c_LinkList_Destroy(c_LinkList_t* self) { + if (!self) return; + c_LinkList_Clear(self); +} diff --git a/Foundation/c_LinkList.h b/Foundation/c_LinkList.h index fbc106b..690359e 100644 --- a/Foundation/c_LinkList.h +++ b/Foundation/c_LinkList.h @@ -5,66 +5,118 @@ #include #endif /*INCLUDED_C_TYPES_H*/ -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ +#ifndef INCLUDED_C_ALLOCATOR_H +#include +#endif /*INCLUDED_C_ALLOCATOR_H*/ -typedef struct c_LinkListNode_t { - void* data; - struct c_LinkListNode_t* next; -}c_LinkListNode_t; - -typedef struct { - c_LinkListNode_t* head; - int obj_size; - c_size_t size; -}c_LinkList_t; - -typedef struct { - c_LinkList_t* list; - c_LinkListNode_t** node; -}c_LinkListIter_t; /* ------------------------------------------------------------------------------------------------------------------ */ /* */ -c_err_t c_LinkList_Init(c_LinkList_t* self, c_size_t obj_size); -void c_LinkList_Destroy(c_LinkList_t* self); +typedef struct c_LinkNode_t { + struct c_LinkNode_t* next; // 后驱节点 + // 后面会紧跟一整块大小为 item_size 的物理连续内存块直接存放真实数据值 +} c_LinkNode_t; -c_err_t c_LinkList_Add(c_LinkList_t* self, void* obj); +// 闭环泛型单向链表控制头 +typedef struct { + c_LinkNode_t* head; // 哑哨兵头节点(Dummy Head) + c_size_t item_size; // 单个元素的字节大小 + c_size_t size; // 当前链表中已有的有效元素个数 + c_Allocator_t allocator; // 内部绑定的自主内存管理器 +} c_LinkList_t; -c_err_t c_LinkList_Remove(c_LinkList_t* self, void* obj); +typedef struct { + c_LinkList_t* list; // 绑定的非 const 宿主链表,用于联动 size + c_LinkNode_t** pp; // 核心二级指针,映射前驱或控制头指针域物理坑位地址 +} c_LinkListIter_t; + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +c_err_t c_LinkList_Init(c_LinkList_t* self, c_size_t item_size, c_Allocator_t* allocator); +void c_LinkList_Destroy(c_LinkList_t* self); + +// 核心单向链表操作 API (值复制存储模式) +c_err_t c_LinkList_AddHead(c_LinkList_t* self, const void* item); +c_err_t c_LinkList_AddTail(c_LinkList_t* self, const void* item); +c_err_t c_LinkList_RemoveAt(c_LinkList_t* self, c_size_t index, void* out_item); +c_err_t c_LinkList_Read(const c_LinkList_t* self, c_size_t index, void* out_item); +void* c_LinkList_Get(const c_LinkList_t* self, c_size_t index); +void c_LinkList_Clear(c_LinkList_t* self); + +// 内联高频辅助接口 +C_STATIC_FORCE_INLINE +c_size_t c_LinkList_Size(const c_LinkList_t* self) { + if (!self) return 0; + return self->size; // O(1) 实时读取 +} + +C_STATIC_FORCE_INLINE +bool c_LinkList_IsEmpty(const c_LinkList_t* self) { + return c_LinkList_Size(self) == 0; +} + +C_STATIC_FORCE_INLINE +void* c_LinkNode_Get(const c_LinkNode_t* self) { + if (!self) return NULL; + return ((void*)((char*)(self) + sizeof(c_LinkNode_t))); +} /* ------------------------------------------------------------------------------------------------------------------ */ /* */ C_STATIC_FORCE_INLINE void c_LinkListIter_Init(c_LinkListIter_t* self, c_LinkList_t* list) { - if (!self || !list) return; + if (!self) return; self->list = list; - self->node = &list->head; + if (!list) { + self->pp = NULL; + return; + } + // 灵魂一笔:初始直接指向控制头内部的那个真实的 head 指针变量地址 + self->pp = &(list->head); } C_STATIC_FORCE_INLINE -c_bool_t c_LinkListIter_HasNext(c_LinkListIter_t* self) { - if (!self) return C_FALSE; - return (self->node != NULL) && (*(self->node) != NULL); -} - -C_STATIC_FORCE_INLINE -void* c_LinkListIter_Next(c_LinkListIter_t* self) { - if (!self || !self->node || !*(self->node)) return NULL; - void* data = (*(self->node))->data; - self->node = &(*(self->node))->next; - return data; +bool c_LinkListIter_HasNext(const c_LinkListIter_t* self) { + return (self != NULL && self->pp != NULL && *self->pp != NULL); } C_STATIC_FORCE_INLINE void* c_LinkListIter_Get(c_LinkListIter_t* self) { - if (!self || !self->node || !*(self->node)) return NULL; - return (*(self->node))->data; + if (!c_LinkListIter_HasNext(self)) return NULL; + // 获取当前变长节点紧随其后的用户数据地址区域 + return ((void*)((char*)(*self->pp) + sizeof(c_LinkNode_t))); } -void c_LinkListIter_Remove(c_LinkListIter_t* self); +C_STATIC_FORCE_INLINE +void* c_LinkListIter_Next(c_LinkListIter_t* self) { + if (!c_LinkListIter_HasNext(self)) return NULL; + void* user_data = ((void*)((char*)(*self->pp) + sizeof(c_LinkNode_t))); + // 大步向前滑进:让二级指针改为指向当前节点内部的 next 域地址 + self->pp = &((*self->pp)->next); + return user_data; +} + +/** + * @brief 无哨兵裸链表极度抗震防跑飞自主擦除接口 (完美免疫 SIGSEGV) + */ +C_STATIC_FORCE_INLINE +void c_LinkListIter_Remove(c_LinkListIter_t* self) { + if (!c_LinkListIter_HasNext(self) || !self->list) return; + + c_LinkList_t* host_list = self->list; + c_LinkNode_t* node_to_free = *self->pp; + + // 拓扑剥离:修改前驱指向(若当前是第一个节点,这里会自动就地改写 host_list->head 的指向!) + // 修改完的这一瞬间,迭代器的 pp 变量自动对齐到了下一项有效节点,状态瞬间康复 + *self->pp = node_to_free->next; + + // 呼叫内置管理器物理火化 + c_Allocator_Free(&host_list->allocator, node_to_free); + host_list->size--; +} #endif /*INCLUDED_C_LINKLIST_H*/ diff --git a/Foundation/c_LinkList.t.c b/Foundation/c_LinkList.t.c index ce6ebb6..db87f82 100644 --- a/Foundation/c_LinkList.t.c +++ b/Foundation/c_LinkList.t.c @@ -1,68 +1,77 @@ #include "c_LinkList.h" #include #include -#include +#include "c_Test.h" typedef struct { - char name[4]; - int score; -} Student_t; - -int main() { - printf("開始執行 c_LinkList 測試用例...\n"); + int id; + int is_processed; +} DataEvent_t; +TEST_CASE(test_nosentinel_link_list_and_iterator_flow) { c_LinkList_t list; - c_LinkList_Init(&list, sizeof(Student_t)); - Student_t s1 = {"AAA", 80}; - Student_t s2 = {"BBB", 90}; - Student_t s3 = {"CCC", 95}; + // 验证你的新 Init API + ASSERT_INT_EQ(C_ERR_OK, c_LinkList_Init(&list, sizeof(DataEvent_t), NULL)); + ASSERT_TRUE(0==list.head); // 确认 head 严格等于 0 + ASSERT_TRUE(c_LinkList_IsEmpty(&list)); - // 1. 測試新增 (頭插法預期順序: CCC -> BBB -> AAA) - c_LinkList_Add(&list, &s1); - c_LinkList_Add(&list, &s2); - c_LinkList_Add(&list, &s3); - assert(list.size == 3); + DataEvent_t e1 = { .id = 10, .is_processed = 1 }; // 已处理,迭代时擦除 + DataEvent_t e2 = { .id = 20, .is_processed = 0 }; + DataEvent_t e3 = { .id = 30, .is_processed = 1 }; // 已处理,边界连续擦除 + DataEvent_t e4 = { .id = 40, .is_processed = 0 }; - // 2. 測試迭代器走訪 - c_LinkListIter_t iter; - c_LinkListIter_Init(&iter, &list); + // 1. 验证 AddTail 与 AddHead 在无哨兵下的完美二级指针闭环运转 + ASSERT_INT_EQ(C_ERR_OK, c_LinkList_AddTail(&list, &e1)); // Head -> 10 + ASSERT_INT_EQ(C_ERR_OK, c_LinkList_AddTail(&list, &e2)); // Head -> 10 -> 20 + ASSERT_INT_EQ(C_ERR_OK, c_LinkList_AddTail(&list, &e3)); // Head -> 10 -> 20 -> 30 + ASSERT_INT_EQ(C_ERR_OK, c_LinkList_AddHead(&list, &e4)); // 头插 40, 拓扑进化为: Head -> 40 -> 10 -> 20 -> 30 - printf("當前串列內容:\n"); - while (c_LinkListIter_HasNext(&iter)) { - Student_t* s = (Student_t*)c_LinkListIter_Next(&iter); - printf(" 學生: %s, 分數: %d\n", s->name, s->score); - } + ASSERT_INT_EQ(4, c_LinkList_Size(&list)); - // 3. 測試一般刪除 (Remove - 透過二進位資料比對刪除 "BBB") - Student_t target_remove = {"BBB", 90}; - c_err_t err = c_LinkList_Remove(&list, &target_remove); - assert(err == C_ERR_OK); - assert(list.size == 2); + // 2. 启动极致无哨兵二级指针迭代清理流 + c_LinkListIter_t it; + c_LinkListIter_Init(&it, &list); - // 4. 測試迭代器走訪並刪除 (Iter_Remove) - c_LinkListIter_Init(&iter, &list); - while (c_LinkListIter_HasNext(&iter)) { - Student_t* s = (Student_t*)c_LinkListIter_Get(&iter); - if (s->score == 80) { // 找到分數 80 的學生 (AAA) - c_LinkListIter_Remove(&iter); - printf("[Log] 迭代器成功刪除了分數為 80 的學生\n"); - } else { - c_LinkListIter_Next(&iter); + int scanned = 0; + while (c_LinkListIter_HasNext(&it)) { + DataEvent_t* ev = (DataEvent_t*)c_LinkListIter_Get(&it); + ASSERT_PTR_NOT_NULL(ev); + scanned++; + + if (ev->is_processed) { + // 自主剔除:当剔除 e1(10) 时,由于它是当时的第二项,其前驱是 e4 的 next + // 当剔除头项或末尾项时,二级指针无需任何 if 分支,在硬件层面一路展平串联 + c_LinkListIter_Remove(&it); + continue; } + c_LinkListIter_Next(&it); } - assert(list.size == 1); - // 5. 驗證最後留下來的是否為 CCC - c_LinkListIter_Init(&iter, &list); - Student_t* final_s = (Student_t*)c_LinkListIter_Get(&iter); - assert(strcmp(final_s->name, "CCC") == 0); + // 3. 终极断言验证 + ASSERT_INT_EQ(4, scanned); + ASSERT_INT_EQ(2, c_LinkList_Size(&list)); // 2 个已处理的脏数据被定点抹杀 + + // 严苛验证存活项的相对物理连续性 (剩下了 40 和 20) + DataEvent_t* r0 = (DataEvent_t*)c_LinkList_Get(&list, 0); + DataEvent_t* r1 = (DataEvent_t*)c_LinkList_Get(&list, 1); + + ASSERT_PTR_NOT_NULL(r0); + ASSERT_PTR_NOT_NULL(r1); + ASSERT_INT_EQ(40, r0->id); + ASSERT_INT_EQ(20, r1->id); + + // 校验 naked 单链表的物理封底指针是否干净合拢 + ASSERT_TRUE(c_LinkNode_Get(list.head) == r0); // list.head 应该妥妥地挂在 40 节点上 + ASSERT_TRUE(c_LinkNode_Get(list.head->next) == r1); // 40 的下一个由于 10 死了,直接跨越连到了 20 节点 + ASSERT_TRUE(c_LinkNode_Get(list.head->next->next) == NULL); // 20 作为最后一个节点,其 next 指针域必须被强制完美封底为 NULL - // 銷毀資源 c_LinkList_Destroy(&list); - assert(list.head == NULL); - assert(list.size == 0); +} - printf("所有測試成功通過!\n"); - return 0; +int main(void) { + TEST_START(C_NoSentinel_LinkList_System_Tests); + RUN_TEST(test_nosentinel_link_list_and_iterator_flow); + TEST_REPORT(); + RETURN_TEST_STATUS; } \ No newline at end of file diff --git a/Foundation/c_LinkQueue.c b/Foundation/c_LinkQueue.c index 12c130a..7ad425e 100644 --- a/Foundation/c_LinkQueue.c +++ b/Foundation/c_LinkQueue.c @@ -1,129 +1,95 @@ #include -#include -#include "c_Alignment.h" -#include "c_Macros.h" -c_err_t c_LinkQueue_Init(c_LinkQueue_t* self, int obj_size) { - if (!self || obj_size == 0) return C_ERR_PARAM; +// 原地初始化:无哨兵模式,初始化 head 和 tail 全部指向 0 +c_err_t c_LinkQueue_Init(c_LinkQueue_t* self, c_size_t item_size, c_Allocator_t* allocator) { + if (!self || item_size == 0) return C_ERR_PARAM; + + self->allocator = (allocator != NULL) ? *allocator : c_DefaultAllocator; + self->item_size = item_size; + self->size = 0; self->head = NULL; self->tail = NULL; - self->obj_size = (int)obj_size; - self->size = 0; + return C_ERR_OK; } -void c_LinkQueue_Destroy(c_LinkQueue_t* self) { - if (!self) return; +// 入队操作 (基于二级指针的完美 O(1) 极致分支优化) +c_err_t c_LinkQueue_Enqueue(c_LinkQueue_t* self, const void* item) { + if (!self || !item) return C_ERR_PARAM; - c_LinkQueueNode_t* current = self->head; - while (current != NULL) { - c_LinkQueueNode_t* next = current->next; - C_FREE(current); - current = next; - } - self->head = NULL; - self->tail = NULL; - self->size = 0; -} - -c_err_t c_LinkQueue_Push(c_LinkQueue_t* self, void* obj) { - if (!self || !obj) return C_ERR_PARAM; - - // 1. 配置新節點與資料空間 - int size = (int)sizeof(c_LinkQueueNode_t) + self->obj_size; - size = C_ALIGN_UPB(size, C_ALIGN_SIZE); - c_LinkQueueNode_t* new_node = (c_LinkQueueNode_t*)C_ALLOC(size); + // 1. 分配变长节点空间 (控制壳 + 业务数据一体化) + c_size_t total_bytes = sizeof(c_LinkQueueNode_t) + self->item_size; + c_LinkQueueNode_t* new_node = (c_LinkQueueNode_t*)c_Allocator_Alloc(&self->allocator, total_bytes); if (!new_node) return C_ERR_NOMEM; - new_node->data = new_node+1; - // 深複製資料內容 - memcpy(new_node->data, obj, self->obj_size); new_node->next = NULL; + memcpy(QUEUE_NODE_DATA(new_node), item, self->item_size); // 泛型值深度复制 - // 2. 將新節點追加到串列尾端 - if (self->tail == NULL) { - // 佇列原本為空 - self->head = new_node; - self->tail = new_node; - } else { - // 佇列不為空,讓原本尾端的 next 指向新節點,並更新 tail - self->tail->next = new_node; - self->tail = new_node; - } + // 2. 【二级指针艺术】:消灭空队列插入的分支 + // 如果队列为空,新节点应该挂在 head 上;如果不为空,新节点应该挂在 tail->next 上 + c_LinkQueueNode_t** pp = (self->head == NULL) ? &(self->head) : &(self->tail->next); + // 一行代码,完美完成旧拓扑到新节点的挂接 + *pp = new_node; + + // 3. 将尾指针直接移到最新插入的节点上,自愈性推进 + self->tail = new_node; self->size++; + return C_ERR_OK; } -c_err_t c_LinkQueue_Pop(c_LinkQueue_t* self, void* obj) { - if (!self ) return C_ERR_PARAM; - if (self->size == 0 || !self->head) return C_ERR_EMPTY; +// 出队操作 (O(1) 性能,完美防御下溢) +c_err_t c_LinkQueue_Dequeue(c_LinkQueue_t* self, void* out_item) { + if (!self || self->size == 0 || !self->head) return C_ERR_OUTOFBOUND; - c_LinkQueueNode_t* to_delete = self->head; + // 锁定队头即将被剔除解体的物理节点 + c_LinkQueueNode_t* node_to_free = self->head; - // 1. 複製資料到使用者緩衝區 - if (obj) { - memcpy(obj, to_delete->data, self->obj_size); + // 如果用户需要拷出快照副本,执行深度拷贝 + if (out_item) { + memcpy(out_item, QUEUE_NODE_DATA(node_to_free), self->item_size); } - // 2. 將 head 移至下一個節點 - self->head = to_delete->next; + // 队头指针向后大步滑进一格 + self->head = node_to_free->next; + // 边界特殊维护:如果出队后队列彻底被掏空了,尾指针 tail 必须安全地缩回 NULL if (self->head == NULL) { self->tail = NULL; } - // 3. 釋放斷開的節點資源 - C_FREE(to_delete); - + // 闭环退还包装内存壳 + c_Allocator_Free(&self->allocator, node_to_free); self->size--; + return C_ERR_OK; } -c_err_t c_LinkQueue_Peek(c_LinkQueue_t* self, void* obj) { - if (!self ) return C_ERR_PARAM; - if (self->size == 0 || !self->head) return C_ERR_EMPTY; - - // 複製最前端的資料內容 - if (obj) { - memcpy(obj, self->head->data, self->obj_size); - } - return C_ERR_OK; +// 查看队头元素 (只读原位窥探,零拷贝损耗) +void* c_LinkQueue_Peek(const c_LinkQueue_t* self) { + if (!self || self->size == 0 || !self->head) return NULL; + return QUEUE_NODE_DATA(self->head); } -void c_LinkQueueIter_Remove(c_LinkQueueIter_t* self) { - if (!self || !self->queue || !self->node || !*(self->node)) return; +// 高效清空队列 +void c_LinkQueue_Clear(c_LinkQueue_t* self) { + if (!self) return; - c_LinkQueueNode_t* to_delete = *(self->node); - c_LinkQueue_t* q = self->queue; - - // 檢查目前要刪除的是否為尾端節點 - const c_bool_t is_tail = (to_delete == q->tail); - - // 讓上一個節點的 next(或 head)直接指向下一個節點,將 to_delete 從串列中斷開 - *(self->node) = to_delete->next; - - // 如果刪除的是尾端節點,必須更新 tail 指標 - if (is_tail) { - if (q->head == NULL) { - // 情況 A:刪除後佇列完全空了 - q->tail = NULL; - } else { - // 情況 B:刪除的是尾巴,但前方還有元素。 - // 沿著 head 重新走訪一遍,找出現在最尾端的節點(即 next 為 NULL 的節點) - c_LinkQueueNode_t* curr = q->head; - while (curr->next != NULL) { - curr = curr->next; - } - q->tail = curr; // 更新新的尾端 - } + c_LinkQueueNode_t* curr = self->head; + while (curr) { + c_LinkQueueNode_t* next_to_free = curr->next; + c_Allocator_Free(&self->allocator, curr); + curr = next_to_free; } - // 釋放記憶體資源 - C_FREE(to_delete); + self->head = NULL; + self->tail = NULL; + self->size = 0; +} - // 同步遞減佇列大小 - q->size--; - - // 此時 self->node 已自動留在原本的下一個節點上,呼叫端可直接繼續 Get() 或 Next() -} \ No newline at end of file +// 彻底销毁 +void c_LinkQueue_Destroy(c_LinkQueue_t* self) { + if (!self) return; + c_LinkQueue_Clear(self); +} diff --git a/Foundation/c_LinkQueue.h b/Foundation/c_LinkQueue.h index e274790..e4849af 100644 --- a/Foundation/c_LinkQueue.h +++ b/Foundation/c_LinkQueue.h @@ -5,66 +5,63 @@ #include #endif /*INCLUDED_C_TYPES_H*/ +#ifndef INCLUDED_C_ALLOCATOR_H +#include +#endif /*INCLUDED_C_ALLOCATOR_H*/ + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +#define QUEUE_NODE_DATA(node) ((void*)((char*)(node) + sizeof(c_LinkQueueNode_t))) + /* ------------------------------------------------------------------------------------------------------------------ */ /* */ typedef struct c_LinkQueueNode_t { - void* data; - struct c_LinkQueueNode_t * next; -}c_LinkQueueNode_t; + struct c_LinkQueueNode_t* next; // 后驱节点指针 + // 后面会紧跟一整块大小为 item_size 的物理连续内存直接存放真实数据值 +} c_LinkQueueNode_t; +// 终极闭环泛型链式队列控制头(无哨兵极致架构) typedef struct { - c_LinkQueueNode_t* head; - c_LinkQueueNode_t* tail; - int obj_size; - c_size_t size; -}c_LinkQueue_t; - -typedef struct { - c_LinkQueue_t* queue; - c_LinkQueueNode_t** node; -}c_LinkQueueIter_t; + c_LinkQueueNode_t* head; // 指向真实的队头节点(出队端) + c_LinkQueueNode_t* tail; // 指向真实的队尾节点(入队端) + c_size_t item_size; // 单个元素的字节大小 + c_size_t size; // 当前队列中持有的有效元素个数(O(1) 计数) + c_Allocator_t allocator; // 内部绑定的自主内存管理器 +} c_LinkQueue_t; /* ------------------------------------------------------------------------------------------------------------------ */ /* */ -c_err_t c_LinkQueue_Init(c_LinkQueue_t* self, int obj_size); - -void c_LinkQueue_Destroy(c_LinkQueue_t* self); - -c_err_t c_LinkQueue_Push(c_LinkQueue_t* self, void* obj); - -c_err_t c_LinkQueue_Pop(c_LinkQueue_t* self, void* obj); - -c_err_t c_LinkQueue_Peek(c_LinkQueue_t* self, void* obj); - C_STATIC_FORCE_INLINE -void c_LinkQueueIter_Init(c_LinkQueueIter_t* self, c_LinkQueue_t* queue) { - if (!self || !queue) return; - self->queue = queue; - self->node = &queue->head; +void* c_LinkQueueNode_Get(const c_LinkQueueNode_t* self) { + if (!self) return NULL; + return QUEUE_NODE_DATA(self); +} + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +c_err_t c_LinkQueue_Init(c_LinkQueue_t* self, c_size_t item_size, c_Allocator_t* allocator); +void c_LinkQueue_Destroy(c_LinkQueue_t* self); + +// 核心链式队列操作 API (安全值复制模式) +c_err_t c_LinkQueue_Enqueue(c_LinkQueue_t* self, const void* item); +c_err_t c_LinkQueue_Dequeue(c_LinkQueue_t* self, void* out_item); +void* c_LinkQueue_Peek(const c_LinkQueue_t* self); +void c_LinkQueue_Clear(c_LinkQueue_t* self); + +// 内联高频辅助接口 +C_STATIC_FORCE_INLINE +c_size_t c_LinkQueue_Size(const c_LinkQueue_t* self) { + if (!self) return 0; + return self->size; // O(1) 实时读取 } C_STATIC_FORCE_INLINE -c_bool_t c_LinkQueueIter_HasNext(c_LinkQueueIter_t* self) { - if (!self) return C_FALSE; - return (self->node != NULL) && (*(self->node) != NULL); +bool c_LinkQueue_IsEmpty(const c_LinkQueue_t* self) { + return c_LinkQueue_Size(self) == 0; } -C_STATIC_FORCE_INLINE -void* c_LinkQueueIter_Next(c_LinkQueueIter_t* self) { - if (!self || !self->node || !*(self->node)) return NULL; - void* data = (*(self->node))->data; - self->node = &(*(self->node))->next; - return data; -} - -C_STATIC_FORCE_INLINE -void* c_LinkQueueIter_Get(c_LinkQueueIter_t* self) { - if (!self || !self->node || !*(self->node)) return NULL; - return (*(self->node))->data; -} - -void c_LinkQueueIter_Remove(c_LinkQueueIter_t* self); - #endif /*INCLUDED_C_LINKQUEUE_H*/ diff --git a/Foundation/c_LinkQueue.t.c b/Foundation/c_LinkQueue.t.c index 52f95ce..5ce8061 100644 --- a/Foundation/c_LinkQueue.t.c +++ b/Foundation/c_LinkQueue.t.c @@ -1,201 +1,84 @@ #include "c_LinkQueue.h" -#include -#include -#include +#include "c_Test.h" +// 专门用于测试测试的值复制结构体 typedef struct { - char text[16]; - int id; -} Message_t; - -void test_log(const char* test_name) { - printf("[PASS] %s\n", test_name); -} - -typedef struct { - char* data_str; - int id; -} DataPacket_t; - -static void test_iter(void) { - printf("==================================================\n"); - printf(" 開始執行 c_LinkQueueIter_Remove 單元測試\n"); - printf("==================================================\n\n"); + int log_level; + uint32_t timestamp; +} LogMessage_t; +TEST_CASE(test_link_queue_closure_and_memory_layout) { c_LinkQueue_t queue; - c_LinkQueue_Init(&queue, sizeof(DataPacket_t)); - DataPacket_t p1 = {"PacketA", 101}; - DataPacket_t p2 = {"PacketB", 102}; - DataPacket_t p3 = {"PacketC", 103}; + // 初始化一个专门存放 LogMessage_t 结构的泛型单向链式队列 + ASSERT_INT_EQ(C_ERR_OK, c_LinkQueue_Init(&queue, sizeof(LogMessage_t), NULL)); + ASSERT_TRUE(c_LinkQueue_IsEmpty(&queue)); + ASSERT_TRUE(queue.head == NULL); + ASSERT_TRUE(queue.tail == NULL); - // 推入三筆資料 (FIFO 順序: head -> p1 -> p2 -> p3 <- tail) - c_LinkQueue_Push(&queue, &p1); - c_LinkQueue_Push(&queue, &p2); - c_LinkQueue_Push(&queue, &p3); - assert(queue.size == 3); - assert(((DataPacket_t*)queue.tail->data)->id == 103); // 確任目前尾端是 p3 + LogMessage_t msg1 = { .log_level = 1, .timestamp = 11111 }; + LogMessage_t msg2 = { .log_level = 2, .timestamp = 22222 }; + LogMessage_t msg3 = { .log_level = 3, .timestamp = 33333 }; - c_LinkQueueIter_t iter; + // 1. 验证入队操作与二级指针空安全合并能力 + ASSERT_INT_EQ(C_ERR_OK, c_LinkQueue_Enqueue(&queue, &msg1)); // 第一次插入:head == tail == msg1 + ASSERT_PTR_NOT_NULL(queue.head); + ASSERT_TRUE(queue.head == queue.tail); - // ========================================== - // 測試 1:刪除中間節點 (p2: 102) - // ========================================== - c_LinkQueueIter_Init(&iter, &queue); - while (c_LinkQueueIter_HasNext(&iter)) { - DataPacket_t* pkt = (DataPacket_t*)c_LinkQueueIter_Get(&iter); - if (pkt->id == 102) { - c_LinkQueueIter_Remove(&iter); // 刪除 PacketB - printf("[PASS] 成功刪除中間節點 (102)\n"); - } else { - c_LinkQueueIter_Next(&iter); - } - } - assert(queue.size == 2); - assert(((DataPacket_t*)queue.tail->data)->id == 103); // 尾端應維持 103 + ASSERT_INT_EQ(C_ERR_OK, c_LinkQueue_Enqueue(&queue, &msg2)); // 正常挂接:head->msg1, tail->msg2 + ASSERT_INT_EQ(C_ERR_OK, c_LinkQueue_Enqueue(&queue, &msg3)); // 正常挂接:head->msg1, tail->msg3 - // ========================================== - // 測試 2:刪除尾端節點 (p3: 103) -> 測試 tail 更新 - // ========================================== - c_LinkQueueIter_Init(&iter, &queue); - while (c_LinkQueueIter_HasNext(&iter)) { - DataPacket_t* pkt = (DataPacket_t*)c_LinkQueueIter_Get(&iter); - if (pkt->id == 103) { - c_LinkQueueIter_Remove(&iter); // 刪除 PacketC (當前的尾端) - printf("[PASS] 成功刪除尾端節點 (103)\n"); - } else { - c_LinkQueueIter_Next(&iter); - } - } - assert(queue.size == 1); - // 關鍵斷言:刪除原本的尾端 103 後,queue->tail 必須自動往前更新為 101 (PacketA) - assert(queue.tail != NULL); - assert(((DataPacket_t*)queue.tail->data)->id == 101); - assert(queue.head == queue.tail); // 只剩一個元素時,head 應等於 tail + ASSERT_INT_EQ(3, c_LinkQueue_Size(&queue)); - // ========================================== - // 3. 測試 3:刪除最後一個節點 (p1: 101) -> 測試佇列歸零 - // ========================================== - c_LinkQueueIter_Init(&iter, &queue); - assert(c_LinkQueueIter_HasNext(&iter) == C_TRUE); - c_LinkQueueIter_Remove(&iter); // 刪除僅存的 PacketA - printf("[PASS] 成功刪除最後一個節點 (101)\n"); + // 强隔离隔离性检查:修改临时外部变量,内部数据不应被污染 + msg1.log_level = 999; - assert(queue.size == 0); - assert(queue.head == NULL); - assert(queue.tail == NULL); // 關鍵斷言:完全空了之後 tail 必須回歸 NULL - assert(c_LinkQueueIter_HasNext(&iter) == C_FALSE); + // 2. 验证 Peek 窥探能力 + LogMessage_t* peeked = (LogMessage_t*)c_LinkQueue_Peek(&queue); + ASSERT_PTR_NOT_NULL(peeked); + ASSERT_INT_EQ(1, peeked->log_level); // 依旧是 1,证明值复制强屏障有效 + + // 3. 【严苛验证变长内存布局的拓扑对齐情况】 + // 根据变长公式寻址:QUEUE_NODE_DATA(node) 必须与抛出的数据指针完全吻合 + ASSERT_TRUE(c_LinkQueueNode_Get(queue.head) == peeked); + + // 队尾节点的寻址验证 + LogMessage_t* tail_data = c_LinkQueueNode_Get(queue.tail); + ASSERT_INT_EQ(3, tail_data->log_level); + + // 4. 出队顺序与先进先出(FIFO)及边界收缩断言 (Dequeue) + LogMessage_t out_res; + + ASSERT_INT_EQ(C_ERR_OK, c_LinkQueue_Dequeue(&queue, &out_res)); + ASSERT_INT_EQ(1, out_res.log_level); + ASSERT_INT_EQ(11111, out_res.timestamp); + + ASSERT_INT_EQ(C_ERR_OK, c_LinkQueue_Dequeue(&queue, &out_res)); + ASSERT_INT_EQ(2, out_res.log_level); + + // 此时队列只剩最后一个元素 msg3,head 应当等同于 tail + ASSERT_TRUE(queue.head == queue.tail); + ASSERT_INT_EQ(1, c_LinkQueue_Size(&queue)); + + // 最后一个元素出队,迫使尾指针恢复到你指定的 0 纯净空空空状态 + ASSERT_INT_EQ(C_ERR_OK, c_LinkQueue_Dequeue(&queue, &out_res)); + ASSERT_INT_EQ(3, out_res.log_level); + + // 终极下溢复位检查 + ASSERT_TRUE(c_LinkQueue_IsEmpty(&queue)); + ASSERT_TRUE(queue.head == NULL); + ASSERT_TRUE(queue.tail == NULL); + + // 防御重复下溢出队,应当报错拒绝 + ASSERT_INT_EQ(C_ERR_OUTOFBOUND, c_LinkQueue_Dequeue(&queue, &out_res)); - // 清理資源 c_LinkQueue_Destroy(&queue); - printf("\n==================================================\n"); - printf(" 恭喜!c_LinkQueueIter_Remove 所有特例驗證全數通過!\n"); - printf("==================================================\n"); } -int main() { - printf("==================================================\n"); - printf(" 開始執行 c_LinkQueue 完整版測試用例\n"); - printf("==================================================\n\n"); +int main(void) { + TEST_START(C_LinkQueue_Generic_Layout_Tests); + RUN_TEST(test_link_queue_closure_and_memory_layout); + TEST_REPORT(); + RETURN_TEST_STATUS; +} - // ========================================== - // 1. 測試初始化 - // ========================================== - c_LinkQueue_t q; - c_err_t err = c_LinkQueue_Init(&q, sizeof(Message_t)); - assert(err == C_ERR_OK); - assert(q.size == 0); - assert(q.head == NULL); - test_log("1. 鏈結佇列初始化成功"); - - // ========================================== - // 2. 測試資料推入 (Push) - // ========================================== - Message_t msg1 = {"MsgA", 101}; - Message_t msg2 = {"MsgB", 102}; - Message_t msg3 = {"MsgC", 103}; - - err = c_LinkQueue_Push(&q, &msg1); assert(err == C_ERR_OK); - err = c_LinkQueue_Push(&q, &msg2); assert(err == C_ERR_OK); - err = q.size == 2; - err = c_LinkQueue_Push(&q, &msg3); assert(err == C_ERR_OK); - assert(q.size == 3); - test_log("2. 三筆資料成功推入佇列 (尾端追加)"); - - // ========================================== - // 3. 測試迭代器走訪 (應符合 Push 的先進順序:A -> B -> C) - // ========================================== - c_LinkQueueIter_t iter; - c_LinkQueueIter_Init(&iter, &q); - - int check_idx = 0; - while (c_LinkQueueIter_HasNext(&iter)) { - Message_t* m = (Message_t*)c_LinkQueueIter_Next(&iter); - if (check_idx == 0) assert(strcmp(m->text, "MsgA") == 0); - if (check_idx == 1) assert(strcmp(m->text, "MsgB") == 0); - if (check_idx == 2) assert(strcmp(m->text, "MsgC") == 0); - check_idx++; - } - assert(check_idx == 3); - test_log("3. 迭代器順序走訪驗證成功 (符合 FIFO 順序)"); - - // ========================================== - // 4. 測試查看最前端元素 (Peek) - // ========================================== - Message_t local_buf; - err = c_LinkQueue_Peek(&q, &local_buf); - assert(err == C_ERR_OK); - assert(strcmp(local_buf.text, "MsgA") == 0); - assert(local_buf.id == 101); - assert(q.size == 3); // 驗證 Peek 不會減少佇列大小 - test_log("4. 隨機查看最前端元素 (Peek) 成功"); - - // ========================================== - // 5. 測試先進先出彈出 (Pop) - // ========================================== - // 第一次 Pop:預期拿到最先進入的 MsgA - err = c_LinkQueue_Pop(&q, &local_buf); - assert(err == C_ERR_OK); - assert(strcmp(local_buf.text, "MsgA") == 0); - assert(q.size == 2); - - // 彈出後再次 Peek,最前端應該變成 MsgB - err = c_LinkQueue_Peek(&q, &local_buf); - assert(err == C_ERR_OK); - assert(strcmp(local_buf.text, "MsgB") == 0); - - // 第二次與第三次 Pop - err = c_LinkQueue_Pop(&q, &local_buf); assert(err == C_ERR_OK); // 彈出 MsgB - err = c_LinkQueue_Pop(&q, &local_buf); assert(err == C_ERR_OK); // 彈出 MsgC - assert(q.size == 0); - - // 空佇列彈出與查看測試,預期回傳越界錯誤 - err = c_LinkQueue_Pop(&q, &local_buf); - assert(err == C_ERR_EMPTY); - err = c_LinkQueue_Peek(&q, &local_buf); - assert(err == C_ERR_EMPTY); - test_log("5. 彈出 (Pop) 邏輯與空佇列防呆驗證成功"); - - // ========================================== - // 6. 參數安全檢查 - // ========================================== - assert(c_LinkQueue_Init(NULL, sizeof(Message_t)) == C_ERR_PARAM); - assert(c_LinkQueue_Push(NULL, &msg1) == C_ERR_PARAM); - // assert(c_LinkQueue_Pop(&q, NULL) == C_ERR_PARAM); - test_log("6. 介面 NULL 指標防呆驗證成功"); - - // ========================================== - // 7. 銷毀佇列 - // ========================================== - c_LinkQueue_Destroy(&q); - assert(q.head == NULL); - assert(q.size == 0); - test_log("7. 佇列銷毀與記憶體釋放成功"); - - printf("\n==================================================\n"); - printf(" 恭喜!所有 c_LinkQueue 測試皆順利通過!\n"); - printf("==================================================\n"); - - test_iter(); - return 0; -} \ No newline at end of file diff --git a/Foundation/c_LinkStack.c b/Foundation/c_LinkStack.c index c09424e..3fe3e29 100644 --- a/Foundation/c_LinkStack.c +++ b/Foundation/c_LinkStack.c @@ -1,99 +1,85 @@ #include -#include -#include "c_Alignment.h" -#include "c_Macros.h" - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ -c_err_t c_LinkStack_Init(c_LinkStack_t* self, int obj_size) { - if (!self || obj_size <= 0) return C_ERR_PARAM; - self->head = NULL; - self->obj_size = obj_size; +#define STACK_NODE_DATA(node) ((void*)((char*)(node) + sizeof(c_LinkStackNode_t))) + +// 原地初始化:无哨兵模式,初始化栈顶 top 为 0 (NULL) +c_err_t c_LinkStack_Init(c_LinkStack_t* self, c_size_t item_size, c_Allocator_t* allocator) { + if (!self || item_size == 0) return C_ERR_PARAM; + + self->allocator = (allocator != NULL) ? *allocator : c_DefaultAllocator; + self->item_size = item_size; self->size = 0; + self->top = NULL; + return C_ERR_OK; } -// 銷毀堆疊並釋放所有配置的節點與資料記憶體 -void c_LinkStack_Destroy(c_LinkStack_t* self) { - if (!self) return; +// 入栈操作 (完美的真正 O(1) 极致无跳转头插) +c_err_t c_LinkStack_Push(c_LinkStack_t* self, const void* item) { + if (!self || !item) return C_ERR_PARAM; - c_LinkStackNode_t* current = self->head; - while (current != NULL) { - c_LinkStackNode_t* next = current->next; - C_FREE(current); - current = next; - } - self->head = NULL; - self->size = 0; -} - -// 推入元素:採用頭插法實作 O(1) 頂端推入,並深複製資料內容 -c_err_t c_LinkStack_Push(c_LinkStack_t* self, void* obj) { - if (!self || !obj) return C_ERR_PARAM; - int size = sizeof(c_LinkStackNode_t) + self->obj_size; - size = C_ALIGN_UPB(size, C_ALIGN_SIZE); - - c_LinkStackNode_t* new_node = (c_LinkStackNode_t*)C_ALLOC(size); + // 1. 动态分配变长节点空间 (控制壳 + 业务数据一体化) + c_size_t total_bytes = sizeof(c_LinkStackNode_t) + self->item_size; + c_LinkStackNode_t* new_node = (c_LinkStackNode_t*)c_Allocator_Alloc(&self->allocator, total_bytes); if (!new_node) return C_ERR_NOMEM; - new_node->data = new_node+1; - // 值複製 (Value Copy) - memcpy(new_node->data, obj, self->obj_size); + // 2. 泛型值深度复制 + memcpy(STACK_NODE_DATA(new_node), item, self->item_size); - // 頭插法連結 - new_node->next = self->head; - self->head = new_node; + // 3. 无边界头插拓扑串联:新节点咬住当前的 top,再让 top 沦为新节点 + new_node->next = self->top; + self->top = new_node; self->size++; return C_ERR_OK; } -// 彈出頂端元素:將 `head` 的資料值複製給使用者,隨後釋放該前端節點 (O(1)) -c_err_t c_LinkStack_Pop(c_LinkStack_t* self, void* obj) { - if (!self || !obj) return C_ERR_PARAM; - if (self->size == 0 || !self->head) return C_ERR_EMPTY; +// 出栈操作 (O(1) 性能,深度拷贝至外部缓冲区,完美防御下溢) +c_err_t c_LinkStack_Pop(c_LinkStack_t* self, void* out_item) { + if (!self || self->size == 0 || !self->top) return C_ERR_OUTOFBOUND; - c_LinkStackNode_t* to_delete = self->head; + // 锁定即将被弹出解体的栈顶节点 + c_LinkStackNode_t* node_to_free = self->top; - // 將資料複製到呼叫端提供的緩衝區 - memcpy(obj, to_delete->data, self->obj_size); + // 如果外部需要拷出数据快照,执行 memcpy + if (out_item) { + memcpy(out_item, STACK_NODE_DATA(node_to_free), self->item_size); + } - // 斷開頂端節點,head 指向下一個 - self->head = to_delete->next; - - // 釋放資源 - C_FREE(to_delete); + // 栈顶指针顺理成章移向下一个更早入栈的项 + self->top = node_to_free->next; + // 闭环通过内置分配器归还物理块资源 + c_Allocator_Free(&self->allocator, node_to_free); self->size--; + return C_ERR_OK; } -// 查看目前最頂端的元素指標 (O(1),不移除節點) -void* c_LinkStack_Peek(c_LinkStack_t* self) { - if (!self || !self->head || self->size == 0) return NULL; - return self->head->data; +// 查看栈顶元素 (只读原位原位窥探,零拷贝损耗) +void* c_LinkStack_Peek(const c_LinkStack_t* self) { + if (!self || self->size == 0 || !self->top) return NULL; + return STACK_NODE_DATA(self->top); } -void c_LinkStackIter_Remove(c_LinkStackIter_t* self) { - // 防呆檢查:確保迭代器有效、繫結的堆疊存在,且當前指向的節點不為空 - if (!self || !self->stack || !self->node || !*(self->node)) return; +// 高效清空栈内全部节点 +void c_LinkStack_Clear(c_LinkStack_t* self) { + if (!self) return; - c_LinkStackNode_t* to_delete = *(self->node); + c_LinkStackNode_t* curr = self->top; + while (curr) { + c_LinkStackNode_t* next_to_free = curr->next; + c_Allocator_Free(&self->allocator, curr); + curr = next_to_free; + } - // 關鍵指標轉移: - // 將當前結構中維護的指標(可能是前一節點的 next,或是 stack 的 head) - // 修改為指向下一個節點,直接從鏈結串列中斷開該節點 - *(self->node) = to_delete->next; + self->top = NULL; // 还原到你 Init 指定的 0 纯净空空空状态 + self->size = 0; +} - // 釋放節點內深複製的資料空間與節點結構本體 - C_FREE(to_delete); - - // 同步遞減堆疊的總大小 - self->stack->size--; - - // 注意:由於 *(self->node) 已被賦值為 to_delete->next, - // self->node 目前已自動指向了原本的下一個節點。 - // 使用者不需要再手動呼叫 Next(),即可直接對新位置進行 Get()、Next() 或再次 Remove()。 +// 彻底销毁 +void c_LinkStack_Destroy(c_LinkStack_t* self) { + if (!self) return; + c_LinkStack_Clear(self); } diff --git a/Foundation/c_LinkStack.h b/Foundation/c_LinkStack.h index 0364d82..9514466 100644 --- a/Foundation/c_LinkStack.h +++ b/Foundation/c_LinkStack.h @@ -5,60 +5,59 @@ #include #endif /*INCLUDED_C_TYPES_H*/ +#ifndef INCLUDED_C_ALLOCATOR_H +#include +#endif /*INCLUDED_C_ALLOCATOR_H*/ + + /* ------------------------------------------------------------------------------------------------------------------ */ /* */ typedef struct c_LinkStackNode_t { - void* data; - struct c_LinkStackNode_t* next; + struct c_LinkStackNode_t* next; // 指向下一个更早入栈的节点 + // 后面紧跟一整块大小为 item_size 的物理连续内存,直接存放真实数据值 } c_LinkStackNode_t; +// 终极闭环泛型链式栈控制头(无哨兵极致架构) typedef struct { - c_LinkStackNode_t* head; - int obj_size; - c_size_t size; + c_LinkStackNode_t* top; // 指向当前的栈顶节点(即单链表真实的第一个有效元素) + c_size_t item_size; // 单个元素的字节大小 + c_size_t size; // 当前栈内持有的有效元素个数(O(1) 实时读取) + c_Allocator_t allocator; // 内部绑定的自主内存管理器 } c_LinkStack_t; -typedef struct { - c_LinkStack_t* stack; - c_LinkStackNode_t** node; -} c_LinkStackIter_t; +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ -c_err_t c_LinkStack_Init(c_LinkStack_t* self, int obj_size); -void c_LinkStack_Destroy(c_LinkStack_t* self); -c_err_t c_LinkStack_Push(c_LinkStack_t* self, void* obj); -c_err_t c_LinkStack_Pop(c_LinkStack_t* self, void* obj); -void* c_LinkStack_Peek(c_LinkStack_t* self); - -// 迭代器內聯函數實作 C_STATIC_FORCE_INLINE -void c_LinkStackIter_Init(c_LinkStackIter_t* self, c_LinkStack_t* stack) { - if (!self || !stack) return; - self->stack = stack; - self->node = &stack->head; +void* c_LinkStackNode_Get(const c_LinkStackNode_t* self) { + if (!self) return NULL; + return ((void*)((char*)(self) + sizeof(c_LinkStackNode_t))); +} + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +c_err_t c_LinkStack_Init(c_LinkStack_t* self, c_size_t item_size, c_Allocator_t* allocator); +void c_LinkStack_Destroy(c_LinkStack_t* self); + +// 核心链式栈操作 API (安全值复制模式) +c_err_t c_LinkStack_Push(c_LinkStack_t* self, const void* item); +c_err_t c_LinkStack_Pop(c_LinkStack_t* self, void* out_item); +void* c_LinkStack_Peek(const c_LinkStack_t* self); +void c_LinkStack_Clear(c_LinkStack_t* self); + +// 内联高频辅助接口 +C_STATIC_FORCE_INLINE +c_size_t c_LinkStack_Size(const c_LinkStack_t* self) { + if (!self) return 0; + return self->size; // O(1) 实时读取 } C_STATIC_FORCE_INLINE -c_bool_t c_LinkStackIter_HasNext(c_LinkStackIter_t* self) { - if (!self) return C_FALSE; - return (self->node != NULL) && (*(self->node) != NULL); +bool c_LinkStack_IsEmpty(const c_LinkStack_t* self) { + return c_LinkStack_Size(self) == 0; } -C_STATIC_FORCE_INLINE -void* c_LinkStackIter_Next(c_LinkStackIter_t* self) { - if (!self || !self->node || !*(self->node)) return NULL; - void* data = (*(self->node))->data; - self->node = &(*(self->node))->next; - return data; -} - -C_STATIC_FORCE_INLINE -void* c_LinkStackIter_Get(c_LinkStackIter_t* self) { - if (!self || !self->node || !*(self->node)) return NULL; - return (*(self->node))->data; -} - -void c_LinkStackIter_Remove(c_LinkStackIter_t* self); - #endif /*INCLUDED_C_LINKSTACK_H*/ diff --git a/Foundation/c_LinkStack.t.c b/Foundation/c_LinkStack.t.c index 85de8d5..493c7fd 100644 --- a/Foundation/c_LinkStack.t.c +++ b/Foundation/c_LinkStack.t.c @@ -1,118 +1,84 @@ #include "c_LinkStack.h" +#include "c_Test.h" #include #include -#include typedef struct { - char name[16]; - int id; -} Frame_t; + int thread_id; + uint32_t pc_register; +} ThreadContext_t; -void test_log(const char* test_name) { - printf("[PASS] %s\n", test_name); +TEST_CASE(test_link_stack_closure_and_lifo_flow) { + c_LinkStack_t stack; + + // 初始化一个专门存放 ThreadContext_t 结构的泛型单向链式栈 + ASSERT_INT_EQ(C_ERR_OK, c_LinkStack_Init(&stack, sizeof(ThreadContext_t), NULL)); + ASSERT_TRUE(c_LinkStack_IsEmpty(&stack)); + ASSERT_TRUE(stack.top == NULL); + + ThreadContext_t ctx1 = { .thread_id = 10, .pc_register = 0x00A0 }; + ThreadContext_t ctx2 = { .thread_id = 20, .pc_register = 0x00B0 }; + ThreadContext_t ctx3 = { .thread_id = 30, .pc_register = 0x00C0 }; + + // 1. 验证入栈操作 (Push) 与 LIFO 排列 + ASSERT_INT_EQ(C_ERR_OK, c_LinkStack_Push(&stack, &ctx1)); // 第一次插入:top -> ctx1 + ASSERT_PTR_NOT_NULL(stack.top); + ASSERT_TRUE(stack.top->next == NULL); + + ASSERT_INT_EQ(C_ERR_OK, c_LinkStack_Push(&stack, &ctx2)); // 此时排列:top -> ctx2 -> ctx1 + ASSERT_INT_EQ(C_ERR_OK, c_LinkStack_Push(&stack, &ctx3)); // 此时排列:top -> ctx3 -> ctx2 -> ctx1 + + ASSERT_INT_EQ(3, c_LinkStack_Size(&stack)); + + // 强隔离隔离性检查:修改外部临时变量,内部数据必须牢不可破 + ctx3.thread_id = 999; + + // 2. 验证 Peek 窥探能力 + ThreadContext_t* peeked = (ThreadContext_t*)c_LinkStack_Peek(&stack); + ASSERT_PTR_NOT_NULL(peeked); + ASSERT_INT_EQ(30, peeked->thread_id); // 应该依旧是原值 30,证明深度值复制有效 + + // 3. 【严苛验证变长内存布局的拓扑对齐情况】 + // 根据变长公式寻址:STACK_NODE_DATA(node) 必须与抛出的数据指针完全吻合 + ASSERT_TRUE(c_LinkStackNode_Get(stack.top) == peeked); + + // 验证更深一层的 LIFO 相对位置节点: + // top 的下一个应当是 ctx2 对应的控制头,提取其内部用户数据区地址 + ThreadContext_t* second_data = (ThreadContext_t*)c_LinkStackNode_Get(stack.top->next); + ASSERT_INT_EQ(20, second_data->thread_id); + + // 4. 出栈顺序与后进先出(LIFO)及边界复位断言 (Pop) + ThreadContext_t out_res; + + // 弹出第 1 个:应当是最后进来的 ctx3 + ASSERT_INT_EQ(C_ERR_OK, c_LinkStack_Pop(&stack, &out_res)); + ASSERT_INT_EQ(30, out_res.thread_id); + ASSERT_INT_EQ(0, c_LinkStack_IsEmpty(&stack)); + + // 弹出第 2 个:应当是 ctx2 + ASSERT_INT_EQ(C_ERR_OK, c_LinkStack_Pop(&stack, &out_res)); + ASSERT_INT_EQ(20, out_res.thread_id); + + // 弹出第 3 个:应当是最早进来的 ctx1 + ASSERT_INT_EQ(C_ERR_OK, c_LinkStack_Pop(&stack, &out_res)); + ASSERT_INT_EQ(10, out_res.thread_id); + + // 终极下溢与纯净复位检查 + ASSERT_TRUE(c_LinkStack_IsEmpty(&stack)); + ASSERT_TRUE(stack.top == NULL); + ASSERT_INT_EQ(0, c_LinkStack_Size(&stack)); + + // 防御重复下溢出栈,应当优雅报错 + ASSERT_INT_EQ(C_ERR_OUTOFBOUND, c_LinkStack_Pop(&stack, &out_res)); + ASSERT_TRUE(c_LinkStack_Peek(&stack) == NULL); + + c_LinkStack_Destroy(&stack); } -int main() { - printf("==================================================\n"); - printf(" 開始執行 c_LinkStack 完整單元測試用例\n"); - printf("==================================================\n\n"); - - // ========================================== - // 1. 初始化測試 - // ========================================== - c_LinkStack_t s; - c_err_t err = c_LinkStack_Init(&s, sizeof(Frame_t)); - assert(err == C_ERR_OK); - assert(s.size == 0); - assert(s.head == NULL); - test_log("1. 鏈結堆疊初始化狀態驗證成功"); - - // ========================================== - // 2. 資料推入測試 (Push) - // ========================================== - Frame_t f1 = {"MainFrame", 100}; - Frame_t f2 = {"RenderFrame", 200}; - Frame_t f3 = {"UpdateFrame", 300}; - - // 依序推入,預期最新推入的會待在鏈結最前端 (head) - err = c_LinkStack_Push(&s, &f1); assert(err == C_ERR_OK); - err = c_LinkStack_Push(&s, &f2); assert(err == C_ERR_OK); - err = c_LinkStack_Push(&s, &f3); assert(err == C_ERR_OK); - assert(s.size == 3); - test_log("2. 三筆資料成功推入堆疊 (頭插法 O(1))"); - - // ========================================== - // 3. 迭代器走訪測試 (應符合後進先出順序:f3 -> f2 -> f1) - // ========================================== - c_LinkStackIter_t iter; - c_LinkStackIter_Init(&iter, &s); - int check_idx = 0; - while (c_LinkStackIter_HasNext(&iter)) { - Frame_t* f = (Frame_t*)c_LinkStackIter_Next(&iter); - if (check_idx == 0) assert(strcmp(f->name, "UpdateFrame") == 0); - if (check_idx == 1) assert(strcmp(f->name, "RenderFrame") == 0); - if (check_idx == 2) assert(strcmp(f->name, "MainFrame") == 0); - check_idx++; - } - assert(check_idx == 3); - test_log("3. 迭代器走訪順序驗證成功 (符合 LIFO 頂端到探底順序)"); - - // ========================================== - // 4. 查看堆疊頂端 (Peek) - // ========================================== - // 目前最頂端應該依然是最後推進去的 UpdateFrame - Frame_t* p_peek = (Frame_t*)c_LinkStack_Peek(&s); - assert(p_peek != NULL); - assert(strcmp(p_peek->name, "UpdateFrame") == 0); - assert(p_peek->id == 300); - assert(s.size == 3); // 驗證 Peek 不會移除元素 - test_log("4. 唯讀查看堆疊頂端元素 (Peek) 成功"); - - // ========================================== - // 5. 先進後出彈出測試 (Pop) - // ========================================== - Frame_t local_buf; - - // 第一次 Pop:預期取出最上方的 UpdateFrame - err = c_LinkStack_Pop(&s, &local_buf); - assert(err == C_ERR_OK); - assert(strcmp(local_buf.name, "UpdateFrame") == 0); - assert(s.size == 2); - - // 再次 Peek,頂端應更新為 RenderFrame - p_peek = (Frame_t*)c_LinkStack_Peek(&s); - assert(strcmp(p_peek->name, "RenderFrame") == 0); - - // 連續彈出剩下的兩個元素 - err = c_LinkStack_Pop(&s, &local_buf); assert(err == C_ERR_OK); // 取出 RenderFrame - err = c_LinkStack_Pop(&s, &local_buf); assert(err == C_ERR_OK); // 取出 MainFrame - assert(s.size == 0); - assert(s.head == NULL); - - // 空堆疊彈出與查看測試,預期回傳越界錯誤 - err = c_LinkStack_Pop(&s, &local_buf); - assert(err == C_ERR_EMPTY); - assert(c_LinkStack_Peek(&s) == NULL); - test_log("5. 後進先出彈出 (Pop) 邏輯與空防呆驗證成功"); - - // ========================================== - // 6. 介面安全指標檢查 - // ========================================== - assert(c_LinkStack_Init(NULL, sizeof(Frame_t)) == C_ERR_PARAM); - assert(c_LinkStack_Push(NULL, &f1) == C_ERR_PARAM); - assert(c_LinkStack_Pop(&s, NULL) == C_ERR_PARAM); - test_log("6. 介面 NULL 指標防呆驗證成功"); - - // ========================================== - // 7. 銷毀堆疊 (Destroy) - // ========================================== - c_LinkStack_Destroy(&s); - assert(s.head == NULL); - assert(s.size == 0); - test_log("7. 堆疊資源銷毀與記憶體釋放成功"); - - printf("\n==================================================\n"); - printf(" 恭喜!c_LinkStack 優化版單元測試全數順利通過!\n"); - printf("==================================================\n"); - return 0; +int main(void) { + printf("\n"); + TEST_START(C_LinkStack_Generic_Layout_Tests); + RUN_TEST(test_link_stack_closure_and_lifo_flow); + TEST_REPORT(); + RETURN_TEST_STATUS; } \ No newline at end of file diff --git a/Foundation/c_List.c b/Foundation/c_List.c deleted file mode 100644 index 2857b2c..0000000 --- a/Foundation/c_List.c +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/Foundation/c_List.h b/Foundation/c_List.h deleted file mode 100644 index f3c99ed..0000000 --- a/Foundation/c_List.h +++ /dev/null @@ -1,73 +0,0 @@ -#ifndef INCLUDED_C_LIST_H -#define INCLUDED_C_LIST_H - -#ifndef INCLUDED_C_TYPES_H -#include -#endif /*INCLUDED_C_TYPES_H*/ - - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -typedef struct c_ListNode_t { - struct c_ListNode_t* prev; - struct c_ListNode_t* next; -}c_ListNode_t; - -typedef c_ListNode_t c_List_t; - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -#define c_List_Prev(n) (n)->prev -#define c_List_Next(n) (n)->next -#define c_List_PrevNext(n) c_List_Next(c_List_Prev(n)) -#define c_List_NextPrev(n) c_List_Prev(c_List_Next(n)) - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - - -#define c_List_Init(n) do{ \ - c_List_Prev(n) = c_List_Next(n) = (n); \ -}while(0) - -#define c_List_IsEmpty(n) ((c_List_Next(n) == (n)) && (c_List_Prev(n) == (n))) - -#define c_List_InsertBefore(L, N) do { \ - c_List_Next(N) = (L); \ - c_List_Prev(N) = c_List_Prev(L); \ - c_List_PrevNext(N) = (N); \ - c_List_Prev(L) = (N); \ -} while(0) - -#define c_List_InsertAfter(L, N) do { \ - c_List_Prev(N) = (L); \ - c_List_Next(N) = c_List_Next(L); \ - c_List_NextPrev(N) = (N); \ - c_List_Next(L) = (N); \ -} while(0) - -#define c_List_Remove(n) do { \ - c_List_PrevNext(n) = c_List_Next(n); \ - c_List_NextPrev(n) = c_List_Prev(n); \ - c_List_Init(n); \ -} while(0) - -#define c_List_Entry(ptr, type, member) \ - ((type *)((char *)(ptr) - offsetof(type, member))) - -// Standard forward loop: Safe for lookups, UNSAFE for deletions -#define c_List_ForEachEntry(head, pos, type, member) \ - for (pos = c_List_Entry(c_List_Next(head), type, member); \ - &pos->member != (head); \ - pos = c_List_Entry(c_List_Next(&pos->member), type, member)) - -// Safe forward loop: Explicitly safe to call c_List_Remove inside the loop body -#define c_List_ForEachEntrySafe(head, pos, n, type, member) \ - for (pos = c_List_Entry(c_List_Next(head), type, member), \ - n = c_List_Entry(c_List_Next(&pos->member), type, member); \ - &pos->member != (head); \ - pos = n, n = c_List_Entry(c_List_Next(&n->member), type, member)) - -#endif /*INCLUDED_C_LIST_H*/ diff --git a/Foundation/c_List.t.c b/Foundation/c_List.t.c deleted file mode 100644 index 2d86c10..0000000 --- a/Foundation/c_List.t.c +++ /dev/null @@ -1,143 +0,0 @@ -#include "c_List.h" -#include -#include -#include - -// Custom User Type showcasing intrusive inclusion -typedef struct { - int value; - c_ListNode_t node; // Intrusive node payload linkage -} CustomData_t; - -static void test2(void) { - printf("==================================================\n"); - printf(" Starting Intrusive Safe-Iterator Unit Tests\n"); - printf("==================================================\n\n"); - - c_List_t head; - c_List_Init(&head); - - CustomData_t d1 = {10}; - CustomData_t d2 = {20}; - CustomData_t d3 = {30}; - - // Linking nodes to tail: [Head] <-> [10] <-> [20] <-> [30] - c_List_InsertBefore(&head, &d1.node); - c_List_InsertBefore(&head, &d2.node); - c_List_InsertBefore(&head, &d3.node); - - // ========================================== - // 1. Verify Lookups via ForEachEntry - // ========================================== - CustomData_t* pos; - int index = 0; - int expected[] = {10, 20, 30}; - - printf("Reading nodes using standard ForEachEntry:\n"); - c_List_ForEachEntry(&head, pos, CustomData_t, node) { - printf(" Found Entry value: %d\n", pos->value); - assert(pos->value == expected[index++]); - } - assert(index == 3); - printf("[PASS] Standard lookup loop complete.\n\n"); - - // ========================================== - // 2. Verify Mutations via ForEachEntrySafe - // ========================================== - CustomData_t* tmp; // Cache variable for safe traversal tracking - index = 0; - - printf("Filtering and removing matching entry elements via Safe Loop:\n"); - c_List_ForEachEntrySafe(&head, pos, tmp, CustomData_t, node) { - if (pos->value == 20) { - printf(" Modifying layout: Safely dropping element (%d)\n", pos->value); - c_List_Remove(&pos->node); // Remove middle item mid-flight - } - index++; - } - assert(index == 3); // Iterated through all three bounds - - // ========================================== - // 3. Confirm Final Structure Integrity - // ========================================== - // List must now structurally bridge to bypass item 20: [10] <-> [30] - index = 0; - c_List_ForEachEntry(&head, pos, CustomData_t, node) { - if (index == 0) assert(pos->value == 10); - if (index == 1) assert(pos->value == 30); - index++; - } - assert(index == 2); - printf("[PASS] Structural integrity verified following safe removal mutation.\n"); - - printf("\n==================================================\n"); - printf(" Success! Intrusive layout traversal operates flawlessly!\n"); - printf("==================================================\n"); -} - -int main() { - printf("==================================================\n"); - printf(" Starting Intrusive Circular Doubly Linked List Tests\n"); - printf("==================================================\n\n"); - - // Initialize list head context anchor - c_List_t head; - c_List_Init(&head); - assert(c_List_IsEmpty(&head) == 1); - - CustomData_t d1 = {100}; - CustomData_t d2 = {200}; - CustomData_t d3 = {300}; - - // ========================================== - // 1. Insertion Testing - // ========================================== - // Insert d1 after head -> List: [Head] <-> [100] - c_List_InsertAfter(&head, &d1.node); - assert(c_List_IsEmpty(&head) == 0); - - // Insert d3 before head -> List: [Head] <-> [100] <-> [300] - c_List_InsertBefore(&head, &d3.node); - - // Insert d2 after d1 -> List: [Head] <-> [100] <-> [200] <-> [300] - c_List_InsertAfter(&d1.node, &d2.node); - - printf("[PASS] Sequence insertions complete.\n"); - - // ========================================== - // 2. Linear Traversal Verification - // ========================================== - c_ListNode_t* curr = c_List_Next(&head); - int expected_values[] = {100, 200, 300}; - int idx = 0; - - while (curr != &head) { - CustomData_t* entry = c_List_Entry(curr, CustomData_t, node); - assert(entry->value == expected_values[idx]); - curr = c_List_Next(curr); - idx++; - } - assert(idx == 3); - printf("[PASS] Intrusive forward iterator matching sequential expectations.\n"); - - // ========================================== - // 3. Deletion and Mutation Verification - // ========================================== - // Target and drop middle node (200) - c_List_Remove(&d2.node); - - // Structure must bridge gaps smoothly: [100] <-> [300] - assert(c_List_Next(&d1.node) == &d3.node); - assert(c_List_Prev(&d3.node) == &d1.node); - - // Eliminated isolated node must be self-referencing via macro assignment - assert(c_List_IsEmpty(&d2.node) == 1); - printf("[PASS] Drop operation and isolated reference initialization verified.\n"); - - printf("\n==================================================\n"); - printf(" Success! Intrusive macro mutations match layout specs!\n"); - printf("==================================================\n"); - - test2(); - return 0; -} \ No newline at end of file diff --git a/Foundation/c_LockQueue.c b/Foundation/c_LockQueue.c deleted file mode 100644 index 90ab27e..0000000 --- a/Foundation/c_LockQueue.c +++ /dev/null @@ -1,324 +0,0 @@ -#include - -#if defined(PLATFORM_POSIX) -#include -#endif - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -c_err_t c_LockQueue_Init(c_LockQueue_t* queue, c_size_t capacity) { - if (!queue || capacity==0) return C_ERR_PARAM; - queue->data = (void**)malloc(sizeof(void*) * capacity); - if (!queue->data) { - return C_ERR_NOMEM; - } - queue->capacity = capacity; - queue->write_idx = 0; - queue->read_idx = 0; - queue->size = 0; - queue->is_shutdown = C_FALSE; - - if ((c_Mutex_Init(&queue->lock)!=C_ERR_OK) || - (c_Cond_Init(&queue->not_full)!=C_ERR_OK) || - (c_Cond_Init(&queue->not_empty)!=C_ERR_OK)) - { - if (queue->data) { - free(queue->data); - queue->data = NULL; - } - } - return C_ERR_OK; -} -void c_LockQueue_Destroy(c_LockQueue_t* queue) { - if (!queue) return; - - c_LockQueue_Shutdown(queue); - - c_Mutex_Lock(&queue->lock); - c_Cond_Destroy(&queue->not_full); - c_Cond_Destroy(&queue->not_empty); - if (queue->data) { - free(queue->data); - queue->data = NULL; - } - c_Mutex_UnLock(&queue->lock); - - // 销毁跨平台锁 - c_Mutex_Destroy(&queue->lock); -} - -void c_LockQueue_Shutdown(c_LockQueue_t* queue) { - if (!queue) return; - - c_Mutex_Lock(&queue->lock); - queue->is_shutdown = C_TRUE; - - // 广播唤醒所有正在阻塞的生产者和消费者,让他们通过 is_shutdown 状态感知并安全退出 - c_Cond_Broadcast(&queue->not_full); - c_Cond_Broadcast(&queue->not_empty); - c_Mutex_UnLock(&queue->lock); -} - -c_err_t c_LockQueue_Push(c_LockQueue_t* queue, void* data) { - if (!queue) return C_ERR_PARAM; - - c_Mutex_Lock(&queue->lock); - - // 1. 经典工业级设计:使用 while 循环检查条件,完美防御虚假唤醒 - while (queue->size == queue->capacity && !queue->is_shutdown) { - c_Cond_Wait(&queue->not_full, &queue->lock); - } - - // 2. 如果队列中途被关闭,直接拒绝写入并返回 - if (queue->is_shutdown) { - c_Mutex_UnLock(&queue->lock); - return C_ERR_FAIL; - } - - // 3. 循环数组插入数据 - queue->data[queue->write_idx] = data; - queue->write_idx = (queue->write_idx + 1) % queue->capacity; - queue->size++; - - // 4. 唤醒可能正在等待数据的消费者 - c_Cond_Signal(&queue->not_empty); - - c_Mutex_UnLock(&queue->lock); - return C_ERR_OK; -} - -c_err_t c_LockQueue_Pop(c_LockQueue_t* queue, void** item) { - if (!queue ) return C_ERR_PARAM; - - c_Mutex_Lock(&queue->lock); - - // 1. 队空且未关闭时,消费者阻塞等待 - while (queue->size == 0 && !queue->is_shutdown) { - c_Cond_Wait(&queue->not_empty, &queue->lock); - } - - // 2. 如果队列已关闭且数据已被清空,优雅退出 - if (queue->is_shutdown && queue->size == 0) { - c_Mutex_UnLock(&queue->lock); - return C_ERR_FAIL; - } - - // 3. 循环数组取出数据 - if (item) { - *item = queue->data[queue->read_idx]; - } - queue->read_idx = (queue->read_idx + 1) % queue->capacity; - queue->size--; - - // 4. 唤醒可能正在等待空间的生产者 - c_Cond_Signal(&queue->not_full); - - c_Mutex_UnLock(&queue->lock); - return C_ERR_OK; -} - -c_size_t c_LockQueue_Size(c_LockQueue_t* queue) { - if (!queue) return 0; - c_Mutex_Lock(&queue->lock); - const c_size_t size = queue->size; - c_Mutex_UnLock(&queue->lock); - return size; -} - -c_bool_t c_LockQueue_IsEmpty(c_LockQueue_t* queue) { - if (!queue) return true; // 安全檢查:無效隊列視為空 - - c_Mutex_Lock(&queue->lock); - const c_bool_t is_empty = (queue->size == 0); - c_Mutex_UnLock(&queue->lock); - - return is_empty; -} - -c_bool_t c_LockQueue_IsFull(c_LockQueue_t* queue) { - if (!queue) return false; // 安全檢查 - - c_Mutex_Lock(&queue->lock); - const c_bool_t is_full = (queue->size == queue->capacity); - c_Mutex_UnLock(&queue->lock); - return is_full; -} - - -c_bool_t c_LockQueue_TimedPop(c_LockQueue_t* queue, void** item, c_uint_t timeout_ms) { - if (!queue || !item) return C_FALSE; - - c_Mutex_Lock(&queue->lock); - - // 1. Calculate the absolute deadline for POSIX or track elapsed time for Windows - c_uint_t remaining_ms = timeout_ms; - -#if defined(PLATFORM_POSIX) - // POSIX timedwait requires an absolute system calendar time deadline - struct timespec deadline; - struct timeval now; - gettimeofday(&now, NULL); - long long total_ns = (long long)now.tv_usec * 1000 + (long long)timeout_ms * 1000000; - deadline.tv_sec = now.tv_sec + total_ns / 1000000000LL; - deadline.tv_nsec = total_ns % 1000000000LL; -#elif defined(PLATFORM_WINDOWS) - // Windows tracks relative intervals natively via GetTickCount/GetTickCount64 - ULONGLONG start_tick = GetTickCount64(); -#endif - - // 2. Loop to defend against Spurious Wakeups - while (queue->size == 0 && !queue->is_shutdown) { - if (remaining_ms == 0) { - // Out of time before cond wait or remaining time became zero - c_Mutex_UnLock(&queue->lock); - return C_FALSE; - } - - // 3. Atomically release the lock and sleep until signaled or timed out -#if defined(PLATFORM_WINDOWS) - // SleepConditionVariableCS handles relative timeout natively - BOOL wait_success = SleepConditionVariableCS(&queue->not_empty.handle, &queue->lock.handle, remaining_ms); - - if (!wait_success) { - if (GetLastError() == ERROR_TIMEOUT) { - c_Mutex_UnLock(&queue->lock); - return C_FALSE; // Dynamic Windows timeout hit - } - } - - // Recalculate remaining time in case of spurious wakeups - ULONGLONG elapsed = GetTickCount64() - start_tick; - if (elapsed >= timeout_ms) { - remaining_ms = 0; - } else { - remaining_ms = timeout_ms - (c_uint_t)elapsed; - } -#elif defined(PLATFORM_POSIX) - // pthread_cond_timedwait takes the exact calculated deadline - int wait_result = pthread_cond_timedwait(&queue->not_empty.handle, &queue->lock.handle, &deadline); - - if (wait_result != 0) { - // POSIX returns ETIMEDOUT (usually 110) if time limit expires - c_Mutex_UnLock(&queue->lock); - return C_FALSE; - } - - // Re-verify remaining time using current clock just to be precise - gettimeofday(&now, NULL); - long long current_ms = (long long)now.tv_sec * 1000 + now.tv_usec / 1000; - long long deadline_ms = (long long)deadline.tv_sec * 1000 + deadline.tv_nsec / 1000000; - if (current_ms >= deadline_ms) { - remaining_ms = 0; - } else { - remaining_ms = (c_uint_t)(deadline_ms - current_ms); - } -#endif - } - - // 4. Handle exit criteria if queue shut down during wait - if (queue->is_shutdown && queue->size == 0) { - c_Mutex_UnLock(&queue->lock); - return C_FALSE; - } - - // 5. Securely pop data from circular buffer - *item = queue->data[queue->read_idx]; - queue->read_idx = (queue->read_idx + 1) % queue->capacity; - queue->size--; - - // 6. Signal blocked producers that space has cleared up - c_Cond_Signal(&queue->not_full); - - c_Mutex_UnLock(&queue->lock); - return C_TRUE; -} - -c_bool_t c_LockQueue_TimedPush(c_LockQueue_t* queue, void* item, c_uint_t timeout_ms) { - if (!queue || !item) return C_FALSE; - - c_Mutex_Lock(&queue->lock); - - // 1. Calculate the absolute deadline for POSIX or track elapsed time for Windows - c_uint_t remaining_ms = timeout_ms; - -#if defined(PLATFORM_POSIX) - // POSIX timedwait requires an absolute wall-clock calendar deadline - struct timespec deadline; - struct timeval now; - gettimeofday(&now, NULL); - long long total_ns = (long long)now.tv_usec * 1000 + (long long)timeout_ms * 1000000; - deadline.tv_sec = now.tv_sec + total_ns / 1000000000LL; - deadline.tv_nsec = total_ns % 1000000000LL; -#elif defined(PLATFORM_WINDOWS) - // Windows tracks relative intervals natively via clock ticks - ULONGLONG start_tick = GetTickCount64(); -#endif - - // 2. Loop to defend against Spurious Wakeups while the queue is full - while (queue->size == queue->capacity && !queue->is_shutdown) { - if (remaining_ms == 0) { - // Out of time before cond wait or remaining time ticked down to zero - c_Mutex_UnLock(&queue->lock); - return C_FALSE; - } - - // 3. Atomically release the lock and sleep until signaled or timed out -#if defined(PLATFORM_WINDOWS) - // SleepConditionVariableCS handles relative timeout natively - BOOL wait_success = SleepConditionVariableCS(&queue->not_full.handle, &queue->lock.handle, remaining_ms); - - if (!wait_success) { - if (GetLastError() == ERROR_TIMEOUT) { - c_Mutex_UnLock(&queue->lock); - return C_FALSE; // Dynamic Windows timeout expired - } - } - - // Recalculate remaining time in case of a spurious wakeup - ULONGLONG elapsed = GetTickCount64() - start_tick; - if (elapsed >= timeout_ms) { - remaining_ms = 0; - } else { - remaining_ms = timeout_ms - (c_uint_t)elapsed; - } -#elif defined(PLATFORM_POSIX) - // pthread_cond_timedwait takes the absolute calculated deadline - int wait_result = pthread_cond_timedwait(&queue->not_full.handle, &queue->lock.handle, &deadline); - - if (wait_result != 0) { - // POSIX returns ETIMEDOUT (110) if time limit expires - c_Mutex_UnLock(&queue->lock); - return C_FALSE; - } - - // Re-verify remaining time using current clock to stay precise - gettimeofday(&now, NULL); - long long current_ms = (long long)now.tv_sec * 1000 + now.tv_usec / 1000; - long long deadline_ms = (long long)deadline.tv_sec * 1000 + deadline.tv_nsec / 1000000; - if (current_ms >= deadline_ms) { - remaining_ms = 0; - } else { - remaining_ms = (c_uint_t)(deadline_ms - current_ms); - } -#endif - } - - // 4. Handle exit criteria if queue shut down during wait - if (queue->is_shutdown) { - c_Mutex_UnLock(&queue->lock); - return C_FALSE; - } - - // 5. Securely push data into the circular buffer - queue->data[queue->write_idx] = item; - queue->write_idx = (queue->write_idx + 1) % queue->capacity; - queue->size++; - - // 6. Signal blocked consumers that data is ready - c_Cond_Signal(&queue->not_empty); - - c_Mutex_UnLock(&queue->lock); - return C_TRUE; -} - diff --git a/Foundation/c_LockQueue.h b/Foundation/c_LockQueue.h deleted file mode 100644 index a3b6da1..0000000 --- a/Foundation/c_LockQueue.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef INCLUDED_C_LOCKQUEUE_H -#define INCLUDED_C_LOCKQUEUE_H - -#ifndef INCLUDED_C_TYPES_H -#include -#endif /*INCLUDED_C_TYPES_H*/ - -#ifndef INCLUDED_C_MUTEX_H -#include -#endif /*INCLUDED_C_MUTEX_H*/ - -#ifndef INCLUDED_C_COND_H -#include -#endif /*INCLUDED_C_COND_H*/ - - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -typedef struct { - void** data; - c_size_t capacity; - c_size_t write_idx; - c_size_t read_idx; - c_size_t size; - c_bool_t is_shutdown; - - c_Mutex_t lock; - c_Cond_t not_full; - c_Cond_t not_empty; -}c_LockQueue_t; - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -c_err_t c_LockQueue_Init(c_LockQueue_t* queue, c_size_t capacity); -void c_LockQueue_Destroy(c_LockQueue_t* queue); -void c_LockQueue_Shutdown(c_LockQueue_t* queue); - -c_err_t c_LockQueue_Push(c_LockQueue_t* queue, void* data); -c_err_t c_LockQueue_Pop(c_LockQueue_t* queue, void** data); -c_bool_t c_LockQueue_TimedPop(c_LockQueue_t* queue, void** item, c_uint_t timeout_ms); -c_bool_t c_LockQueue_TimedPush(c_LockQueue_t* queue, void* item, c_uint_t timeout_ms); -c_size_t c_LockQueue_Size(c_LockQueue_t* queue); - -c_bool_t c_LockQueue_IsEmpty(c_LockQueue_t* queue); -c_bool_t c_LockQueue_IsFull(c_LockQueue_t* queue); - -#endif /*INCLUDED_C_LOCKQUEUE_H*/ diff --git a/Foundation/c_Matrix.c b/Foundation/c_Matrix.c index 79c362a..5329f67 100644 --- a/Foundation/c_Matrix.c +++ b/Foundation/c_Matrix.c @@ -1,493 +1,351 @@ #include -#include -// 初始化矩阵(由外部传入结构体指针 self,内部只分配绑定的 c_Array 内存) -c_err_t c_Matrix_Init(c_Matrix_t* self, c_size_t rows, c_size_t cols, c_size_t element_size) { - if (!self) return C_ERR_PARAM; - if (rows == 0 || cols == 0 || element_size == 0) return C_ERR_PARAM; +c_err_t c_Matrix_Init(c_Matrix_t* self, c_size_t rows, c_size_t cols, c_size_t item_size, c_Allocator_t* allocator) { + if (!self || rows == 0 || cols == 0 || item_size == 0) return C_ERR_PARAM; - // 分配底层封装的一维泛型数组 - self->array = c_Array_New(rows * cols, element_size); - if (!self->array) { - return C_ERR_NOMEM; - } + // 防止 rows * cols * item_size 发生整型乘法回绕引发的堆踩踏 + if (rows > (c_size_t)-1 / (cols * item_size)) return C_ERR_OUTOFBOUND; + self->allocator = (allocator != NULL) ? *allocator : c_DefaultAllocator; self->rows = rows; self->cols = cols; - return C_SUCCESS; + self->item_size = item_size; + + // 一次性开辟完美的连续空间 + c_size_t total_bytes = self->rows * self->cols * self->item_size; + self->data = c_Allocator_Alloc(&self->allocator, total_bytes); + if (!self->data) return C_ERR_NOMEM; + + // 默认执行物理抹零清洁 + memset(self->data, 0, total_bytes); + return C_ERR_OK; } -// 销毁矩阵(释放内部资源,不释放 self 本身,由外部决定 self 释放方式) +// 物理销毁 void c_Matrix_Destroy(c_Matrix_t* self) { - if (self) { - if (self->array) { - c_Array_Delete(&self->array); - self->array = NULL; - } - self->rows = 0; - self->cols = 0; + if (!self) return; + if (self->data) { + c_Allocator_Free(&self->allocator, self->data); + self->data = NULL; } + self->rows = 0; + self->cols = 0; } -// 获取单个元素字节大小 -c_size_t c_Matrix_ElementSize(c_Matrix_t* self) { - if (!self || !self->array) return 0; - return c_Array_Size(self->array); +// 定点安全写入 (值深度复制) +c_err_t c_Matrix_Write(c_Matrix_t* self, c_size_t r, c_size_t c, const void* item) { + if (!self || !item || r >= self->rows || c >= self->cols) return C_ERR_PARAM; + + // 行优先扁平化寻址计算 + c_size_t index = r * self->cols + c; + char* target = (char*)self->data + (index * self->item_size); + memcpy(target, item, self->item_size); + + return C_ERR_OK; } -// 获取矩阵元素(通过二级指针 value 返回该元素的内部指针,并返回状态码) -c_err_t c_Matrix_Get(c_Matrix_t* self, c_size_t row, c_size_t col, void** value) { - if (!self || !value) return C_ERR_PARAM; - if (row >= self->rows || col >= self->cols) return C_ERR_PARAM; +// 定点安全读取 (安全拷贝副本) +c_err_t c_Matrix_Read(const c_Matrix_t* self, c_size_t r, c_size_t c, void* out_item) { + if (!self || !out_item || r >= self->rows || c >= self->cols) return C_ERR_PARAM; - // 计算一维索引:index = row * cols + col - const c_size_t index = row * self->cols + col; + c_size_t index = r * self->cols + c; + const char* source = (const char*)self->data + (index * self->item_size); + memcpy(out_item, source, self->item_size); - c_err_t err = c_Array_Get(self->array, index, value); - if (err!=C_ERR_OK) return err; - - return C_SUCCESS; + return C_ERR_OK; } -// 写入矩阵元素 -c_err_t c_Matrix_Put(c_Matrix_t* self, c_size_t row, c_size_t col, void* value) { - if (!self || !value) return C_ERR_PARAM; - if (row >= self->rows || col >= self->cols) return C_ERR_PARAM; - - const c_size_t index = row * self->cols + col; - return c_Array_Put(self->array, index, value); +// 只读原位窥探指针 (由于是固定一维连续空间,只要不销毁,此指针极其平稳安全) +void* c_Matrix_Get(const c_Matrix_t* self, c_size_t r, c_size_t c) { + if (!self || r >= self->rows || c >= self->cols) return NULL; + c_size_t index = r * self->cols + c; + return (char*)self->data + (index * self->item_size); } -// 矩阵转置:dst 必须是已经初始化好的大小为 (src->cols x src->rows) 的矩阵 -c_err_t c_Matrix_TransposeTo(c_Matrix_t* src, c_Matrix_t* dst) { - if (!src || !dst) return C_ERR_PARAM; - if (src->cols != dst->rows || src->rows != dst->cols) return C_ERR_PARAM; +// 批量全局抹值填充 +c_err_t c_Matrix_Fill(c_Matrix_t* self, const void* item) { + if (!self || !item) return C_ERR_PARAM; - for (c_size_t i = 0; i < src->rows; i++) { - for (c_size_t j = 0; j < src->cols; j++) { - void* temp = NULL; - c_Matrix_Get(src, i, j, (void**)&temp); - c_Matrix_Put(dst, j, i, temp); // 行列互换写入 - } + c_size_t total_elements = self->rows * self->cols; + char* target = (char*)self->data; + + for (c_size_t i = 0; i < total_elements; i++) { + memcpy(target, item, self->item_size); + target += self->item_size; } - - return C_SUCCESS; + return C_ERR_OK; } -// 矩阵乘法:C = A * B (以 float 为例) -c_err_t c_Matrix_Multiply(const c_Matrix_t* A, const c_Matrix_t* B, c_Matrix_t* C, void (*multiply)(const void* a, const void* b, void** c)) { - // 1. 基础健壮性检查 - if (!A || !B || !C || !multiply) return C_ERR_PARAM; +// 极致高速的一整行搬迁导出接口 (常用于图像处理的一行扫描线批量搬运) +c_err_t c_Matrix_CopyRow(const c_Matrix_t* self, c_size_t r, void* out_row_buffer) { + if (!self || !out_row_buffer || r >= self->rows) return C_ERR_PARAM; - // 2. 矩阵乘法维度匹配检查 (A的列数必须等于B的行数,C的尺寸必须是 A.rows x B.cols) - if (A->cols != B->rows || C->rows != A->rows || C->cols != B->cols) { - return C_ERR_PARAM; - } + // 因为行优先存储,整行的数据在物理上是 100% 绝对连续的一条线 + // 我们可以直接通过一次 memcpy 瞬时打包带走一整行,效率达到硬件总线传输极限 + const char* row_start = (const char*)self->data + (r * self->cols * self->item_size); + size_t row_bytes = self->cols * self->item_size; - const c_size_t elem_size = c_Matrix_ElementSize((c_Matrix_t*)A); - - // 4. 三重循环计算矩阵乘法 - for (c_size_t i = 0; i < A->rows; i++) { - for (c_size_t j = 0; j < B->cols; j++) { - - // 在计算当前 C[i][j] 的点积前,必须先获取 C[i][j] 现有的物理指针 - void* c_item_ptr = NULL; - c_Matrix_Get(C, i, j, &c_item_ptr); - - // 将当前位置的数据清零(初始化累加器) - memset(c_item_ptr, 0, elem_size); - - for (c_size_t k = 0; k < A->cols; k++) { - void *a_item_ptr = NULL; - void *b_item_ptr = NULL; - - // 安全获取 A[i][k] 和 B[k][j] - c_Matrix_Get((c_Matrix_t*)A, i, k, &a_item_ptr); - c_Matrix_Get((c_Matrix_t*)B, k, j, &b_item_ptr); - - // 核心:调用用户自定义的单元素乘法 - // 指针传参解释: - // &prod_res 是一个二级指针 (void**),回调函数内部会将计算结果写入到 prod_res 指向的缓冲区 - void* ctx_ptr = c_item_ptr; - multiply(a_item_ptr, b_item_ptr, (void**)&ctx_ptr); - - // 执行累加:这里需要对通用泛型执行加法 - // 由于 C 语言泛型限制,我们在这里进行一维数组层面的二进制或特定类型累加。 - // 工业级做法通常会将“加法”也作为回调,或者假设前几个字节可加。 - // 针对最常见的数值类型,我们可以根据用户传进来的回调结果,在当前位置累加: - // 为使设计更严谨,通常让 multiply 内部直接实现:*(Type*)c_item_ptr += *(Type*)a * *(Type*)b - // 如果你的 multiply 语义是:*c = a * b,则需要外部进行特定类型的累加,例如以 float 为例: - // *(float*)c_item_ptr += *(float*)prod_res; - } - } - } - - return C_SUCCESS; + memcpy(out_row_buffer, row_start, row_bytes); + return C_ERR_OK; } /* ------------------------------------------------------------------------------------------------------------------ */ /* */ -// 辅助函数:根据一维索引,计算转置后该元素应当去往的新一维索引 -// 公式:新行 = 旧列,新列 = 旧行 -> new_index = (old_index % cols) * rows + (old_index / cols) -C_STATIC_FORCE_INLINE -c_size_t get_transposed_source_index(c_size_t curr_index, c_size_t old_rows, c_size_t old_cols) { - return (curr_index % old_rows) * old_cols + (curr_index / old_rows); -} +// 辅助寻址内部宏 +#define MAT_ELEMENT(mat, idx) ((char*)(mat)->data + ((idx) * (mat)->item_size)) -c_err_t c_Matrix_InPlaceTranspose(c_Matrix_t* self) { - if (!self || !self->array) return C_ERR_PARAM; - - c_size_t rows = self->rows; - c_size_t cols = self->cols; - c_size_t elem_size = c_Matrix_ElementSize(self); - - if (rows <= 1 && cols <= 1) { - return C_SUCCESS; +/** + * @brief 逐元素(Element-wise)矩阵运算通用驱动函数(内部私有) + */ +static c_err_t c_Matrix_ElementWiseCore(c_Matrix_t* out, const c_Matrix_t* lhs, const c_Matrix_t* rhs, + c_Matrix_OpFn_t op, void* ud) { + if (!out || !lhs || !rhs || !op) return C_ERR_PARAM; + // 强御安全校验:矩阵运算要求维度必须完全空间对齐一致 + if (lhs->rows != rhs->rows || lhs->cols != rhs->cols || + lhs->rows != out->rows || lhs->cols != out->cols || + lhs->item_size != rhs->item_size || lhs->item_size != out->item_size) { + return C_ERR_OUTOFBOUND; } - // -------------------------------------------------------------------------------- - // 场景 A:方阵原地转置(不变,原本就是正确的) - // -------------------------------------------------------------------------------- - if (rows == cols) { -#define SWAP_BUF_SIZE 256 - uint8_t swap_buf[SWAP_BUF_SIZE]; - uint8_t* temp = swap_buf; - if (elem_size > SWAP_BUF_SIZE) { - temp = (uint8_t*)C_ALLOC(elem_size); - if (!temp) return C_ERR_NOMEM; - } - for (c_size_t i = 0; i < rows; i++) { - for (c_size_t j = i + 1; j < cols; j++) { - void *cell_a = NULL, *cell_b = NULL; - c_Matrix_Get(self, i, j, &cell_a); - c_Matrix_Get(self, j, i, &cell_b); - memcpy(temp, cell_a, elem_size); - memcpy(cell_a, cell_b, elem_size); - memcpy(cell_b, temp, elem_size); - } - } - if (elem_size > SWAP_BUF_SIZE) C_FREE(temp); -#undef SWAP_BUF_SIZE - return C_SUCCESS; - } - - // -------------------------------------------------------------------------------- - // 场景 B:非方阵原地转置(已完全修复环路拉取逻辑) - // -------------------------------------------------------------------------------- - c_size_t total_elements = rows * cols; - - c_size_t bitmask_size = (total_elements + 7) / 8; - uint8_t* visited = (uint8_t*)C_CALLOC(bitmask_size, sizeof(uint8_t)); - if (!visited) return C_ERR_NOMEM; - - uint8_t* cycle_buf = (uint8_t*)C_ALLOC(elem_size); - if (!cycle_buf) { - C_FREE(visited); - return C_ERR_NOMEM; - } - - void* base_data = NULL; - c_err_t array_err = c_Array_Get(self->array, 0, &base_data); - if (array_err != C_SUCCESS || !base_data) { - C_FREE(cycle_buf); - C_FREE(visited); - return array_err; - } + c_size_t total_elements = lhs->rows * lhs->cols; + // 【工业级内核性能极致拉平】:直接抛弃二维坐标计算,用一维指针流极速推进 for (c_size_t i = 0; i < total_elements; i++) { - if (visited[i / 8] & (1 << (i % 8))) { - continue; - } - - c_size_t curr_idx = i; - // 使用修正后的逆向映射函数 - c_size_t next_idx = get_transposed_source_index(curr_idx, rows, cols); - - if (next_idx == curr_idx) { - visited[curr_idx / 8] |= (1 << (curr_idx % 8)); - continue; - } - - // 暂存当前起点元素 - memcpy(cycle_buf, (char*)base_data + (curr_idx * elem_size), elem_size); - - // 沿着逆向数据源环路追溯拉取 - while (next_idx != i) { - void* src = (char*)base_data + (next_idx * elem_size); - void* dst = (char*)base_data + (curr_idx * elem_size); - - memcpy(dst, src, elem_size); // 正确地拉取源数据 - visited[curr_idx / 8] |= (1 << (curr_idx % 8)); - - curr_idx = next_idx; - next_idx = get_transposed_source_index(curr_idx, rows, cols); - } - - // 闭合环路 - void* dst = (char*)base_data + (curr_idx * elem_size); - memcpy(dst, cycle_buf, elem_size); - visited[curr_idx / 8] |= (1 << (curr_idx % 8)); + void* out_ptr = MAT_ELEMENT(out, i); + const void* lhs_ptr = MAT_ELEMENT(lhs, i); + const void* rhs_ptr = MAT_ELEMENT(rhs, i); + op(out_ptr, lhs_ptr, rhs_ptr, ud); // 驱动具体类型算子 } - - C_FREE(cycle_buf); - C_FREE(visited); - - // 修改元数据宽高 - self->rows = cols; - self->cols = rows; - - return C_SUCCESS; + return C_ERR_OK; } -c_err_t c_Matrix_Determinant(const c_Matrix_t* self, const c_MatrixOps_t* ops, void* out_det) { - if (!self || !ops || !out_det) return C_ERR_PARAM; - if (self->rows != self->cols) return C_ERR_PARAM; +c_err_t c_Matrix_Add(c_Matrix_t* out, const c_Matrix_t* lhs, const c_Matrix_t* rhs, c_Matrix_OpFn_t add_op, void* ud) { + return c_Matrix_ElementWiseCore(out, lhs, rhs, add_op, ud); +} - c_size_t n = self->rows; - c_size_t elem_size = c_Matrix_ElementSize((c_Matrix_t*)self); +c_err_t c_Matrix_Sub(c_Matrix_t* out, const c_Matrix_t* lhs, const c_Matrix_t* rhs, c_Matrix_OpFn_t sub_op, void* ud) { + return c_Matrix_ElementWiseCore(out, lhs, rhs, sub_op, ud); +} +c_err_t c_Matrix_Div(c_Matrix_t* out, const c_Matrix_t* lhs, const c_Matrix_t* rhs, c_Matrix_OpFn_t div_op, void* ud) { + return c_Matrix_ElementWiseCore(out, lhs, rhs, div_op, ud); +} + +/** + * @brief 经典线性代数标准矩阵乘法 (Matrix Multiplication: O(N^3)) + * @note 满足拓扑条件:lhs(M x K) * rhs(K x N) = out(M x N) + */ +c_err_t c_Matrix_Mul(c_Matrix_t* out, const c_Matrix_t* lhs, const c_Matrix_t* rhs, + c_Matrix_OpFn_t mul_op, c_Matrix_OpFn_t add_op, void* ud) { + if (!out || !lhs || !rhs || !mul_op || !add_op) return C_ERR_PARAM; + // 拓扑几何边界校验 + if (lhs->cols != rhs->rows || out->rows != lhs->rows || out->cols != rhs->cols || + lhs->item_size != rhs->item_size || lhs->item_size != out->item_size) { + return C_ERR_OUTOFBOUND; + } + + c_size_t M = lhs->rows; + c_size_t K = lhs->cols; + c_size_t N = rhs->cols; + + // 分配一个栈上的临时缓冲区,用来暂存单次乘法的中间值(避免频繁分配堆内存导致碎片) + // 由于是泛型,大小通过 item_size 动态抹平 + void* temp_mul_res = c_Allocator_Alloc(&out->allocator, out->item_size); + if (!temp_mul_res) return C_ERR_NOMEM; + + for (c_size_t i = 0; i < M; i++) { + for (c_size_t j = 0; j < N; j++) { + void* out_cell = (char*)out->data + ((i * N + j) * out->item_size); + + // 每次计算新格子前,首先执行干净的物理抹零(清空历史残存值) + memset(out_cell, 0, out->item_size); + + for (c_size_t k = 0; k < K; k++) { + const void* lhs_cell = (char*)lhs->data + ((i * K + k) * lhs->item_size); + const void* rhs_cell = (char*)rhs->data + ((k * N + j) * rhs->item_size); + + // 1. 计算当前权重的乘积:temp_mul_res = lhs_cell * rhs_cell + mul_op(temp_mul_res, lhs_cell, rhs_cell, ud); + + // 2. 累加到目标格子中:out_cell = out_cell + temp_mul_res + add_op(out_cell, out_cell, temp_mul_res, ud); + } + } + } + + c_Allocator_Free(&out->allocator, temp_mul_res); + return C_ERR_OK; +} + +/** + * @brief 标量运算通用驱动核心(内部私有) + */ +static c_err_t c_Matrix_ScalarCore(c_Matrix_t* out, const c_Matrix_t* in, const void* scalar, + c_Matrix_OpFn_t op, void* ud) { + if (!out || !in || !scalar || !op) return C_ERR_PARAM; + if (in->rows != out->rows || in->cols != out->cols || in->item_size != out->item_size) { + return C_ERR_OUTOFBOUND; + } + + c_size_t total_elements = in->rows * in->cols; + for (c_size_t i = 0; i < total_elements; i++) { + void* out_ptr = MAT_ELEMENT(out, i); + const void* in_ptr = MAT_ELEMENT(in, i); + op(out_ptr, in_ptr, scalar, ud); // 驱动单元素与标量运算 + } + return C_ERR_OK; +} + +c_err_t c_Matrix_AddScalar(c_Matrix_t* out, const c_Matrix_t* in, const void* scalar, c_Matrix_OpFn_t add_op, void* ud) { + return c_Matrix_ScalarCore(out, in, scalar, add_op, ud); +} + +c_err_t c_Matrix_SubScalar(c_Matrix_t* out, const c_Matrix_t* in, const void* scalar, c_Matrix_OpFn_t sub_op, void* ud) { + return c_Matrix_ScalarCore(out, in, scalar, sub_op, ud); +} + +c_err_t c_Matrix_MulScalar(c_Matrix_t* out, const c_Matrix_t* in, const void* scalar, c_Matrix_OpFn_t mul_op, void* ud) { + return c_Matrix_ScalarCore(out, in, scalar, mul_op, ud); +} + +c_err_t c_Matrix_DivScalar(c_Matrix_t* out, const c_Matrix_t* in, const void* scalar, c_Matrix_OpFn_t div_op, void* ud) { + return c_Matrix_ScalarCore(out, in, scalar, div_op, ud); +} + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +// 矩阵转置实现 (M x N -> N x M) +c_err_t c_Matrix_Transpose(c_Matrix_t* out, const c_Matrix_t* in) { + if (!out || !in || !out->data || !in->data) return C_ERR_PARAM; + + // 空间几何拓扑强校验 + if (out->rows != in->cols || out->cols != in->rows || out->item_size != in->item_size) { + return C_ERR_OUTOFBOUND; + } + + c_size_t r_max = in->rows; + c_size_t c_max = in->cols; + c_size_t item_sz = in->item_size; + + // 行优先数据错位映射搬运:in(r, c) -> out(c, r) + for (c_size_t r = 0; r < r_max; r++) { + for (c_size_t c = 0; c < c_max; c++) { + const char* src_cell = (const char*)in->data + ((r * c_max + c) * item_sz); + char* dst_cell = (char*)out->data + ((c * r_max + r) * item_sz); + memcpy(dst_cell, src_cell, item_sz); // 泛型值原装迁徙 + } + } + return C_ERR_OK; +} + +/** + * @brief 内部私有递归核心:拉普拉斯代数余子式展开 + */ +static void c_Matrix_DetInternal(c_Matrix_t* mat, void* out_det, + c_Matrix_OpFn_t add_op, c_Matrix_OpFn_t sub_op, + c_Matrix_OpFn_t mul_op, c_Matrix_NegFn_t neg_op, + void* ud) { + c_size_t n = mat->rows; + c_size_t item_sz = mat->item_size; + + // 基本边界 1: 1x1 方阵,行列式值即为其唯一的单体元素本身 if (n == 1) { - void* cell = NULL; - c_Matrix_Get((c_Matrix_t*)self, 0, 0, &cell); - memcpy(out_det, cell, elem_size); - return C_SUCCESS; + memcpy(out_det, mat->data, item_sz); + return; } - c_Matrix_t temp_mat; - c_err_t err = c_Matrix_Init(&temp_mat, n, n, elem_size); - if (err != C_SUCCESS) return err; + // 基本边界 2: 2x2 方阵,计算 ad - bc 快速通路,消除不必要的低层递归 + if (n == 2) { + char* a = (char*)mat->data + (0 * item_sz); + char* b = (char*)mat->data + (1 * item_sz); + char* c = (char*)mat->data + (2 * item_sz); + char* d = (char*)mat->data + (3 * item_sz); - void* src_base = NULL; - void* dst_base = NULL; - c_Array_Get(self->array, 0, &src_base); - c_Array_Get(temp_mat.array, 0, &dst_base); - memcpy(dst_base, src_base, n * n * elem_size); + // 分配栈上局部存储,避开堆碎片 + void* ad = c_Allocator_Alloc(&mat->allocator, item_sz); + void* bc = c_Allocator_Alloc(&mat->allocator, item_sz); - ops->one(out_det); - int sign = 1; + mul_op(ad, a, d, ud); // a * d + mul_op(bc, b, c, ud); // b * c + sub_op(out_det, ad, bc, ud); // ad - bc - // 分配真正独立的单元素计算缓冲区 - void* pivot_val = C_ALLOC(elem_size); - void* factor = C_ALLOC(elem_size); - void* temp_val = C_ALLOC(elem_size); - - if (!pivot_val || !factor || !temp_val) { - C_FREE(pivot_val); - C_FREE(factor); - C_FREE(temp_val); - return C_ERR_NOMEM; + c_Allocator_Free(&mat->allocator, ad); + c_Allocator_Free(&mat->allocator, bc); + return; } - for (c_size_t i = 0; i < n; i++) { - // --- 部分主元选择 --- - c_size_t pivot_row = i; - void* max_cell = NULL; - c_Matrix_Get(&temp_mat, i, i, &max_cell); + // 递归分支: n > 2,固定沿第 0 行进行展开 + memset(out_det, 0, item_sz); // 抹零累加器 - for (c_size_t k = i + 1; k < n; k++) { - void* check_cell = NULL; - c_Matrix_Get(&temp_mat, k, i, &check_cell); - if (ops->compare_abs(check_cell, max_cell) > 0) { - max_cell = check_cell; - pivot_row = k; + // 原地创建子方阵控制头 (大小为 n-1) + c_Matrix_t sub_mat; + sub_mat.allocator = mat->allocator; + sub_mat.rows = n - 1; + sub_mat.cols = n - 1; + sub_mat.item_size = item_sz; + + c_size_t sub_bytes = sub_mat.rows * sub_mat.cols * item_sz; + sub_mat.data = c_Allocator_Alloc(&mat->allocator, sub_bytes); + if (!sub_mat.data) return; + + void* sub_det = c_Allocator_Alloc(&mat->allocator, item_sz); + void* term = c_Allocator_Alloc(&mat->allocator, item_sz); + void* neg_term = c_Allocator_Alloc(&mat->allocator, item_sz); + + // 遍历第 0 行的每一列 c + for (c_size_t c = 0; c < n; c++) { + // 构建割裂后的代数余子式子方阵数据块 + c_size_t sub_r = 0; + for (c_size_t r = 1; r < n; r++) { // 跳过第 0 行 + c_size_t sub_c = 0; + for (c_size_t j = 0; j < n; j++) { + if (j == c) continue; // 跳过当前列 + + const char* src = (const char*)mat->data + ((r * n + j) * item_sz); + char* dst = (char*)sub_mat.data + ((sub_r * (n - 1) + sub_c) * item_sz); + memcpy(dst, src, item_sz); + sub_c++; } + sub_r++; } - if (ops->is_zero(max_cell)) { - ops->zero(out_det); - goto _cleanup; + // 递归求解子方阵的行列式 + c_Matrix_DetInternal(&sub_mat, sub_det, add_op, sub_op, mul_op, neg_op, ud); + + // 计算当前项的系数乘积 term = mat(0, c) * sub_det + const void* current_element = (const char*)mat->data + (c * item_sz); + mul_op(term, current_element, sub_det, ud); + + // 根据棋盘格正负号规则 ((-1)^(r+c)):当前第 0 行第 c 列,当 c 为奇数时取反 + if (c % 2 == 1) { + neg_op(neg_term, term, ud); // 取负号 + add_op(out_det, out_det, neg_term, ud); // 累加负项 + } else { + add_op(out_det, out_det, term, ud); // 累加正项 } - - if (pivot_row != i) { - for (c_size_t j = i; j < n; j++) { - void *cell_a = NULL, *cell_b = NULL; - c_Matrix_Get(&temp_mat, i, j, &cell_a); - c_Matrix_Get(&temp_mat, pivot_row, j, &cell_b); - - memcpy(temp_val, cell_a, elem_size); - memcpy(cell_a, cell_b, elem_size); - memcpy(cell_b, temp_val, elem_size); - } - sign = -sign; - } - - // --- 🛠️ 核心修复点:安全获取当前主元的数据 --- - void* internal_pivot_ptr = NULL; - c_Matrix_Get(&temp_mat, i, i, &internal_pivot_ptr); // 此时被覆盖的是临时的 internal_pivot_ptr - memcpy(pivot_val, internal_pivot_ptr, elem_size); // 将真实数据拷贝到我们的 C_ALLOC 缓冲区中,保持 pivot_val 的指针值不变 - - // --- 消元 --- - for (c_size_t k = i + 1; k < n; k++) { - void* current_col_cell = NULL; - c_Matrix_Get(&temp_mat, k, i, ¤t_col_cell); - - if (ops->is_zero(current_col_cell)) continue; - - ops->div(current_col_cell, pivot_val, factor); - - for (c_size_t j = i; j < n; j++) { - void *row_i_cell = NULL, *row_k_cell = NULL; - c_Matrix_Get(&temp_mat, i, j, &row_i_cell); - c_Matrix_Get(&temp_mat, k, j, &row_k_cell); - - ops->mul(row_i_cell, factor, temp_val); - ops->sub(row_k_cell, temp_val, row_k_cell); - } - } - - // 累乘对角线元素 - ops->mul(out_det, pivot_val, out_det); } - if (sign == -1) { - ops->zero(temp_val); - ops->sub(temp_val, out_det, out_det); - } - -_cleanup: - // 此时的指针地址完美保持初始 C_ALLOC 状态,可以安全 C_FREE! - C_FREE(pivot_val); - C_FREE(factor); - C_FREE(temp_val); - c_Matrix_Destroy(&temp_mat); - return C_SUCCESS; + // 异常安全性层级强力物理释放,绝不产生多级残留 + c_Allocator_Free(&mat->allocator, sub_mat.data); + c_Allocator_Free(&mat->allocator, sub_det); + c_Allocator_Free(&mat->allocator, term); + c_Allocator_Free(&mat->allocator, neg_term); } -c_err_t c_Matrix_Solve(const c_Matrix_t* A, const c_Matrix_t* b, c_Matrix_t* x, const c_MatrixOps_t* ops) { - // 1. 基础健壮性检查 - if (!A || !b || !x || !ops) return C_ERR_PARAM; - if (A->rows != A->cols) return C_ERR_PARAM; // A 必须是方阵 - if (b->rows != A->rows || b->cols != 1) return C_ERR_PARAM; // b 必须是 Nx1 - if (x->rows != A->rows || x->cols != 1) return C_ERR_PARAM; // x 必须是 Nx1 +// 行列式主驱动包装接口 +c_err_t c_Matrix_Determinant(c_Matrix_t* self, void* out_det, + c_Matrix_OpFn_t add_op, c_Matrix_OpFn_t sub_op, + c_Matrix_OpFn_t mul_op, c_Matrix_NegFn_t neg_op, + void* ud) { + if (!self || !out_det || !add_op || !sub_op || !mul_op || !neg_op) return C_ERR_PARAM; - c_size_t n = A->rows; - c_size_t elem_size = c_Matrix_ElementSize((c_Matrix_t*)A); - - // 2. 初始化 Nx(N+1) 的增广矩阵 - c_Matrix_t aug; - c_err_t err = c_Matrix_Init(&aug, n, n + 1, elem_size); - if (err != C_SUCCESS) return err; - - // 填充增广矩阵:前 n 列拷贝 A,第 n+1 列拷贝 b - for (c_size_t i = 0; i < n; i++) { - for (c_size_t j = 0; j < n; j++) { - void* cell_A = NULL; - c_Matrix_Get((c_Matrix_t*)A, i, j, &cell_A); - c_Matrix_Put(&aug, i, j, cell_A); - } - void* cell_b = NULL; - c_Matrix_Get((c_Matrix_t*)b, i, 0, &cell_b); - c_Matrix_Put(&aug, i, n, cell_b); // 最后一列 + // 强行约束约束:只有正方矩阵具备行列式 + if (self->rows != self->cols || self->rows == 0) { + return C_ERR_OUTOFBOUND; } - // 分配独立的计算缓冲区,严格保护指针地址不被 Get 覆盖 - void* pivot_val = C_ALLOC(elem_size); - void* factor = C_ALLOC(elem_size); - void* temp_val = C_ALLOC(elem_size); - void* sum_val = C_ALLOC(elem_size); - - if (!pivot_val || !factor || !temp_val || !sum_val) { - C_FREE(pivot_val); - C_FREE(factor); - C_FREE(temp_val); - C_FREE(sum_val); - return C_ERR_NOMEM; - } - - // 3. 高斯消元主循环(化为上三角矩阵) - for (c_size_t i = 0; i < n; i++) { - // --- 3.1 部分主元选择(选绝对值最大的行交换上来,提高数值稳定性) --- - c_size_t pivot_row = i; - void* max_cell = NULL; - c_Matrix_Get(&aug, i, i, &max_cell); - - for (c_size_t k = i + 1; k < n; k++) { - void* check_cell = NULL; - c_Matrix_Get(&aug, k, i, &check_cell); - if (ops->compare_abs(check_cell, max_cell) > 0) { - max_cell = check_cell; - pivot_row = k; - } - } - - // 如果主元极度接近 0,说明矩阵奇异(无解或无数解) - if (ops->is_zero(max_cell)) { - err = C_ERR_SINGULAR; - goto _cleanup; - } - - // 行交换 - if (pivot_row != i) { - for (c_size_t j = i; j <= n; j++) { - void *cell_a = NULL, *cell_b = NULL; - c_Matrix_Get(&aug, i, j, &cell_a); - c_Matrix_Get(&aug, pivot_row, j, &cell_b); - - memcpy(temp_val, cell_a, elem_size); - memcpy(cell_a, cell_b, elem_size); - memcpy(cell_b, temp_val, elem_size); - } - } - - // --- 3.2 保护性安全读取当前行的主元数据 --- - void* internal_pivot_ptr = NULL; - c_Matrix_Get(&aug, i, i, &internal_pivot_ptr); - memcpy(pivot_val, internal_pivot_ptr, elem_size); // 复制数据,保证 pivot_val 的 C_ALLOC 指针不被踩坏 - - // --- 3.3 消元过程 --- - for (c_size_t k = i + 1; k < n; k++) { - void* current_col_cell = NULL; - c_Matrix_Get(&aug, k, i, ¤t_col_cell); - - if (ops->is_zero(current_col_cell)) continue; - - // factor = aug[k][i] / pivot_val - ops->div(current_col_cell, pivot_val, factor); - - for (c_size_t j = i; j <= n; j++) { - void *row_i_cell = NULL, *row_k_cell = NULL; - c_Matrix_Get(&aug, i, j, &row_i_cell); - c_Matrix_Get(&aug, k, j, &row_k_cell); - - ops->mul(row_i_cell, factor, temp_val); // temp = aug[i][j] * factor - ops->sub(row_k_cell, temp_val, row_k_cell); // aug[k][j] -= temp - } - } - } - - // 4. 回代法求解(Back Substitution) - // 公式:x[i] = (aug[i][n] - sum(aug[i][j] * x[j])) / aug[i][i] - for (int i = (int)n - 1; i >= 0; i--) { - ops->zero(sum_val); // sum = 0 - - for (c_size_t j = (c_size_t)i + 1; j < n; j++) { - void *aug_cell = NULL, *x_cell = NULL; - c_Matrix_Get(&aug, (c_size_t)i, j, &aug_cell); - c_Matrix_Get(x, j, 0, &x_cell); - - ops->mul(aug_cell, x_cell, temp_val); // temp = aug[i][j] * x[j] - ops->add(sum_val, temp_val, sum_val); // sum += temp - } - - void *aug_b_cell = NULL, *aug_diag_cell = NULL; - c_Matrix_Get(&aug, (c_size_t)i, n, &aug_b_cell); // 最后一列的常数项 - c_Matrix_Get(&aug, (c_size_t)i, (c_size_t)i, &aug_diag_cell); // 对角线主元 - - ops->sub(aug_b_cell, sum_val, temp_val); // temp = b_item - sum - - void* x_dest_slot = NULL; - c_Matrix_Get(x, (c_size_t)i, 0, &x_dest_slot); - ops->div(temp_val, aug_diag_cell, x_dest_slot); // x[i] = temp / aug[i][i] - } - - err = C_SUCCESS; - -_cleanup: - C_FREE(pivot_val); - C_FREE(factor); - C_FREE(temp_val); - C_FREE(sum_val); - c_Matrix_Destroy(&aug); - return err; + c_Matrix_DetInternal(self, out_det, add_op, sub_op, mul_op, neg_op, ud); + return C_ERR_OK; } diff --git a/Foundation/c_Matrix.h b/Foundation/c_Matrix.h index 64239e1..b3f9d2c 100644 --- a/Foundation/c_Matrix.h +++ b/Foundation/c_Matrix.h @@ -1,90 +1,102 @@ #ifndef INCLUDED_C_MATRIX_H #define INCLUDED_C_MATRIX_H -#ifndef INCLUDED_C_ARRAY_H -#include -#endif /*INCLUDED_C_ARRAY_H*/ +#ifndef INCLUDED_C_TYPES_H +#include +#endif /*INCLUDED_C_TYPES_H*/ + + +#ifndef INCLUDED_C_ALLOCATOR_H +#include +#endif /*INCLUDED_C_ALLOCATOR_H*/ /* ------------------------------------------------------------------------------------------------------------------ */ /* */ -// “主元全为0”而触发矩阵奇异错误 -#define C_ERR_SINGULAR C_ERR_FAIL +// 元素对元素算子:将 a 和 b 运算后的结果写入 out 中 +typedef void (*c_Matrix_OpFn_t)(void* out, const void* a, const void* b, void* ud); + +// 变号算子:将 in 取负(或执行共轭对调等)后写入 out 中 +typedef void (*c_Matrix_NegFn_t)(void* out, const void* in, void* ud); -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ typedef struct { - c_Array_t* array; // 内部封装的一维泛型数组 - c_size_t rows; // 矩阵行数 - c_size_t cols; // 矩阵列数 -}c_Matrix_t; - -// 泛型数学算子包 -typedef struct { - void (*zero)(void* out); // 设为 0 - void (*one)(void* out); // 设为 1 - void (*add)(const void* a, const void* b, void* out); // out = a + b - void (*sub)(const void* a, const void* b, void* out); // out = a - b - void (*mul)(const void* a, const void* b, void* out); // out = a * b - void (*div)(const void* a, const void* b, void* out); // out = a / b - int (*is_zero)(const void* a); // 判断是否为 0 (或接近 0) - int (*compare_abs)(const void* a, const void* b); // 绝对值比较:|a| > |b| 返回 1, 否则返回 0 -} c_MatrixOps_t; + void* data; // 一维扁平化的连续行优先(Row-Major)存储区 + c_size_t rows; // 矩阵的固定总行数 + c_size_t cols; // 矩阵的固定总列数 + c_size_t item_size; // 单个元素的字节大小 + c_Allocator_t allocator; // 内部绑定的自主内存管理器 +} c_Matrix_t; /* ------------------------------------------------------------------------------------------------------------------ */ /* */ -c_err_t c_Matrix_Init(c_Matrix_t* self, c_size_t rows, c_size_t cols, c_size_t element_size); +c_err_t c_Matrix_Init(c_Matrix_t* self, c_size_t rows, c_size_t cols, c_size_t item_size, c_Allocator_t* allocator); +void c_Matrix_Destroy(c_Matrix_t* self); -void c_Matrix_Destroy(c_Matrix_t* self); +// 核心定点操作 API (安全值复制模式) +c_err_t c_Matrix_Write(c_Matrix_t* self, c_size_t r, c_size_t c, const void* item); +c_err_t c_Matrix_Read(const c_Matrix_t* self, c_size_t r, c_size_t c, void* out_item); +void* c_Matrix_Get(const c_Matrix_t* self, c_size_t r, c_size_t c); -c_size_t c_Matrix_ElementSize(c_Matrix_t* self); +// 矩阵高级辅助操作 +c_err_t c_Matrix_Fill(c_Matrix_t* self, const void* item); +c_err_t c_Matrix_CopyRow(const c_Matrix_t* self, c_size_t r, void* out_row_buffer); -c_err_t c_Matrix_Get(c_Matrix_t* self, c_size_t row, c_size_t col, void** value); - -c_err_t c_Matrix_Put(c_Matrix_t* self, c_size_t row, c_size_t col, void* value); +// 内联高频辅助接口 +C_STATIC_FORCE_INLINE c_size_t c_Matrix_Rows(const c_Matrix_t* self) { return self ? self->rows : 0; } +C_STATIC_FORCE_INLINE c_size_t c_Matrix_Cols(const c_Matrix_t* self) { return self ? self->cols : 0; } /* ------------------------------------------------------------------------------------------------------------------ */ -/* +/* */ -float 运算 举例 - void float_matmul_callback(const void* a, const void* b, void** c) { - float val_a = *(const float*)a; - float val_b = *(const float*)b; +// 1. 矩阵与矩阵之间的加、减、乘、除(其中加减除为 Element-wise 逐元素运算,乘法为标准线性代数矩阵乘法) +c_err_t c_Matrix_Add(c_Matrix_t* out, const c_Matrix_t* lhs, const c_Matrix_t* rhs, c_Matrix_OpFn_t add_op, void* ud); +c_err_t c_Matrix_Sub(c_Matrix_t* out, const c_Matrix_t* lhs, const c_Matrix_t* rhs, c_Matrix_OpFn_t sub_op, void* ud); +c_err_t c_Matrix_Div(c_Matrix_t* out, const c_Matrix_t* lhs, const c_Matrix_t* rhs, c_Matrix_OpFn_t div_op, void* ud); - // 1. 拿到外部矩阵 C[i][j] 的真实内存地址 - float* dest_cell = *(float**)c; +// 标准线性代数矩阵乘法 (Matrix Multiplication):要求 lhs 的列数等于 rhs 的行数 +// 内部包含累加逻辑,因此除了乘法算子,还需要额外传入一个加法算子 +c_err_t c_Matrix_Mul(c_Matrix_t* out, const c_Matrix_t* lhs, const c_Matrix_t* rhs, + c_Matrix_OpFn_t mul_op, c_Matrix_OpFn_t add_op, void* ud); - // 2. 严格执行乘加(+=) - *dest_cell += val_a * val_b; - } - */ +// 2. 矩阵与标量(Scalar)的加减乘除(即矩阵中的每一个元素都与外部单值标量进行运算) +c_err_t c_Matrix_AddScalar(c_Matrix_t* out, const c_Matrix_t* in, const void* scalar, c_Matrix_OpFn_t add_op, void* ud); +c_err_t c_Matrix_SubScalar(c_Matrix_t* out, const c_Matrix_t* in, const void* scalar, c_Matrix_OpFn_t sub_op, void* ud); +c_err_t c_Matrix_MulScalar(c_Matrix_t* out, const c_Matrix_t* in, const void* scalar, c_Matrix_OpFn_t mul_op, void* ud); +c_err_t c_Matrix_DivScalar(c_Matrix_t* out, const c_Matrix_t* in, const void* scalar, c_Matrix_OpFn_t div_op, void* ud); -c_err_t c_Matrix_Multiply(const c_Matrix_t* A, const c_Matrix_t* B, c_Matrix_t* C, void (*multiply)(const void* a, const void* b, void** c)) ; - -c_err_t c_Matrix_TransposeTo(c_Matrix_t* src, c_Matrix_t* dst); - -c_err_t c_Matrix_InPlaceTranspose(c_Matrix_t* self); +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ /** - * @brief 计算方阵的行列式 - * @param self 矩阵指针 - * @param ops 用户注册的泛型数学算子包 - * @param out_det 存储计算结果的内存指针(外部分配) - * @return c_err_t 成功返回 C_SUCCESS,非方阵返回 C_ERR_PARAM + * @brief 矩阵转置 (Matrix Transpose) + * @param out 存储结果的目标矩阵。空间几何拓扑必须满足:out->rows == in->cols 且 out->cols == in->rows + * @param in 输入的原矩阵 (M x N) + * @return c_err_t 成功返回 C_ERR_OK */ -c_err_t c_Matrix_Determinant(const c_Matrix_t* self, const c_MatrixOps_t* ops, void* out_det); +c_err_t c_Matrix_Transpose(c_Matrix_t* out, const c_Matrix_t* in); + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + /** - * @brief 使用高斯消元法求解线性方程组 Ax = b - * @param A NxN 的系数矩阵指针 - * @param b Nx1 的常数项向量矩阵指针 - * @param x Nx1 的解向量矩阵指针(外部分配好内存) - * @param ops 用户注册的泛型数学算子包 - * @return c_err_t 成功返回 C_SUCCESS,维度不匹配返回 C_ERR_PARAM,矩阵奇异返回 C_ERR_SINGULAR + * @brief 泛型矩阵行列式求解 (Matrix Determinant) + * @note 采用经典的拉普拉斯代数余子式递归展开法(Laplace Expansion) + * @param self 目标矩阵,空间拓扑必须为方阵:self->rows == self->cols + * @param out_det 外部提供用以承接最终行列式标量值的缓冲区(大小必须 >= item_size) + * @param add_op 加法算子 + * @param sub_op 减法算子 + * @param mul_op 乘法算子 + * @param neg_op 变号/取负算子 + * @param ud 用户自定义上下文指针 + * @return c_err_t 成功返回 C_ERR_OK,方阵校验失败返回 C_ERR_OUTOFBOUND */ -c_err_t c_Matrix_Solve(const c_Matrix_t* A, const c_Matrix_t* b, c_Matrix_t* x, const c_MatrixOps_t* ops); +c_err_t c_Matrix_Determinant(c_Matrix_t* self, void* out_det, + c_Matrix_OpFn_t add_op, c_Matrix_OpFn_t sub_op, + c_Matrix_OpFn_t mul_op, c_Matrix_NegFn_t neg_op, + void* ud); #endif /*INCLUDED_C_MATRIX_H*/ diff --git a/Foundation/c_Matrix.t.c b/Foundation/c_Matrix.t.c new file mode 100644 index 0000000..19f3dd2 --- /dev/null +++ b/Foundation/c_Matrix.t.c @@ -0,0 +1,223 @@ +#include "c_Matrix.h" +#include "c_Test.h" + +typedef struct { + float x_scale; + float y_scale; +} TransformNode_t; + +TEST_CASE(test_generic_flattened_matrix_flow) { + c_Matrix_t mat; + + // 初始化一个 2行 3列 专门存储 TransformNode_t 变换的矩阵 + ASSERT_INT_EQ(C_ERR_OK, c_Matrix_Init(&mat, 2, 3, sizeof(TransformNode_t), NULL)); + ASSERT_INT_EQ(2, c_Matrix_Rows(&mat)); + ASSERT_INT_EQ(3, c_Matrix_Cols(&mat)); + ASSERT_PTR_NOT_NULL(mat.data); + + TransformNode_t t_origin = { .x_scale = 1.0f, .y_scale = 1.0f }; + TransformNode_t t_custom = { .x_scale = 5.5f, .y_scale = 9.9f }; + + // 1. 全局先刷入原始一阶数据 + ASSERT_INT_EQ(C_ERR_OK, c_Matrix_Fill(&mat, &t_origin)); + + // 2. 在 (1行, 2列) 定点写入定制数据 + ASSERT_INT_EQ(C_ERR_OK, c_Matrix_Write(&mat, 1, 2, &t_custom)); + + // 防御防御:拦截一切非法非法越界读写 + ASSERT_INT_EQ(C_ERR_PARAM, c_Matrix_Write(&mat, 2, 0, &t_custom)); // 2行已越界 + + // 3. 验证定点读取与强值复制隔离 (Read / Get) + TransformNode_t read_res; + ASSERT_INT_EQ(C_ERR_OK, c_Matrix_Read(&mat, 1, 2, &read_res)); + ASSERT_DOUBLE_EQ_MSG(5.5f, read_res.x_scale, "Float accuracy inside matrix"); + + // 修改外部变量,内部绝对不可受到交叉污染 + t_custom.x_scale = 0.1f; + TransformNode_t* peeked = (TransformNode_t*)c_Matrix_Get(&mat, 1, 2); + ASSERT_PTR_NOT_NULL(peeked); + ASSERT_DOUBLE_EQ_MSG(5.5f, peeked->x_scale, "Verify deep value copy shield"); + + // 4. 【严苛物理断言】:验证一维行优先扁平存储的连续性 + // 在 (1行, 2列) 上的扁平一维映射偏移:Index = 1 * 3 + 2 = 5 + // 也就是说,它的物理物理实际物理首地址必须与矩阵的 data 首地址完美偏移 5 个结构体步长 + void* expected_address = (void*)((char*)mat.data + (5 * sizeof(TransformNode_t))); + ASSERT_TRUE((void*)peeked == expected_address); + + // 5. 验证高级整行高速抓取复制功能 (CopyRow) + // 我们抓取第 1 行的整行快照(包含 3 个 TransformNode_t 元素) + TransformNode_t row_dump_buffer[3]; + ASSERT_INT_EQ(C_ERR_OK, c_Matrix_CopyRow(&mat, 1, row_dump_buffer)); + + // 验证这一行里抓取出来的最后一项是不是之前写入的定制变换 + ASSERT_DOUBLE_EQ_MSG(5.5f, row_dump_buffer[2].x_scale, "Row block transmission verification"); + + c_Matrix_Destroy(&mat); +} + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +// ================================================================================================================== +// 具体类型:Double 矩阵专属算子族实现 +// ================================================================================================================== +static void double_add_op(void* out, const void* a, const void* b, void* ud) { + (void)ud; *(double*)out = *(const double*)a + *(const double*)b; +} + +static void double_sub_op(void* out, const void* a, const void* b, void* ud) { + (void)ud; *(double*)out = *(const double*)a - *(const double*)b; +} + +static void double_mul_op(void* out, const void* a, const void* b, void* ud) { + (void)ud; *(double*)out = *(const double*)a * *(const double*)b; +} + +static void double_div_op(void* out, const void* a, const void* b, void* ud) { + (void)ud; *(double*)out = *(const double*)a / *(const double*)b; +} + +static void double_neg_op(void* out, const void* in, void* ud) { + (void)ud; *(double*)out = -(*(const double*)in); +} + +// ================================================================================================================== +// 单元测试用例 +// ================================================================================================================== +TEST_CASE(test_matrix_generic_math_computations) { + c_Matrix_t A, B, C; + + // 初始化三个 2x2 的 double 矩阵 + ASSERT_INT_EQ(C_ERR_OK, c_Matrix_Init(&A, 2, 2, sizeof(double), NULL)); + ASSERT_INT_EQ(C_ERR_OK, c_Matrix_Init(&B, 2, 2, sizeof(double), NULL)); + ASSERT_INT_EQ(C_ERR_OK, c_Matrix_Init(&C, 2, 2, sizeof(double), NULL)); + + // 填充 A 矩阵数据: [2.0, 4.0] + // [6.0, 8.0] + double v_a[2][2] = {{2.0, 4.0}, {6.0, 8.0}}; + c_Matrix_Write(&A, 0, 0, &v_a[0][0]); c_Matrix_Write(&A, 0, 1, &v_a[0][1]); + c_Matrix_Write(&A, 1, 0, &v_a[1][0]); c_Matrix_Write(&A, 1, 1, &v_a[1][1]); + + // 填充 B 矩阵数据: [1.0, 2.0] + // [3.0, 4.0] + double v_b[2][2] = {{1.0, 2.0}, {3.0, 4.0}}; + c_Matrix_Write(&B, 0, 0, &v_b[0][0]); c_Matrix_Write(&B, 0, 1, &v_b[0][1]); + c_Matrix_Write(&B, 1, 0, &v_b[1][0]); c_Matrix_Write(&B, 1, 1, &v_b[1][1]); + + // ------------------------------------------------------------------------- + // 1. 测试 Element-wise 逐元素矩阵加法 + // ------------------------------------------------------------------------- + ASSERT_INT_EQ(C_ERR_OK, c_Matrix_Add(&C, &A, &B, double_add_op, NULL)); + // 结果 C 应为: [3.0, 6.0] + // [9.0, 12.0] + ASSERT_DOUBLE_EQ_MSG(3.0, *(double*)c_Matrix_Get(&C, 0, 0), "Matrix Add Cell (0,0)"); + ASSERT_DOUBLE_EQ_MSG(12.0, *(double*)c_Matrix_Get(&C, 1, 1), "Matrix Add Cell (1,1)"); + + // ------------------------------------------------------------------------- + // 2. 测试 标量乘法 (Scalar Multiplication) + // ------------------------------------------------------------------------- + double factor = 2.0; + ASSERT_INT_EQ(C_ERR_OK, c_Matrix_MulScalar(&C, &A, &factor, double_mul_op, NULL)); + // 结果 C 应为 A 的每个元素乘以 2: [4.0, 8.0] + // [12.0, 16.0] + ASSERT_DOUBLE_EQ_MSG(4.0, *(double*)c_Matrix_Get(&C, 0, 0), "Matrix Scalar Mul Cell (0,0)"); + ASSERT_DOUBLE_EQ_MSG(16.0, *(double*)c_Matrix_Get(&C, 1, 1), "Matrix Scalar Mul Cell (1,1)"); + + // ------------------------------------------------------------------------- + // 3. 测试 线性代数标准矩阵乘法 (Matrix Multiplication) + // ------------------------------------------------------------------------- + // 计算 C = A * B + // [2.0, 4.0] [1.0, 2.0] [(2*1 + 4*3), (2*2 + 4*4)] [14.0, 20.0] + // [6.0, 8.0] * [3.0, 4.0] = [(6*1 + 8*3), (6*2 + 8*4)] = [30.0, 44.0] + ASSERT_INT_EQ(C_ERR_OK, c_Matrix_Mul(&C, &A, &B, double_mul_op, double_add_op, NULL)); + + ASSERT_DOUBLE_EQ_MSG(14.0, *(double*)c_Matrix_Get(&C, 0, 0), "Matrix Mul Cell (0,0)"); + ASSERT_DOUBLE_EQ_MSG(20.0, *(double*)c_Matrix_Get(&C, 0, 1), "Matrix Mul Cell (0,1)"); + ASSERT_DOUBLE_EQ_MSG(30.0, *(double*)c_Matrix_Get(&C, 1, 0), "Matrix Mul Cell (1,0)"); + ASSERT_DOUBLE_EQ_MSG(44.0, *(double*)c_Matrix_Get(&C, 1, 1), "Matrix Mul Cell (1,1)"); + + // 4. 清理闭环 + c_Matrix_Destroy(&A); + c_Matrix_Destroy(&B); + c_Matrix_Destroy(&C); +} + +TEST_CASE(test_matrix_transpose_and_determinant_closure) { + c_Matrix_t A, A_T; + + // ------------------------------------------------------------------------- + // 1. 验证矩阵转置 (Transpose) + // ------------------------------------------------------------------------- + // 建立一个 2行 3列 的非方阵 A + ASSERT_INT_EQ(C_ERR_OK, c_Matrix_Init(&A, 2, 3, sizeof(double), NULL)); + ASSERT_INT_EQ(C_ERR_OK, c_Matrix_Init(&A_T, 3, 2, sizeof(double), NULL)); // 转置后为 3x2 + + // 填充 A 为: [1.0, 2.0, 3.0] + // [4.0, 5.0, 6.0] + double val = 1.0; + for(c_size_t r=0; r<2; r++) { + for(c_size_t c=0; c<3; c++) { + c_Matrix_Write(&A, r, c, &val); + val += 1.0; + } + } + + ASSERT_INT_EQ(C_ERR_OK, c_Matrix_Transpose(&A_T, &A)); + + // 校验转置后的几何单元: A_T 应为 [1.0, 4.0] + // [2.0, 5.0] + // [3.0, 6.0] + ASSERT_DOUBLE_EQ_MSG(1.0, *(double*)c_Matrix_Get(&A_T, 0, 0), "Transpose Cell (0,0)"); + ASSERT_DOUBLE_EQ_MSG(4.0, *(double*)c_Matrix_Get(&A_T, 0, 1), "Transpose Cell (0,1)"); + ASSERT_DOUBLE_EQ_MSG(5.0, *(double*)c_Matrix_Get(&A_T, 1, 1), "Transpose Cell (1,1)"); + ASSERT_DOUBLE_EQ_MSG(6.0, *(double*)c_Matrix_Get(&A_T, 2, 1), "Transpose Cell (2,1)"); + + c_Matrix_Destroy(&A); + c_Matrix_Destroy(&A_T); + + // ------------------------------------------------------------------------- + // 2. 验证矩阵行列式求解 (Determinant) + // ------------------------------------------------------------------------- + c_Matrix_t M; + // 建立一个 3x3 的标准双精度方阵 M + ASSERT_INT_EQ(C_ERR_OK, c_Matrix_Init(&M, 3, 3, sizeof(double), NULL)); + + // 填充方阵数据: [1.0, 2.0, 3.0] + // [0.0, 4.0, 5.0] + // [1.0, 0.0, 6.0] + // 理论行列式解算: 1*(4*6 - 5*0) - 2*(0*6 - 5*1) + 3*(0*0 - 4*1) + // = 1*(24) - 2*(-5) + 3*(-4) = 24 + 10 - 12 = 22.0 + double m_data[3][3] = { + {1.0, 2.0, 3.0}, + {0.0, 4.0, 5.0}, + {1.0, 0.0, 6.0} + }; + for(int i=0; i<3; i++) { + for(int j=0; j<3; j++) { + c_Matrix_Write(&M, i, j, &m_data[i][j]); + } + } + + double final_det = 0.0; + c_err_t det_err = c_Matrix_Determinant(&M, &final_det, + double_add_op, double_sub_op, + double_mul_op, double_neg_op, NULL); + + ASSERT_INT_EQ(C_ERR_OK, det_err); + ASSERT_DOUBLE_EQ_MSG(22.0, final_det, "Laplace Expansion Determinant Validation"); + + c_Matrix_Destroy(&M); +} + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + + +int main(void) { + TEST_START(C_Matrix_RowMajor_Layout_Tests); + RUN_TEST(test_generic_flattened_matrix_flow); + RUN_TEST(test_matrix_generic_math_computations); + RUN_TEST(test_matrix_transpose_and_determinant_closure); + TEST_REPORT(); + RETURN_TEST_STATUS; +} \ No newline at end of file diff --git a/Foundation/c_Mutex.c b/Foundation/c_Mutex.c deleted file mode 100644 index 40b3099..0000000 --- a/Foundation/c_Mutex.c +++ /dev/null @@ -1,63 +0,0 @@ -#include - -c_err_t c_Mutex_Init(c_Mutex_t* mutex) { - if (!mutex) return C_ERR_FAIL; - -#if defined(PLATFORM_WINDOWS) - // InitializeCriticalSection 不会失败,但 InitializeCriticalSectionAndSpinCount 可能会 - // 工业级推荐直接使用此 API,性能优秀 - InitializeCriticalSection(&mutex->handle); - mutex->is_initialized = C_TRUE; - return C_ERR_OK; -#elif defined(PLATFORM_POSIX) - // POSIX 默认是 PTHREAD_MUTEX_DEFAULT (不可重入锁) - if (pthread_mutex_init(&mutex->handle, NULL) == 0) { - mutex->is_initialized = C_TRUE; - return C_ERR_OK; - } - return C_ERR_FAIL; -#endif -} - -void c_Mutex_Destroy(c_Mutex_t* mutex) { - if (!mutex || !mutex->is_initialized) return; - -#if defined(PLATFORM_WINDOWS) - DeleteCriticalSection(&mutex->handle); -#elif defined(PLATFORM_POSIX) - pthread_mutex_destroy(&mutex->handle); -#endif - mutex->is_initialized = C_FALSE; -} - - -void c_Mutex_Lock(c_Mutex_t* mutex) { - if (!mutex || !mutex->is_initialized) return; -#if defined(PLATFORM_WINDOWS) - EnterCriticalSection(&mutex->handle); -#elif defined(PLATFORM_POSIX) - pthread_mutex_lock(&mutex->handle); -#endif -} - -c_bool_t c_Mutex_TryLock(c_Mutex_t* mutex) { - if (!mutex || !mutex->is_initialized) return C_FALSE; - -#if defined(PLATFORM_WINDOWS) - // TryEnterCriticalSection 返回非 0 表示成功 - return (TryEnterCriticalSection(&mutex->handle) != 0)?C_TRUE:C_FALSE; -#elif defined(PLATFORM_POSIX) - // pthread_mutex_trylock 返回 0 表示成功 - return (pthread_mutex_trylock(&mutex->handle) == 0)?C_TRUE:C_FALSE; -#endif -} - - -void c_Mutex_UnLock(c_Mutex_t* mutex) { - if (!mutex || !mutex->is_initialized) return; -#if defined(PLATFORM_WINDOWS) - LeaveCriticalSection(&mutex->handle); -#elif defined(PLATFORM_POSIX) - pthread_mutex_unlock(&mutex->handle); -#endif -} \ No newline at end of file diff --git a/Foundation/c_Mutex.h b/Foundation/c_Mutex.h deleted file mode 100644 index dd88484..0000000 --- a/Foundation/c_Mutex.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef INCLUDED_C_MUTEX_H -#define INCLUDED_C_MUTEX_H - -#ifndef INCLUDED_C_TYPES_H -#include -#endif /*INCLUDED_C_TYPES_H*/ - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -#if defined(_WIN32) || defined(_WIN64) - #define PLATFORM_WINDOWS 1 - #ifndef WIN32_LEAN_AND_MEAN - #define WIN32_LEAN_AND_MEAN - #endif - #include -#else - #define PLATFORM_POSIX 1 - #include -#endif - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -typedef struct { -#if defined(PLATFORM_WINDOWS) - CRITICAL_SECTION handle; -#elif defined(PLATFORM_POSIX) - pthread_mutex_t handle; -#endif - c_bool_t is_initialized; -} c_Mutex_t; - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -c_err_t c_Mutex_Init(c_Mutex_t* mutex); -void c_Mutex_Destroy(c_Mutex_t* mutex); -void c_Mutex_Lock(c_Mutex_t* mutex); -c_bool_t c_Mutex_TryLock(c_Mutex_t* mutex); -void c_Mutex_UnLock(c_Mutex_t* mutex); - -#endif /*INCLUDED_C_MUTEX_H*/ diff --git a/Foundation/c_PtrArrayBag.c b/Foundation/c_PtrArrayBag.c deleted file mode 100644 index 0347b2f..0000000 --- a/Foundation/c_PtrArrayBag.c +++ /dev/null @@ -1,64 +0,0 @@ -#include -#include - -#define DEFAULT_INIT_CAPACITY 4 - -c_err_t c_PtrArrayBag_Init(c_PtrArrayBag_t* self, c_size_t capacity) { - if (!self) return C_ERR_PARAM; - self->capacity = (capacity > 0) ? capacity : DEFAULT_INIT_CAPACITY; - self->size = 0; - self->array = (void**)C_ALLOC(self->capacity * sizeof(void*)); - if (!self->array) { - self->capacity = 0; - return C_ERR_NOMEM; - } - - return C_ERR_OK; -} - -void c_PtrArrayBag_Destroy(c_PtrArrayBag_t* self) { - if (!self) return; - C_FREE(self->array); - self->capacity = 0; - self->size = 0; -} - -c_err_t c_PtrArrayBag_Add(c_PtrArrayBag_t* self, void* item) { - if (!self || !self->array) return C_ERR_PARAM; - - // Handle dynamic resizing (doubling capacity) - if (self->size >= self->capacity) { - const c_size_t new_capacity = self->capacity << 1; - void** new_array = (void**)C_REALLOC(self->array, new_capacity * sizeof(void*)); - if (!new_array) { - return C_ERR_NOMEM; - } - self->array = new_array; - self->capacity = new_capacity; - } - - self->array[self->size++] = item; - return C_ERR_OK; -} - -void* c_PtrArrayBag_Get(c_PtrArrayBag_t* self, c_size_t index) { - if (!self || !self->array || index >= self->size) { - return NULL; - } - return self->array[index]; -} - -c_err_t c_PtrArrayBag_Remove(c_PtrArrayBag_t* self, c_size_t index) { - if (!self || !self->array) return C_ERR_PARAM; - if (index >= self->size) return C_ERR_OUTOFBOUND; - - // Shift elements left to fill the gap - if (index < self->size - 1) { - const c_size_t elements_to_move = self->size - index - 1; - memmove(&self->array[index], &self->array[index + 1], elements_to_move * sizeof(void*)); - } - - self->size--; - self->array[self->size] = NULL; // Optional clear for safety - return C_ERR_OK; -} diff --git a/Foundation/c_PtrArrayBag.h b/Foundation/c_PtrArrayBag.h deleted file mode 100644 index 8b1550f..0000000 --- a/Foundation/c_PtrArrayBag.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef INCLUDED_C_PTRARRAYBAG_H -#define INCLUDED_C_PTRARRAYBAG_H - -#ifndef INCLUDED_C_TYPES_H -#include -#endif /*INCLUDED_C_TYPES_H*/ - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -typedef struct { - void** array; - c_size_t capacity; - c_size_t size; -}c_PtrArrayBag_t; - -c_err_t c_PtrArrayBag_Init(c_PtrArrayBag_t* self, c_size_t capacity); - -void c_PtrArrayBag_Destroy(c_PtrArrayBag_t* self); - -c_err_t c_PtrArrayBag_Add(c_PtrArrayBag_t* self, void* item); - -void* c_PtrArrayBag_Get(c_PtrArrayBag_t* self, c_size_t index); - -c_err_t c_PtrArrayBag_Remove(c_PtrArrayBag_t* self, c_size_t index); - -#endif /*INCLUDED_C_PTRARRAYBAG_H*/ diff --git a/Foundation/c_PtrArrayBag.t.c b/Foundation/c_PtrArrayBag.t.c deleted file mode 100644 index b90960b..0000000 --- a/Foundation/c_PtrArrayBag.t.c +++ /dev/null @@ -1,98 +0,0 @@ -#include "c_PtrArrayBag.h" -#include -#include -#include - -// 輔助測試函數:印出測試進度 -void test_log(const char* test_name) { - printf("[PASS] %s\n", test_name); -} - -int main(int argc, char** argv){ - - printf("開始執行 c_PtrArrayBag 測試用例...\n\n"); - - // 模擬一些測試資料 - int val1 = 100; - int val2 = 200; - int val3 = 300; - int val4 = 400; - - // ========================================== - // 1. 測試初始化 (Init) - // ========================================== - c_PtrArrayBag_t bag; - c_err_t err = c_PtrArrayBag_Init(&bag, 2); // 故意設小容量測試動態擴容 - assert(err == C_ERR_OK); - assert(bag.capacity == 2); - assert(bag.size == 0); - assert(bag.array != NULL); - test_log("初始化測試"); - - // ========================================== - // 2. 測試新增元素與基本讀取 (Add & Get) - // ========================================== - err = c_PtrArrayBag_Add(&bag, &val1); - assert(err == C_ERR_OK); - assert(bag.size == 1); - assert(*(int*)c_PtrArrayBag_Get(&bag, 0) == 100); - - err = c_PtrArrayBag_Add(&bag, &val2); - assert(err == C_ERR_OK); - assert(bag.size == 2); - assert(*(int*)c_PtrArrayBag_Get(&bag, 1) == 200); - test_log("基本新增與讀取測試"); - - // ========================================== - // 3. 測試動態擴容 (Dynamic Resizing) - // ========================================== - // 目前 size = 2, capacity = 2。再加第 3 個元素應該要觸發容量翻倍 - err = c_PtrArrayBag_Add(&bag, &val3); - assert(err == C_ERR_OK); - assert(bag.size == 3); - assert(bag.capacity == 4); // 2 * 2 = 4 - assert(*(int*)c_PtrArrayBag_Get(&bag, 2) == 300); - test_log("自動擴容測試"); - - // ========================================== - // 4. 測試邊界與無效引數 (Edge Cases) - // ========================================== - // 讀取超出範圍的索引應該回傳 NULL - assert(c_PtrArrayBag_Get(&bag, 99) == NULL); - - // 傳入 NULL 結構指標應該要防呆 - assert(c_PtrArrayBag_Init(NULL, 10) == C_ERR_PARAM); - assert(c_PtrArrayBag_Add(NULL, &val4) == C_ERR_PARAM); - assert(c_PtrArrayBag_Remove(NULL, 0) == C_ERR_PARAM); - test_log("邊界防呆測試"); - - // ========================================== - // 5. 測試刪除元素與平移 (Remove) - // ========================================== - // 目前狀態: [100, 200, 300],刪除索引 1 (200) - // 預期結果: [100, 300],後方元素向前平移,保持順序 - err = c_PtrArrayBag_Remove(&bag, 1); - assert(err == C_ERR_OK); - assert(bag.size == 2); - - // 驗證原本索引 2 的 300 是否變成索引 1 - assert(*(int*)c_PtrArrayBag_Get(&bag, 0) == 100); - assert(*(int*)c_PtrArrayBag_Get(&bag, 1) == 300); - - // 嘗試刪除不存在的索引 - err = c_PtrArrayBag_Remove(&bag, 5); - assert(err == C_ERR_OUTOFBOUND); - test_log("刪除與元素平移測試"); - - // ========================================== - // 6. 測試銷毀與記憶體釋放 (Destroy) - // ========================================== - c_PtrArrayBag_Destroy(&bag); - assert(bag.array == NULL); - assert(bag.size == 0); - assert(bag.capacity == 0); - test_log("銷毀測試"); - - printf("\n恭喜!所有測試用例皆順利通過 (All Tests Passed)!\n"); - return 0; -} diff --git a/Foundation/c_PtrBag.c b/Foundation/c_PtrBag.c new file mode 100644 index 0000000..9a737da --- /dev/null +++ b/Foundation/c_PtrBag.c @@ -0,0 +1,123 @@ +#include + +#define DEFAULT_INITIAL_CAPACITY 4 + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +c_err_t c_PtrBag_Init(c_PtrBag_t* self, c_size_t capacity, c_Allocator_t* allocator) { + if (!self) return C_ERR_PARAM; + + self->allocator = (allocator != NULL) ? *allocator : c_DefaultAllocator; + self->size = 0; + self->capacity = (capacity > 0) ? capacity : DEFAULT_INITIAL_CAPACITY; + + // 单个 item 固定为指针大小 (sizeof(void*)) + self->array = (void**)c_Allocator_Alloc(&self->allocator, self->capacity * sizeof(void*)); + if (!self->array) return C_ERR_NOMEM; + + return C_ERR_OK; +} + +// 销毁指针袋资源(不负责释放指针所指向的对象内存) +void c_PtrBag_Destroy(c_PtrBag_t* self) { + if (!self) return; + if (self->array) { + c_Allocator_Free(&self->allocator, self->array); + self->array = NULL; + } + self->size = 0; + self->capacity = 0; +} + +// 调整容量(直接对接你最新的 Realloc 包装,闭环支持伙伴系统) +c_err_t c_PtrBag_Resize(c_PtrBag_t* self, c_size_t new_capacity) { + if (!self) return C_ERR_PARAM; + if (new_capacity == self->capacity) return C_ERR_OK; + + if (new_capacity == 0) { + if (self->array) { + c_Allocator_Free(&self->allocator, self->array); + self->array = NULL; + } + self->capacity = 0; + self->size = 0; + return C_ERR_OK; + } + + const c_size_t old_bytes = self->capacity * sizeof(void*); + const c_size_t new_bytes = new_capacity * sizeof(void*); + + void* new_array = c_Allocator_Realloc(&self->allocator, self->array, old_bytes, new_bytes); + if (!new_array) return C_ERR_NOMEM; + + self->array = (void**)new_array; + self->capacity = new_capacity; + + if (self->size > new_capacity) { + self->size = new_capacity; + } + + return C_ERR_OK; +} + +C_STATIC_FORCE_INLINE +bool c_PtrBag_EnsureCapacity(c_PtrBag_t* self) { + if (self->size < self->capacity) return true; + c_size_t new_capacity = self->capacity * 2; + return c_PtrBag_Resize(self, new_capacity) == C_ERR_OK; +} + +// 往袋子里丢一个指针 (O(1)) +c_err_t c_PtrBag_Add(c_PtrBag_t* self, void* ptr) { + if (!self || !ptr) return C_ERR_PARAM; + if (!c_PtrBag_EnsureCapacity(self)) return C_ERR_NOMEM; + + self->array[self->size++] = ptr; + return C_ERR_OK; +} + +// 检查某个指针是否在袋子中 (O(N) 扁平线性扫描) +bool c_PtrBag_Contains(const c_PtrBag_t* self, const void* ptr) { + if (!self || !ptr) return false; + for (c_size_t i = 0; i < self->size; i++) { + if (self->array[i] == ptr) return true; + } + return false; +} + +// 根据索引移除指针 (基于 Swap-and-Remove 的 O(1) 终极优化) +c_err_t c_PtrBag_RemoveAt(c_PtrBag_t* self, c_size_t index, void** out_ptr) { + if (!self || index >= self->size) return C_ERR_PARAM; + + if (out_ptr) { + *out_ptr = self->array[index]; + } + + // 核心优化点:如果移除的不是最后一个,直接用最后一个元素填坑,不需要 memmove + if (index < self->size - 1) { + self->array[index] = self->array[self->size - 1]; + } + + self->size--; + return C_ERR_OK; +} + +// 直接移除指定的指针实例 (O(1) 移除) +c_err_t c_PtrBag_Remove(c_PtrBag_t* self, void* ptr) { + if (!self || !ptr) return C_ERR_PARAM; + + for (c_size_t i = 0; i < self->size; i++) { + if (self->array[i] == ptr) { + return c_PtrBag_RemoveAt(self, i, NULL); // 复用 Swap-and-Remove 逻辑 + } + } + return C_ERR_NOTFOUND; // 假设你有定义对应的错误码,或者返回 C_ERROR +} + +// 高效清空袋子 (保持物理缓冲区容量不变,仅抹零 size 实现无开销复用) +void c_PtrBag_Clear(c_PtrBag_t* self) { + if (!self) return; + self->size = 0; +} + diff --git a/Foundation/c_PtrBag.h b/Foundation/c_PtrBag.h new file mode 100644 index 0000000..1ce4dcb --- /dev/null +++ b/Foundation/c_PtrBag.h @@ -0,0 +1,49 @@ +#ifndef INCLUDED_C_PTRBAG_H +#define INCLUDED_C_PTRBAG_H + +#ifndef INCLUDED_C_TYPES_H +#include +#endif /*INCLUDED_C_TYPES_H*/ + +#ifndef INCLUDED_C_ALLOCATOR_H +#include +#endif /*INCLUDED_C_ALLOCATOR_H*/ + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +typedef struct { + void** array; // 存储 void* 指针的连续数组(本质上还是连续线性表) + c_size_t capacity; // 当前袋子的最大指针容量 + c_size_t size; // 当前袋子中持有的有效指针个数 + c_Allocator_t allocator; // 绑定的通用内存管理器 +} c_PtrBag_t; + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +c_err_t c_PtrBag_Init(c_PtrBag_t* self, c_size_t capacity, c_Allocator_t* allocator); +void c_PtrBag_Destroy(c_PtrBag_t* self); + +// 核心指针袋操作 API +c_err_t c_PtrBag_Add(c_PtrBag_t* self, void* ptr); +c_err_t c_PtrBag_Remove(c_PtrBag_t* self, void* ptr); +c_err_t c_PtrBag_RemoveAt(c_PtrBag_t* self, c_size_t index, void** out_ptr); +bool c_PtrBag_Contains(const c_PtrBag_t* self, const void* ptr); +c_err_t c_PtrBag_Resize(c_PtrBag_t* self, c_size_t new_capacity); +void c_PtrBag_Clear(c_PtrBag_t* self); + +// 内联高频辅助接口 +C_STATIC_FORCE_INLINE +c_size_t c_PtrBag_Size(const c_PtrBag_t* self) { + if (!self) return 0; + return self->size; +} + +C_STATIC_FORCE_INLINE +void* c_PtrBag_Get(const c_PtrBag_t* self, c_size_t index) { + if (!self || index >= self->size) return NULL; + return self->array[index]; +} + +#endif /*INCLUDED_C_PTRBAG_H*/ diff --git a/Foundation/c_PtrBag.t.c b/Foundation/c_PtrBag.t.c new file mode 100644 index 0000000..29250f6 --- /dev/null +++ b/Foundation/c_PtrBag.t.c @@ -0,0 +1,64 @@ +#include "c_PtrBag.h" +#include "c_Test.h" + + +TEST_CASE(test_ptr_bag_basic_and_optimization) { + c_PtrBag_t bag; + + // 初始化一个初始容量为 3 的指针袋 + ASSERT_INT_EQ(C_ERR_OK, c_PtrBag_Init(&bag, 3, NULL)); + + // 模拟三个异构结构体的实体对象(可以是完全不同的类型) + int dummy_entity_a = 100; + float dummy_entity_b = 200.0f; + char* dummy_entity_c = "EntityC"; + int dummy_entity_d = 400; // 用于触发自动扩容 + + // 1. 添加指针测试 + ASSERT_INT_EQ(C_ERR_OK, c_PtrBag_Add(&bag, &dummy_entity_a)); + ASSERT_INT_EQ(C_ERR_OK, c_PtrBag_Add(&bag, &dummy_entity_b)); + ASSERT_INT_EQ(C_ERR_OK, c_PtrBag_Add(&bag, &dummy_entity_c)); + ASSERT_INT_EQ(3, c_PtrBag_Size(&bag)); + + // 2. 自动扩容验证 + ASSERT_INT_EQ(C_ERR_OK, c_PtrBag_Add(&bag, &dummy_entity_d)); // 触发 3 -> 6 扩容 + ASSERT_INT_EQ(6, bag.capacity); + + // 3. 包含性检查 (Contains) + ASSERT_TRUE(c_PtrBag_Contains(&bag, &dummy_entity_b)); + ASSERT_TRUE(!c_PtrBag_Contains(&bag, NULL)); + + // 4. CRITICAL:验证 Swap-and-Remove 的 $O(1)$ 正确性 + // 当前顺序:[0]:&a, [1]:&b, [2]:&c, [3]:&d + // 我们强制移除索引 1 处的 &b + void* popped_ptr = NULL; + ASSERT_INT_EQ(C_ERR_OK, c_PtrBag_RemoveAt(&bag, 1, &popped_ptr)); + + // 验证拷出的指针确实是 b + ASSERT_TRUE(popped_ptr == &dummy_entity_b); + ASSERT_INT_EQ(3, c_PtrBag_Size(&bag)); + + // 严苛验证无序替换:原来的最后一个元素 &d 应该被移到了索引 1 处 + ASSERT_TRUE(c_PtrBag_Get(&bag, 0) == &dummy_entity_a); + ASSERT_TRUE(c_PtrBag_Get(&bag, 1) == &dummy_entity_d); // &d 顶替了 &b 的坑位! + ASSERT_TRUE(c_PtrBag_Get(&bag, 2) == &dummy_entity_c); + + // 5. 直接按指针实例移除测试 + ASSERT_INT_EQ(C_ERR_OK, c_PtrBag_Remove(&bag, &dummy_entity_a)); + ASSERT_TRUE(!c_PtrBag_Contains(&bag, &dummy_entity_a)); + ASSERT_INT_EQ(2, c_PtrBag_Size(&bag)); + + // 6. 清空与复用测试 + c_PtrBag_Clear(&bag); + ASSERT_INT_EQ(0, c_PtrBag_Size(&bag)); + ASSERT_INT_EQ(6, bag.capacity); // 缓冲区未被释放 + + c_PtrBag_Destroy(&bag); +} + +int main(void) { + TEST_START(C_PtrBag_Module_Tests); + RUN_TEST(test_ptr_bag_basic_and_optimization); + TEST_REPORT(); + RETURN_TEST_STATUS; +} diff --git a/Foundation/c_PtrLinkBag.c b/Foundation/c_PtrLinkBag.c index 4283864..b0a0d42 100644 --- a/Foundation/c_PtrLinkBag.c +++ b/Foundation/c_PtrLinkBag.c @@ -1,65 +1,69 @@ #include -#include -c_err_t c_PtrLinkBag_Init(c_PtrLinkBag_t* self) { + + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +// 原地初始化:绑定分配器并建立哑哨兵头节点 +c_err_t c_PtrLinkBag_Init(c_PtrLinkBag_t* self, c_Allocator_t* allocator) { if (!self) return C_ERR_PARAM; - self->head= NULL; + + // 内置绑定:如果传入 NULL,无缝降级为系统默认分配器 + self->allocator = (allocator != NULL) ? *allocator : c_DefaultAllocator; + self->size = 0; + self->head = 0; return C_ERR_OK; } -void c_PtrLinkBag_Destroy(c_PtrLinkBag_t* self) { - if (!self) return; - c_PtrLinkBagNode_t* p = self->head; - while (p) { - c_PtrLinkBagNode_t* q = p->next; - C_FREE(p); - p = q; - } - self->head = NULL; +// 快速头插法 (真正的 O(1) 尾部或头部无抖动挂载) +c_PtrLinkNode_t* c_PtrLinkBag_Add(c_PtrLinkBag_t* self, void* ptr) { + if (!self || !ptr) return NULL; + + // 内部闭环调用自身的内置管理器 + c_PtrLinkNode_t* new_node = (c_PtrLinkNode_t*)c_Allocator_Alloc(&self->allocator, sizeof(c_PtrLinkNode_t)); + if (!new_node) return NULL; + + new_node->ptr = ptr; + new_node->next = self->head; + self->head = new_node; + + self->size++; + return new_node; } -c_err_t c_PtrLinkBag_Add(c_PtrLinkBag_t* self, void* item) { - if (!self) return C_ERR_PARAM; - c_PtrLinkBagNode_t* p; - C_NEW(p); - if (!p) { - return C_ERR_NOMEM; - } - p->ptr = item; - p->next = self->head; - self->head = p; - return C_ERR_OK; -} +// 基于二级指针的自主安全裁剪 (O(N) 线性过滤) +c_err_t c_PtrLinkBag_Remove(c_PtrLinkBag_t* self, void* ptr) { + if (!self || !self->head || !ptr) return C_ERR_PARAM; -c_err_t c_PtrLinkBag_Remove(c_PtrLinkBag_t* self, const void* item) { - if (!self) return C_ERR_PARAM; - c_PtrLinkBagNode_t** curr = &self->head; - while (*curr != NULL) { - if ((*curr)->ptr == item) { - c_PtrLinkBagNode_t* entry = *curr; - *curr = entry->next; - C_FREE(entry); + // 二级指针指向 Dummy Head 的下一个节点指针坑位物理地址 + c_PtrLinkNode_t** pp = &(self->head->next); + + while (*pp != NULL) { + c_PtrLinkNode_t* entry = *pp; + if (entry->ptr == ptr) { + // 精妙裁剪:前驱节点的 next 直接指去被删节点的下一跳 + *pp = entry->next; + + // 内部自主物理销毁,账实同步 + c_Allocator_Free(&self->allocator, entry); + self->size--; return C_ERR_OK; } - curr = &(*curr)->next; + pp = &(entry->next); } - return C_ERR_NOTFOUND; } -void c_PtrLinkBagIter_Remove(c_PtrLinkBagIter_t* self) { - // 防呆檢查:確保迭代器有效,且當前指向的節點不為空 - if (!self || !self->node || !*(self->node)) return; - c_PtrLinkBagNode_t* to_delete = *(self->node); +// 彻底解体 +void c_PtrLinkBag_Destroy(c_PtrLinkBag_t* self) { + if (!self) return; - // 將當前結構中維護的指標(可能是上一節點的 next,或是 bag 的 head) - // 修改為指向下一個節點,直接從鏈結串列中斷開 - *(self->node) = to_delete->next; - - // 釋放記憶體 - C_FREE(to_delete); - - // 注意:此時 self->node 自動更新指向了原本的下一個節點 - // 使用者不需要再呼叫 Next(),即可直接對新節點進行 Get() 或再次 Remove() + while (self->head != NULL) { + c_PtrLinkNode_t* entry = self->head; + self->head = entry->next; + c_Allocator_Free(&self->allocator, entry); + } } + diff --git a/Foundation/c_PtrLinkBag.h b/Foundation/c_PtrLinkBag.h index 1bfaf45..9c72e97 100644 --- a/Foundation/c_PtrLinkBag.h +++ b/Foundation/c_PtrLinkBag.h @@ -5,58 +5,110 @@ #include #endif /*INCLUDED_C_TYPES_H*/ +#ifndef INCLUDED_C_ALLOCATOR_H +#include +#endif /*INCLUDED_C_ALLOCATOR_H*/ +#include "c_PtrBag.h" + /* ------------------------------------------------------------------------------------------------------------------ */ /* */ -typedef struct c_PtrLinkBagNode_t { +typedef struct c_PtrLinkNode_t { void* ptr; - struct c_PtrLinkBagNode_t* next; -}c_PtrLinkBagNode_t; + struct c_PtrLinkNode_t* next; +}c_PtrLinkNode_t; typedef struct { - c_PtrLinkBagNode_t* head; + c_PtrLinkNode_t* head; + c_size_t size; + c_Allocator_t allocator; }c_PtrLinkBag_t; typedef struct { - c_PtrLinkBag_t* bag; - c_PtrLinkBagNode_t** node; -}c_PtrLinkBagIter_t; + c_PtrLinkBag_t* bag; // 绑定的非 const 宿主袋子控制头,自主提取内置 allocator 并联动 size + c_PtrLinkNode_t** pp; // 二级指针灵魂:前驱 next 指针域内存地址的直接隐射 +} c_PtrLinkBagIter_t; -c_err_t c_PtrLinkBag_Init(c_PtrLinkBag_t* self); +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ -void c_PtrLinkBag_Destroy(c_PtrLinkBag_t* self); +c_err_t c_PtrLinkBag_Init(c_PtrLinkBag_t* self, c_Allocator_t* allocator); +void c_PtrLinkBag_Destroy(c_PtrLinkBag_t* self); -c_err_t c_PtrLinkBag_Add(c_PtrLinkBag_t* self, void* item); +c_PtrLinkNode_t* c_PtrLinkBag_Add(c_PtrLinkBag_t* self, void* ptr); +c_err_t c_PtrLinkBag_Remove(c_PtrLinkBag_t* self, void* ptr); -c_err_t c_PtrLinkBag_Remove(c_PtrLinkBag_t* self, const void* item); +// C_STATIC_FORCE_INLINE 极致高频内联提速接口 +C_STATIC_FORCE_INLINE +c_size_t c_PtrLinkBag_Size(const c_PtrLinkBag_t* self) { + if (!self) return 0; + return self->size; // 真正的实时 O(1) 返回 +} + +C_STATIC_FORCE_INLINE +bool c_PtrLinkBag_IsEmpty(const c_PtrLinkBag_t* self) { + return c_PtrLinkBag_Size(self) == 0; +} + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ C_STATIC_FORCE_INLINE void c_PtrLinkBagIter_Init(c_PtrLinkBagIter_t* self, c_PtrLinkBag_t* bag) { - if (!self || !bag) return; + if (!self) return; self->bag = bag; - self->node = &bag->head; + if (!bag || !bag->head) { + self->pp = NULL; + return; + } + // 二级指针初始死死咬定宿主 Dummy Head 内部的 next 指针域 + self->pp = &(bag->head); } C_STATIC_FORCE_INLINE -c_bool_t c_PtrLinkBagIter_HasNext(c_PtrLinkBagIter_t* self) { - if (!self) return C_FALSE; - return (self->node!=NULL) && (*(self->node)!=NULL); -} - -C_STATIC_FORCE_INLINE -void* c_PtrLinkBagIter_Next(c_PtrLinkBagIter_t* self) { - if (!self || !self->node) return NULL; - void* ptr = (*(self->node))->ptr; - self->node = &(*(self->node))->next; - return ptr; +bool c_PtrLinkBagIter_HasNext(const c_PtrLinkBagIter_t* self) { + return (self != NULL && self->pp != NULL && *self->pp != NULL); } C_STATIC_FORCE_INLINE void* c_PtrLinkBagIter_Get(c_PtrLinkBagIter_t* self) { - if (!self || !self->node) return NULL; - return (*(self->node))->ptr; + if (!c_PtrLinkBagIter_HasNext(self)) return NULL; + return (*self->pp)->ptr; // 只读窥探数据,绝对不产生位移副作用 } -void c_PtrLinkBagIter_Remove(c_PtrLinkBagIter_t* self); +C_STATIC_FORCE_INLINE +void* c_PtrLinkBagIter_Next(c_PtrLinkBagIter_t* self) { + if (!c_PtrLinkBagIter_HasNext(self)) return NULL; + + void* user_data = (*self->pp)->ptr; + // 顺理成章地推进二级指针到当前节点的 next 域内存坑位地址上 + self->pp = &((*self->pp)->next); + + return user_data; +} + +/** + * @brief 极致防跑飞的 100% 内部自主闭环擦除接口 (完美免疫 SIGSEGV 段错误异常) + */ +C_STATIC_FORCE_INLINE +void c_PtrLinkBagIter_Remove(c_PtrLinkBagIter_t* self) { + // 强御级边界拦截:粉碎一切高危越界或失效呼叫 + if (!c_PtrLinkBagIter_HasNext(self) || !self->bag) return; + + c_PtrLinkBag_t* host_bag = self->bag; + + // 1. 通过局部临时的栈变量把当前即将解体释放的单链表包装壳锁死 + c_PtrLinkNode_t* node_to_free = *self->pp; + + // 2. 二级指针惊绝裁剪:修改前驱 next 指针的值,令其直跳到目标节点的下一跳位置 + // 在修改的这一微秒内,*self->pp 天然等同并对齐到了新一任有效节点,迭代状态干净地自我康复 + *self->pp = node_to_free->next; + + // 3. 【内部自主化闭环】:利用宿主内置的 allocator,物理退还该节点外壳,干净利落 + c_Allocator_Free(&host_bag->allocator, node_to_free); + + // 4. 联动宿主袋子将计数器实时压减,做到账实相符 + host_bag->size--; +} #endif /*INCLUDED_C_PTRLINKBAG_H*/ diff --git a/Foundation/c_PtrLinkBag.t.c b/Foundation/c_PtrLinkBag.t.c index b24d1be..37646a8 100644 --- a/Foundation/c_PtrLinkBag.t.c +++ b/Foundation/c_PtrLinkBag.t.c @@ -1,61 +1,74 @@ #include "c_PtrLinkBag.h" #include #include -#include +#include "c_Test.h" -int main(int argc, char** argv){ - printf("開始執行 c_PtrLinkBag 測試...\n"); - c_PtrLinkBag_t bag; - c_PtrLinkBag_Init(&bag); +typedef struct { + int socket_fd; + int is_timeout; +} Connection_t; - int v1 = 10, v2 = 20, v3 = 30; +TEST_CASE(test_fully_encapsulated_singly_link_bag_and_iter) { + c_PtrLinkBag_t conn_bag; - // 1. 測試新增 (使用頭插法,順序會是 30 -> 20 -> 10) - c_PtrLinkBag_Add(&bag, &v1); - c_PtrLinkBag_Add(&bag, &v2); - c_PtrLinkBag_Add(&bag, &v3); + // 1. 原地初始化:不需要像以前那样在后续高频手工传递外部内存池,API 极其干净 + ASSERT_INT_EQ(C_ERR_OK, c_PtrLinkBag_Init(&conn_bag, NULL)); + ASSERT_TRUE(c_PtrLinkBag_IsEmpty(&conn_bag)); + ASSERT_INT_EQ(0, c_PtrLinkBag_Size(&conn_bag)); - // 2. 測試走訪 - c_PtrLinkBagIter_t iter; - c_PtrLinkBagIter_Init(&iter, &bag); + // 2. 模拟挂载 4 个异构的连接 + Connection_t c1 = { .socket_fd = 80, .is_timeout = 0 }; + Connection_t c2 = { .socket_fd = 443, .is_timeout = 1 }; // 已超时死连接 + Connection_t c3 = { .socket_fd = 22, .is_timeout = 1 }; // 已超时死连接,双重死接连最考验迭代器稳定性 + Connection_t c4 = { .socket_fd = 8080,.is_timeout = 0 }; - printf("目前鏈結串列內容: "); - while (c_PtrLinkBagIter_HasNext(&iter)) { - int* val = (int*)c_PtrLinkBagIter_Next(&iter); - printf("%d ", *val); - } - printf("\n"); + // 内部闭环驱动 Add 操作 + c_PtrLinkBag_Add(&conn_bag, &c1); + c_PtrLinkBag_Add(&conn_bag, &c2); + c_PtrLinkBag_Add(&conn_bag, &c3); + c_PtrLinkBag_Add(&conn_bag, &c4); - // 3. 測試在迭代過程中刪除特定元素 (例如刪除 20) - c_PtrLinkBagIter_Init(&iter, &bag); - while (c_PtrLinkBagIter_HasNext(&iter)) { - int* val = (int*)c_PtrLinkBagIter_Get(&iter); - if (*val == 20) { - c_PtrLinkBagIter_Remove(&iter); // 刪除 20,iter->node 自動指向 10 - printf("[Log] 迭代器成功刪除了 20\n"); - } else { - c_PtrLinkBagIter_Next(&iter); // 沒刪除時才手動前進 + // 验证实时计数 O(1) + ASSERT_INT_EQ(4, c_PtrLinkBag_Size(&conn_bag)); + + // 3. 启动自主滑移闭环迭代器清理死物理连接 + c_PtrLinkBagIter_t it; + c_PtrLinkBagIter_Init(&it, &conn_bag); + + int touch_count = 0; + + while (c_PtrLinkBagIter_HasNext(&it)) { + Connection_t* current_conn = (Connection_t*)c_PtrLinkBagIter_Get(&it); + ASSERT_PTR_NOT_NULL(current_conn); + ++touch_count; + + if (current_conn->is_timeout) { + // 自主 Remove 绝招:拓扑裁切、自主寻找宿主内置的 allocator 进行物理 free、联动宿主计数降级 + c_PtrLinkBagIter_Remove(&it); + + // 迭代器已自动优雅对齐到原本的下一跳,补 continue 防止循环逻辑手动滑飞 + continue; } + + c_PtrLinkBagIter_Next(&it); } - // 4. 驗證刪除後的背包內容 (預期只剩 30 -> 10) - c_PtrLinkBagIter_Init(&iter, &bag); - assert(*(int*)c_PtrLinkBagIter_Next(&iter) == 30); - assert(*(int*)c_PtrLinkBagIter_Next(&iter) == 10); - assert(c_PtrLinkBagIter_HasNext(&iter) == C_FALSE); + // 4. 一致性终审 + ASSERT_INT_EQ(4, touch_count); // 确认全量 4 个元素都在时空里触碰过 + ASSERT_INT_EQ(2, c_PtrLinkBag_Size(&conn_bag)); // 账实完全相符,死连接被剔除清算 - // 5. 測試一般刪除 (Remove) - c_err_t err = c_PtrLinkBag_Remove(&bag, &v3); - assert(err == C_ERR_OK); + // 链表拓扑彻底对齐与完整性校验(由于头插法,排列为 Head -> c4 -> c1 -> NULL) + ASSERT_TRUE(conn_bag.head->ptr == &c4); + ASSERT_TRUE(conn_bag.head->next->ptr == &c1); // c3 和 c2 的包装节点壳已被内置管理器物理火化 + ASSERT_TRUE(conn_bag.head->next->next == NULL); // 完美谢幕! - // 檢查是不是只剩 10 - c_PtrLinkBagIter_Init(&iter, &bag); - assert(*(int*)c_PtrLinkBagIter_Get(&iter) == 10); + c_PtrLinkBag_Destroy(&conn_bag); +} - // 清除記憶體 - c_PtrLinkBag_Destroy(&bag); - printf("所有測試成功通過!\n"); - - return 0; +int main(void) { + TEST_START(C_Fully_Encapsulated_Singly_Link_Bag_System_Tests); + RUN_TEST(test_fully_encapsulated_singly_link_bag_and_iter); + TEST_REPORT(); + RETURN_TEST_STATUS; } diff --git a/Foundation/c_RBTree.c b/Foundation/c_RBTree.c deleted file mode 100644 index db25597..0000000 --- a/Foundation/c_RBTree.c +++ /dev/null @@ -1,321 +0,0 @@ -#include -#include -#include "c_Macros.h" - -// Internal Helper: Allocates structural payload node properties -C_STATIC_FORCE_INLINE -c_RBTreeNode_t* create_node(c_RBTree_t* self, void* obj) { - int size = (int)sizeof(c_RBTreeNode_t) + self->obj_size; - size = C_ALIGN_UPB(size, C_ALIGN_SIZE); - - c_RBTreeNode_t* node = (c_RBTreeNode_t*)C_ALLOC(size); - if (!node) return NULL; - node->data = node + 1; - - memcpy(node->data, obj, self->obj_size); - node->left = self->nil; - node->right = self->nil; - node->parent = self->nil; - node->color = C_RBTREE_RED; - return node; -} - - -static void destroy_recursive(c_RBTree_t* self, c_RBTreeNode_t* node) { - if (node == self->nil || node == NULL) return; - destroy_recursive(self, node->left); - destroy_recursive(self, node->right); - C_FREE(node); -} - - -// Tree Rotation Helpers -C_STATIC_FORCE_INLINE -void left_rotate(c_RBTree_t* self, c_RBTreeNode_t* x) { - c_RBTreeNode_t* y = x->right; - x->right = y->left; - if (y->left != self->nil) y->left->parent = x; - y->parent = x->parent; - if (x->parent == self->nil) self->root = y; - else if (x == x->parent->left) x->parent->left = y; - else x->parent->right = y; - y->left = x; - x->parent = y; -} - -C_STATIC_FORCE_INLINE -void right_rotate(c_RBTree_t* self, c_RBTreeNode_t* y) { - c_RBTreeNode_t* x = y->left; - y->left = x->right; - if (x->right != self->nil) x->right->parent = y; - x->parent = y->parent; - if (y->parent == self->nil) self->root = x; - else if (y == y->parent->right) y->parent->right = x; - else y->parent->left = x; - x->right = y; - y->parent = x; -} - -// Balance adjustments post standard insert passes -static void insert_fixup(c_RBTree_t* self, c_RBTreeNode_t* z) { - while (z->parent->color == C_RBTREE_RED) { - if (z->parent == z->parent->parent->left) { - c_RBTreeNode_t* y = z->parent->parent->right; - if (y->color == C_RBTREE_RED) { - z->parent->color = C_RBTREE_BLACK; - y->color = C_RBTREE_BLACK; - z->parent->parent->color = C_RBTREE_RED; - z = z->parent->parent; - } else { - if (z == z->parent->right) { - z = z->parent; - left_rotate(self, z); - } - z->parent->color = C_RBTREE_BLACK; - z->parent->parent->color = C_RBTREE_RED; - right_rotate(self, z->parent->parent); - } - } else { - c_RBTreeNode_t* y = z->parent->parent->left; - if (y->color == C_RBTREE_RED) { - z->parent->color = C_RBTREE_BLACK; - y->color = C_RBTREE_BLACK; - z->parent->parent->color = C_RBTREE_RED; - z = z->parent->parent; - } else { - if (z == z->parent->left) { - z = z->parent; - right_rotate(self, z); - } - z->parent->color = C_RBTREE_BLACK; - z->parent->parent->color = C_RBTREE_RED; - left_rotate(self, z->parent->parent); - } - } - } - self->root->color = C_RBTREE_BLACK; -} - - -static void inorder_recursive(c_RBTree_t* self, c_RBTreeNode_t* node, c_RBTree_Visit_f visit, void* cl) { - if (node == self->nil || node == NULL) return; - inorder_recursive(self, node->left, visit, cl); - visit(node->data, cl); - inorder_recursive(self, node->right, visit, cl); -} - -C_STATIC_FORCE_INLINE -void rb_transplant(c_RBTree_t* self, c_RBTreeNode_t* u, c_RBTreeNode_t* v) { - if (u->parent == self->nil) { - self->root = v; - } else if (u == u->parent->left) { - u->parent->left = v; - } else { - u->parent->right = v; - } - v->parent = u->parent; -} - -// 內部輔助函數:尋找子樹中的最小節點(用於刪除時尋找後繼節點) -C_STATIC_FORCE_INLINE -c_RBTreeNode_t* rb_tree_minimum(c_RBTree_t* self, c_RBTreeNode_t* node) { - while (node->left != self->nil) { - node = node->left; - } - return node; -} - -static void remove_fixup(c_RBTree_t* self, c_RBTreeNode_t* x) { - while (x != self->root && x->color == C_RBTREE_BLACK) { - if (x == x->parent->left) { - c_RBTreeNode_t* w = x->parent->right; // x 的兄弟節點 - - // 狀況 1:兄弟節點 w 是紅色 - if (w->color == C_RBTREE_RED) { - w->color = C_RBTREE_BLACK; - x->parent->color = C_RBTREE_RED; - left_rotate(self, x->parent); - w = x->parent->right; - } - - // 狀況 2:兄弟節點 w 是黑色,且其兩個子節點也都是黑色 - if (w->left->color == C_RBTREE_BLACK && w->right->color == C_RBTREE_BLACK) { - w->color = C_RBTREE_RED; - x = x->parent; - } else { - // 狀況 3:兄弟節點 w 是黑色,w 的右子是黑色,左子是紅色 - if (w->right->color == C_RBTREE_BLACK) { - w->left->color = C_RBTREE_BLACK; - w->color = C_RBTREE_RED; - right_rotate(self, w); - w = x->parent->right; - } - // 狀況 4:兄弟節點 w 是黑色,且 w 的右子是紅色 - w->color = x->parent->color; - x->parent->color = C_RBTREE_BLACK; - w->right->color = C_RBTREE_BLACK; - left_rotate(self, x->parent); - x = self->root; // 結束循環 - } - } else { - // 對稱狀況:x 是其父節點的右子 - c_RBTreeNode_t* w = x->parent->left; - if (w->color == C_RBTREE_RED) { - w->color = C_RBTREE_BLACK; - x->parent->color = C_RBTREE_RED; - right_rotate(self, x->parent); - w = x->parent->left; - } - if (w->right->color == C_RBTREE_BLACK && w->left->color == C_RBTREE_BLACK) { - w->color = C_RBTREE_RED; - x = x->parent; - } else { - if (w->left->color == C_RBTREE_BLACK) { - w->right->color = C_RBTREE_BLACK; - w->color = C_RBTREE_RED; - left_rotate(self, w); - w = x->parent->left; - } - w->color = x->parent->color; - x->parent->color = C_RBTREE_BLACK; - w->left->color = C_RBTREE_BLACK; - right_rotate(self, x->parent); - x = self->root; - } - } - } - x->color = C_RBTREE_BLACK; -} - - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - - -c_err_t c_RBTree_Init(c_RBTree_t* self, int obj_size, c_RBTree_Compare_f compare) { - if (!self || obj_size <= 0 || !compare) return C_ERR_PARAM; - - // Allocate an explicit shared Sentinel NIL node boundary properties - self->nil = (c_RBTreeNode_t*)C_ALLOC(sizeof(c_RBTreeNode_t)); - if (!self->nil) return C_ERR_NOMEM; - self->nil->data = NULL; - self->nil->color = C_RBTREE_BLACK; - self->nil->left = NULL; - self->nil->right = NULL; - self->nil->parent = NULL; - - self->root = self->nil; - self->obj_size = obj_size; - self->size = 0; - self->compare = compare; - return C_ERR_OK; -} - -void c_RBTree_Destroy(c_RBTree_t* self) { - if (!self) return; - destroy_recursive(self, self->root); - C_FREE(self->nil); - self->root = NULL; - self->size = 0; -} - - -c_err_t c_RBTree_Insert(c_RBTree_t* self, void* obj) { - if (!self || !obj) return C_ERR_PARAM; - - c_RBTreeNode_t* y = self->nil; - c_RBTreeNode_t* x = self->root; - int cmp = 0; - - while (x != self->nil) { - y = x; - cmp = self->compare(obj, x->data); - if (cmp == 0) return C_ERR_ALREADY_EXISTS; // Unique constraints protection - else if (cmp < 0) x = x->left; - else x = x->right; - } - - c_RBTreeNode_t* z = create_node(self, obj); - if (!z) return C_ERR_NOMEM; - z->parent = y; - - if (y == self->nil) self->root = z; - else if (self->compare(z->data, y->data) < 0) y->left = z; - else y->right = z; - - insert_fixup(self, z); - self->size++; - return C_ERR_OK; -} - -void* c_RBTree_Find(c_RBTree_t* self, const void* key_target) { - if (!self || !key_target) return NULL; - c_RBTreeNode_t* x = self->root; - while (x != self->nil) { - int cmp = self->compare(key_target, x->data); - if (cmp == 0) return x->data; - x = (cmp < 0) ? x->left : x->right; - } - return NULL; -} - -void c_RBTree_InOrder(c_RBTree_t* self, c_RBTree_Visit_f visit, void* cl) { - if (!self || !visit) return; - inorder_recursive(self, self->root, visit, cl); -} - -c_err_t c_RBTree_Remove(c_RBTree_t* self, void* obj) { - if (!self || !obj) return C_ERR_PARAM; - - // 1. 先尋找目標節點是否存在 - c_RBTreeNode_t* z = self->root; - while (z != self->nil) { - int cmp = self->compare(obj, z->data); - if (cmp == 0) break; - z = (cmp < 0) ? z->left : z->right; - } - - if (z == self->nil) return C_ERR_NOTFOUND; // 節點不存在 - - c_RBTreeNode_t* y = z; - c_RBTreeNode_t* x; - c_RBTreeColor_t y_original_color = y->color; - - // 2. 執行標準二元搜尋樹刪除與移植 - if (z->left == self->nil) { - x = z->right; - rb_transplant(self, z, z->right); - } else if (z->right == self->nil) { - x = z->left; - rb_transplant(self, z, z->left); - } else { - // z 有兩個子節點,尋找其右子樹的最小節點作為後繼者 y - y = rb_tree_minimum(self, z->right); - y_original_color = y->color; - x = y->right; - - if (y->parent == z) { - x->parent = y; // 如果 y 剛好是 z 的直接右子,建立與 nil 的 parent 關係 - } else { - rb_transplant(self, y, y->right); - y->right = z->right; - y->right->parent = y; - } - - rb_transplant(self, z, y); - y->left = z->left; - y->left->parent = y; - y->color = z->color; - } - - // 釋放被刪除節點的記憶體 - C_FREE(z); - self->size--; - - // 3. 如果失去的節點顏色是黑色,會破壞黑高平衡,必須呼叫修復狀態機 - if (y_original_color == C_RBTREE_BLACK) { - remove_fixup(self, x); - } - - return C_ERR_OK; -} diff --git a/Foundation/c_RBTree.h b/Foundation/c_RBTree.h deleted file mode 100644 index b45a5dd..0000000 --- a/Foundation/c_RBTree.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef INCLUDED_C_RBTREE_H -#define INCLUDED_C_RBTREE_H - -#ifndef INCLUDED_C_TYPES_H -#include -#endif /*INCLUDED_C_TYPES_H*/ - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -typedef enum { - C_RBTREE_RED, - C_RBTREE_BLACK -} c_RBTreeColor_t; - -typedef struct c_RBTreeNode_t { - void* data; - c_RBTreeColor_t color; - struct c_RBTreeNode_t* left; - struct c_RBTreeNode_t* right; - struct c_RBTreeNode_t* parent; -} c_RBTreeNode_t; - -// User Comparison Callback Signature: Returns <0 if a < b, 0 if a == b, >0 if a > b -typedef int (*c_RBTree_Compare_f)(const void* a, const void* b); - -// User Visitor Callback Signature for Traversals -typedef void (*c_RBTree_Visit_f)(void* data, void* cl); - -typedef struct { - c_RBTreeNode_t* root; - c_RBTreeNode_t* nil; // Sentinal node representing leaf nodes to simplify rotation math - int obj_size; - c_size_t size; - c_RBTree_Compare_f compare; -} c_RBTree_t; - -c_err_t c_RBTree_Init(c_RBTree_t* self, int obj_size, c_RBTree_Compare_f compare); -void c_RBTree_Destroy(c_RBTree_t* self); - -c_err_t c_RBTree_Insert(c_RBTree_t* self, void* obj); -c_err_t c_RBTree_Remove(c_RBTree_t* self, void* obj); -void* c_RBTree_Find(c_RBTree_t* self, const void* key_target); - -void c_RBTree_InOrder(c_RBTree_t* self, c_RBTree_Visit_f visit, void* cl); - - -#endif /*INCLUDED_C_RBTREE_H*/ diff --git a/Foundation/c_RBTree.t.c b/Foundation/c_RBTree.t.c deleted file mode 100644 index 1a4f1f0..0000000 --- a/Foundation/c_RBTree.t.c +++ /dev/null @@ -1,92 +0,0 @@ -#include "c_RBTree.h" -#include -#include -#include - -typedef struct { - int id; - char name[32]; -} Task_t; - -// 比較回呼函數 -int compare_tasks(const void* a, const void* b) { - return (((Task_t*)a)->id - ((Task_t*)b)->id); -} - -// 走訪時驗證遞增順序 -int g_last_id = -1; -void visit_verify(void* data, void* cl) { - Task_t* t = (Task_t*)data; - assert(t->id > g_last_id); // 必須嚴格遞增 - g_last_id = t->id; -} - -void test_log(const char* name) { - printf("[PASS] %s\n", name); -} - -int main() { - printf("==================================================\n"); - printf(" 開始執行 c_RBTree (含 O(log N) Remove) 最終整合測試\n"); - printf("==================================================\n\n"); - - c_RBTree_t tree; - c_RBTree_Init(&tree, sizeof(Task_t), compare_tasks); - - Task_t tasks[] = { - {40, "Task_40"}, {20, "Task_20"}, {60, "Task_60"}, - {10, "Task_10"}, {30, "Task_30"}, {50, "Task_50"}, {70, "Task_70"} - }; - - // 1. 批次推入資料 - for (int i = 0; i < 7; i++) { - c_RBTree_Insert(&tree, &tasks[i]); - } - assert(tree.size == 7); - test_log("1. 批次推入 7 筆資料成功"); - - // ========================================== - // 2. 測試刪除葉子節點 (Task 10) - // ========================================== - Task_t target = {10, ""}; - c_err_t err = c_RBTree_Remove(&tree, &target); - assert(err == C_ERR_OK); - assert(tree.size == 6); - assert(c_RBTree_Find(&tree, &target) == NULL); // 預期找不到 - - // 驗證刪除後的結構順序性 - g_last_id = -1; - c_RBTree_InOrder(&tree, visit_verify, NULL); - test_log("2. 成功刪除葉子節點 (10) 且中序走訪維持平衡有序"); - - // ========================================== - // 3. 測試刪除擁有多個子節點的核心根節點 (Task 40) - // ========================================== - target.id = 40; - err = c_RBTree_Remove(&tree, &target); - assert(err == C_ERR_OK); - assert(tree.size == 5); - assert(c_RBTree_Find(&tree, &target) == NULL); - - // 再次驗證刪除後的結構順序性 - g_last_id = -1; - c_RBTree_InOrder(&tree, visit_verify, NULL); - test_log("3. 成功刪除雙子核心節點 (40) 且平衡移植狀態正確"); - - // ========================================== - // 4. 刪除不存在的鍵值與無效參數防呆 - // ========================================== - target.id = 999; - assert(c_RBTree_Remove(&tree, &target) == C_ERR_NOTFOUND); - assert(c_RBTree_Remove(NULL, &target) == C_ERR_PARAM); - test_log("4. 刪除越界與無效引數防呆驗證成功"); - - c_RBTree_Destroy(&tree); - test_log("5. 紅黑樹資源徹底銷毀成功"); - - printf("\n==================================================\n"); - printf(" 恭喜!包含 O(log N) Remove 在內的所有紅黑樹單元測試完美通過!\n"); - printf("==================================================\n"); - - return 0; -} \ No newline at end of file diff --git a/Foundation/c_SmartPtr.c b/Foundation/c_SmartPtr.c deleted file mode 100644 index 5b446b4..0000000 --- a/Foundation/c_SmartPtr.c +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/Foundation/c_SmartPtr.h b/Foundation/c_SmartPtr.h deleted file mode 100644 index c14f069..0000000 --- a/Foundation/c_SmartPtr.h +++ /dev/null @@ -1,115 +0,0 @@ -#ifndef INCLUDED_C_SMARTPTR_H -#define INCLUDED_C_SMARTPTR_H - -#ifndef INCLUDED_C_TYPES_H -#include -#endif /*INCLUDED_C_TYPES_H*/ - -#ifndef INCLUDED_C_MEMORY_H -#include -#endif /*INCLUDED_C_MEMORY_H*/ - -#ifndef INCLUDED_C_ATOMIC_H -#include -#endif /*INCLUDED_C_ATOMIC_H*/ - - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - - -// 釋放資源的函數指標類型 -typedef void (*c_SmartPtrFreeFn_t)(void* ptr, void* args); - -// 智慧指標結構體 -typedef struct { - void* ptr; - c_SmartPtrFreeFn_t free_fn; - void* args; - c_atomic_int_t* ref_count; -} c_SmartPtr_t; - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -C_STATIC_FORCE_INLINE -c_SmartPtr_t c_SmartPtr_Make(void* ptr, const c_SmartPtrFreeFn_t free_fn, void* args) { - c_SmartPtr_t sptr = { .ptr = ptr, .free_fn = free_fn, .args = args, .ref_count = NULL }; - - if (ptr == NULL) return sptr; - - C_NEW(sptr.ref_count); - if (sptr.ref_count != NULL) { - c_atomic_init_int(sptr.ref_count, 1); - } - return sptr; -} - -C_STATIC_FORCE_INLINE -c_err_t c_SmartPtr_Init(c_SmartPtr_t* self, void* ptr, const c_SmartPtrFreeFn_t free_fn, void* args) { - if (ptr == NULL) return C_ERR_PARAM; - - self->ptr = ptr; - self->free_fn = free_fn; - self->args = args; - self->ref_count = NULL; - - C_NEW(self->ref_count); - if (self->ref_count == NULL) { - return C_ERR_NOMEM; - } - - c_atomic_init_int(self->ref_count, 1); - return C_ERR_OK; -} - -C_STATIC_FORCE_INLINE -void c_SmartPtr_Destroy(c_SmartPtr_t* self) { - if (!self || !self->ref_count) return; - - if (C_ATOMIC_FETCH_SUB(self->ref_count, 1) == 1) { - if (self->free_fn && self->ptr) { - self->free_fn(self->ptr, self->args); - } - C_FREE(self->ref_count); - } - - memset(self, 0, sizeof(c_SmartPtr_t)); -} - -C_STATIC_FORCE_INLINE -c_err_t c_SmartPtr_Copy(c_SmartPtr_t* dest, const c_SmartPtr_t* src) { - if (!dest || !src || dest == src) return C_ERR_PARAM; - if (!src->ptr || !src->ref_count) return C_ERR_PARAM; - - c_SmartPtr_Destroy(dest); - - dest->ptr = src->ptr; - dest->free_fn = src->free_fn; - dest->args = src->args; - dest->ref_count = src->ref_count; - - C_ATOMIC_FETCH_ADD(dest->ref_count, 1); - return C_SUCCESS; -} - -C_STATIC_FORCE_INLINE -c_err_t c_SmartPtr_Move(c_SmartPtr_t* dest, c_SmartPtr_t* src) { - if (!dest || !src || dest == src) return C_ERR_PARAM; - - c_SmartPtr_Destroy(dest); - *dest = *src; - memset(src, 0, sizeof(c_SmartPtr_t)); - - return C_SUCCESS; -} - -C_STATIC_FORCE_INLINE -int c_SmartPtr_UseCount(const c_SmartPtr_t* self) { - if (!self || !self->ref_count) return 0; - return (int)C_ATOMIC_LOAD(self->ref_count); -} - - - -#endif /*INCLUDED_C_SMARTPTR_H*/ diff --git a/Foundation/c_SmartPtr.t.c b/Foundation/c_SmartPtr.t.c deleted file mode 100644 index af339b4..0000000 --- a/Foundation/c_SmartPtr.t.c +++ /dev/null @@ -1,57 +0,0 @@ -#include "c_SmartPtr.h" -#include -#include - -// 自訂釋放函數:負責關閉檔案 -void close_file_callback(void* ptr, void* args) { - FILE* fp = (FILE*)ptr; - char* filename = (char*)args; - - if (fp) { - printf("[SmartPtr] 引用計數歸零,自動關閉檔案: %s\n", filename); - fclose(fp); - } -} - -int main() { - printf("--- 1. 建立資源 (Open File) ---\n"); - char* my_file = "test.txt"; - FILE* fp = fopen(my_file, "w"); - if (!fp) return 1; - - // 寫入一些測試資料 - fprintf(fp, "Hello Smart Pointer in C!"); - fflush(fp); // 確保資料進硬碟,但先不關閉檔案 - - // 使用智慧指標接管檔案控制權 - c_SmartPtr_t sptr_a = c_SmartPtr_Make(fp, close_file_callback, my_file); - printf("sptr_a 建立完成,目前引用計數: %d\n", c_SmartPtr_UseCount(&sptr_a)); - - // 建立另外兩個空白的智慧指標容器 - c_SmartPtr_t sptr_b = {0}; - c_SmartPtr_t sptr_c = {0}; - - printf("\n--- 2. 測試 Copy 語義 (共享檔案控制權) ---\n"); - c_SmartPtr_Copy(&sptr_b, &sptr_a); - printf("A 的計數: %d, B 的計數: %d\n", c_SmartPtr_UseCount(&sptr_a), c_SmartPtr_UseCount(&sptr_b)); - - printf("\n--- 3. 測試 Move 語義 (B 所有權轉移給 C) ---\n"); - c_SmartPtr_Move(&sptr_c, &sptr_b); - printf("Move 後 -> B 計數: %d (已空), C 計數: %d\n", c_SmartPtr_UseCount(&sptr_b), c_SmartPtr_UseCount(&sptr_c)); - - printf("\n--- 4. 開始依序銷毀指標物件 ---\n"); - printf("銷毀 sptr_a...\n"); - c_SmartPtr_Destroy(&sptr_a); // 計數 2 -> 1 - printf("sptr_a 銷毀後,C 的計數: %d\n", c_SmartPtr_UseCount(&sptr_c)); - - printf("銷毀 sptr_b (本身已空,無影響)...\n"); - c_SmartPtr_Destroy(&sptr_b); - - printf("銷毀 sptr_c...\n"); - // 計數 1 -> 0,自動觸發 close_file_callback 關閉檔案! - c_SmartPtr_Destroy(&sptr_c); - - printf("\n程式結束,所有資源安全回收。\n"); - return 0; -} - diff --git a/Foundation/c_SmartPtrVector.c b/Foundation/c_SmartPtrVector.c deleted file mode 100644 index a55ec21..0000000 --- a/Foundation/c_SmartPtrVector.c +++ /dev/null @@ -1,152 +0,0 @@ -#include - -#define DEFAULT_INITIAL_CAPACITY 4 -#define DEFAULT_GROW_FACTOR 2 - -c_err_t c_SmartPtrVector_Init(c_SmartPtrVector_t* vector, c_size_t capacity) { - if (!vector) return C_ERR_PARAM; - if (capacity>0) { - vector->array = C_CALLOC(capacity, sizeof(c_SmartPtr_t)); - if (!vector->array) { - return C_ERR_NOMEM; - } - }else { - vector->array = NULL; - } - vector->capacity = capacity; - vector->size = 0; - return C_SUCCESS; -} - -void c_SmartPtrVector_Destroy(c_SmartPtrVector_t* vector) { - if (!vector || !vector->array) return; - for (c_size_t i=0; isize; i++) { - c_SmartPtr_Destroy(&vector->array[i]); - } - C_FREE(vector->array); - vector->capacity = 0; - vector->size = 0; -} - -c_err_t c_SmartPtrVector_PushBack(c_SmartPtrVector_t* vector, const c_SmartPtr_t* ptr) { - if (!vector || !ptr) return C_ERR_PARAM; - - // 檢查是否需要自動擴容 - if (vector->size >= vector->capacity) { - c_size_t new_capacity = (vector->capacity == 0) ? DEFAULT_INITIAL_CAPACITY : (vector->capacity * DEFAULT_GROW_FACTOR); - c_SmartPtr_t* new_array = (c_SmartPtr_t*)C_CALLOC(new_capacity, sizeof(c_SmartPtr_t)); - if (!new_array) { - return C_ERR_NOMEM; - } - - for (c_size_t i = 0; i < vector->size; i++) { - c_SmartPtr_Move(&new_array[i], &vector->array[i]); - } - - C_FREE(vector->array); - vector->array = new_array; - vector->capacity = new_capacity; - } - - // 執行 Copy 語義:在 Vector 內部建立一個新引用,底層引用計數 (ref_count) 自動 +1 - c_SmartPtr_Copy(&vector->array[vector->size], ptr); - vector->size++; - - return C_SUCCESS; -} - -c_err_t c_SmartPtrVector_Remove(c_SmartPtrVector_t* self, c_size_t index) { - if (!self || index >= self->size) return C_ERR_PARAM; - - // 1. 銷毀該 index 的智慧指標(若引用計數歸零,會在此處自動觸發資源 free 回收) - c_SmartPtr_Destroy(&self->array[index]); - - // 2. 將後續的所有智慧指標往前遞補 - // 這裡同樣必須使用 Move 語義進行「所有權搬移」,保持計數器數值不動 - for (c_size_t i = index; i < self->size - 1; i++) { - c_SmartPtr_Move(&self->array[i], &self->array[i + 1]); - } - - // 3. 將多出來的最後一個格子完全抹零抹乾淨,防止殘留野指標 - memset(&self->array[self->size - 1], 0, sizeof(c_SmartPtr_t)); - self->size--; - - return C_SUCCESS; -} - -c_err_t c_SmartPtrVector_PopBack(c_SmartPtrVector_t* vector, c_SmartPtr_t* ptr) { - if (!vector || !ptr) { - return C_ERR_PARAM; - } - - if (vector->size == 0) { - return C_ERR_EMPTY; - } - - c_SmartPtr_Move(ptr, &vector->array[vector->size - 1]); - vector->size--; - - return C_SUCCESS; -} - -c_err_t c_SmartPtrVector_Insert(c_SmartPtrVector_t* vector, c_size_t index, const c_SmartPtr_t* ptr) { - if (!vector || !ptr || index > vector->size) { - return C_ERR_PARAM; - } - - // 1. 檢查是否需要擴容 - if (vector->size >= vector->capacity) { - c_size_t new_capacity = (vector->capacity == 0) ? DEFAULT_INITIAL_CAPACITY : (vector->capacity * DEFAULT_GROW_FACTOR); - c_SmartPtr_t* new_array = (c_SmartPtr_t*)C_CALLOC(new_capacity, sizeof(c_SmartPtr_t)); - if (!new_array) { - return C_ERR_NOMEM; - } - - // 擴容搬移:使用 Move 語義,不變動計數 - for (c_size_t i = 0; i < vector->size; i++) { - c_SmartPtr_Move(&new_array[i], &vector->array[i]); - } - - C_FREE(vector->array); - vector->array = new_array; - vector->capacity = new_capacity; - } - - // 2. 將插入點之後的元素「從後往前」依序向後挪動一格 - // 關鍵:必須使用 c_SmartPtr_move 以確保在挪動過程中引用計數不發生任何不必要的增減與震盪 - for (c_size_t i = vector->size; i > index; i--) { - c_SmartPtr_Move(&vector->array[i], &vector->array[i - 1]); - } - - // 3. 在空出來的 index 位置執行 Copy 語義,正式納入 Vector 管理(引用計數 +1) - c_SmartPtr_Copy(&vector->array[index], ptr); - vector->size++; - - return C_SUCCESS; -} - -c_err_t c_SmartPtrVector_RemoveAndTake(c_SmartPtrVector_t* self, c_size_t index, c_SmartPtr_t* ptr) { - // 防禦性檢查:確保 self、輸出指標 ptr 有效,且 index 沒有越界 - if (!self || !ptr || index >= self->size) { - return C_ERR_PARAM; - } - - // 1. 執行 Move 語義:將指定 index 處的所有權完美轉移給外面的 ptr - // 這會自動安全釋放 ptr 原本持有的舊資源,並將 self->array[index] 掏空抹零。 - // 底層引用計數(ref_count)數值完全保持不動,沒有任何多餘開銷。 - c_SmartPtr_Move(ptr, &self->array[index]); - - // 2. 將 index 之後的所有智慧指標往前遞補一格 - // 因為 self->array[index] 剛才已經被 move 抹零了, - // 這裡的迴圈會把 index + 1 的內容 move 過去,依此類推。 - for (c_size_t i = index; i < self->size - 1; i++) { - c_SmartPtr_Move(&self->array[i], &self->array[i + 1]); - } - - // 3. 將最後一個多出來的殘留格子完全抹乾淨,防止產生野指標,並更新大小 - memset(&self->array[self->size - 1], 0, sizeof(c_SmartPtr_t)); - self->size--; - - return C_SUCCESS; -} - diff --git a/Foundation/c_SmartPtrVector.h b/Foundation/c_SmartPtrVector.h deleted file mode 100644 index 1083be9..0000000 --- a/Foundation/c_SmartPtrVector.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef INCLUDED_C_SMARTPTRVECTOR_H -#define INCLUDED_C_SMARTPTRVECTOR_H - -#ifndef INCLUDED_C_SMARTPTR_H -#include -#endif /*INCLUDED_C_SMARTPTR_H*/ - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -typedef struct { - c_SmartPtr_t* array; - c_size_t capacity; - c_size_t size; -}c_SmartPtrVector_t; - -#define C_SMART_PTR_VECTOR_INITIALIZER {NULL, 0, 0} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -C_STATIC_FORCE_INLINE -c_SmartPtrVector_t c_SmartPtrVector_Create(void) { - return (c_SmartPtrVector_t)C_SMART_PTR_VECTOR_INITIALIZER; -} - -C_STATIC_FORCE_INLINE -const c_SmartPtr_t* c_SmartPtrVector_Get(const c_SmartPtrVector_t* self, c_size_t index) { - if (!self || index >= self->size) { - return NULL; - } - return &self->array[index]; -} - -c_err_t c_SmartPtrVector_Init(c_SmartPtrVector_t* vector, c_size_t capacity); - -void c_SmartPtrVector_Destroy(c_SmartPtrVector_t* vector); - -c_err_t c_SmartPtrVector_PushBack(c_SmartPtrVector_t* vector, const c_SmartPtr_t* ptr); - -c_err_t c_SmartPtrVector_PopBack(c_SmartPtrVector_t* vector, c_SmartPtr_t* ptr); - -c_err_t c_SmartPtrVector_Remove(c_SmartPtrVector_t* self, c_size_t index); - -c_err_t c_SmartPtrVector_Insert(c_SmartPtrVector_t* vector, c_size_t index, const c_SmartPtr_t* ptr); - -c_err_t c_SmartPtrVector_RemoveAndTake(c_SmartPtrVector_t* self, c_size_t index, c_SmartPtr_t* ptr); - -#endif /*INCLUDED_C_SMARTPTRVECTOR_H*/ diff --git a/Foundation/c_Stopwatch.c b/Foundation/c_Stopwatch.c deleted file mode 100644 index 85f2b9f..0000000 --- a/Foundation/c_Stopwatch.c +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/Foundation/c_Stopwatch.h b/Foundation/c_Stopwatch.h deleted file mode 100644 index 6751e1c..0000000 --- a/Foundation/c_Stopwatch.h +++ /dev/null @@ -1,179 +0,0 @@ -#ifndef INCLUDED_C_STOPWATCH_H -#define INCLUDED_C_STOPWATCH_H - -#ifndef INCLUDED_C_TYPES_H -#include -#endif /*INCLUDED_C_TYPES_H*/ - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - - -#if defined(_WIN32) || defined(_WIN64) - #include - typedef LARGE_INTEGER c_TimePoint_t; -#else -#include -#include -typedef struct timespec c_TimePoint_t; -#endif - -typedef struct { - c_TimePoint_t start_time; - double elapsed_milliseconds; - c_bool_t is_running; -} c_Stopwatch_t; - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -/** - * Internal private helper: Captures the system's hardware clock monotonic timestamp. - */ -C_STATIC_FORCE_INLINE -void c_Stopwatch_GetTimePoint(c_TimePoint_t* tp) { -#if defined(_WIN32) || defined(_WIN64) - QueryPerformanceCounter(tp); -#else - // Using CLOCK_MONOTONIC to guarantee safety against system time changes/NTP adjustments - clock_gettime(CLOCK_MONOTONIC, tp); -#endif -} - -/** - * Internal private helper: Computes the difference in seconds between two points. - */ -C_STATIC_FORCE_INLINE -double c_Stopwatch_ComputeDiffInS(const c_TimePoint_t* start, const c_TimePoint_t* end) { -#if defined(_WIN32) || defined(_WIN64) - LARGE_INTEGER freq; - QueryPerformanceFrequency(&freq); - return (double)(end->QuadPart - start->HighPart) / (double)freq.QuadPart; -#else - double start_sec = (double)start->tv_sec + (double)start->tv_nsec / 1e9; - double end_sec = (double)end->tv_sec + (double)end->tv_nsec / 1e9; - return end_sec - start_sec; -#endif -} - -/** - * Calculate the delta time in milliseconds between two distinct time points. - * Time Complexity: O(1) | Auxiliary Space: O(1) - * @param start Pointer to the starting time point timestamp. - * @param end Pointer to the ending time point timestamp. - * @return The double precision scalar difference value in milliseconds, - * or -1.0 if any parameter pointer is NULL. - */ -C_STATIC_FORCE_INLINE -double c_Stopwatch_ComputeDiffInMS(const c_TimePoint_t* start, const c_TimePoint_t* end) { - if (start == NULL || end == NULL) return -1.0; - -#if defined(_WIN32) || defined(_WIN64) - LARGE_INTEGER freq; - QueryPerformanceFrequency(&freq); - // Convert to seconds first, then scale up to milliseconds - double seconds = (double)(end->QuadPart - start->QuadPart) / (double)freq.QuadPart; - return seconds * 1000.0; -#else - double start_ms = ((double)start->tv_sec * 1000.0) + ((double)start->tv_nsec / 1e6); - double end_ms = ((double)end->tv_sec * 1000.0) + ((double)end->tv_nsec / 1e6); - return end_ms - start_ms; -#endif -} - -/** - * Initialize the Stopwatch. Registers parameters to default states cleanly. - */ -C_STATIC_FORCE_INLINE -c_err_t c_Stopwatch_Init(c_Stopwatch_t* sw) { - if (sw == NULL) return C_ERR_PARAM; - - sw->elapsed_milliseconds = 0.0; - sw->is_running = C_FALSE; - memset(&sw->start_time, 0, sizeof(c_TimePoint_t)); - - return C_ERR_OK; -} - -/** - * Start or resume tracking time. - */ -C_STATIC_FORCE_INLINE -c_err_t c_Stopwatch_Start(c_Stopwatch_t* sw) { - if (sw == NULL) return C_ERR_PARAM; - if (sw->is_running) return C_ERR_OK; // Safe skip if already processing - - c_Stopwatch_GetTimePoint(&sw->start_time); - sw->is_running = C_TRUE; - - return C_ERR_OK; -} - -/** - * Stop tracking time and cache the elapsed segment into the accumulator. - */ -C_STATIC_FORCE_INLINE -c_err_t c_Stopwatch_Stop(c_Stopwatch_t* sw) { - if (sw == NULL) return C_ERR_PARAM; - if (!sw->is_running) return C_ERR_OK; - - c_TimePoint_t end_time; - c_Stopwatch_GetTimePoint(&end_time); - - // Add the delta directly to the millisecond buffer field - sw->elapsed_milliseconds += c_Stopwatch_ComputeDiffInMS(&sw->start_time, &end_time); - sw->is_running = C_FALSE; - - return C_ERR_OK; -} - -/** - * Soft Reset: Blasts elapsed counts down to zero while preserving the active running state. - */ -C_STATIC_FORCE_INLINE -c_err_t c_Stopwatch_Clear(c_Stopwatch_t* sw) { - if (sw == NULL) return C_ERR_PARAM; - - sw->elapsed_milliseconds = 0.0; - if (sw->is_running) { - c_Stopwatch_GetTimePoint(&sw->start_time); // Re-anchor start time mark to prevent jumps - } - - return C_ERR_OK; -} - - -/** - * Utility helper: Extract elapsed timing down to millisecond intervals. - */ -C_STATIC_FORCE_INLINE -double c_Stopwatch_GetElapsedMilliseconds(const c_Stopwatch_t* sw) { - if (sw == NULL) return 0.0; - if (!sw->is_running) return sw->elapsed_milliseconds; // Pure O(1) cache read - - c_TimePoint_t active_tick; - c_Stopwatch_GetTimePoint(&active_tick); - - // Dynamically add current active delta segment to the base accumulator - return sw->elapsed_milliseconds + c_Stopwatch_ComputeDiffInMS(&sw->start_time, &active_tick); -} - - -/** - * Extract total measured elapsed time in seconds up to this exact moment. - * Works perfectly whether the stopwatch is running or stopped (Lap peeking feature). - * Time Complexity: O(1) | Auxiliary Space: O(1) in-place - * @param sw Pointer to the constant stopwatch instance context. - * @return The double precision scalar elapsed time value in seconds, - * or 0.0 if the stopwatch instance handle is NULL. - */ -C_STATIC_FORCE_INLINE -double c_Stopwatch_GetElapsedSeconds(const c_Stopwatch_t* sw) { - if (sw == NULL) return 0.0; - - // Leverage the existing GetElapsedMilliseconds API and scale it down to second precision. - // This maintains perfect abstraction layer unity without duplicating clock read conditions. - return c_Stopwatch_GetElapsedMilliseconds(sw) / 1000.0; -} - -#endif /*INCLUDED_C_STOPWATCH_H*/ diff --git a/Foundation/c_Stopwatch.t.c b/Foundation/c_Stopwatch.t.c deleted file mode 100644 index 69c0f77..0000000 --- a/Foundation/c_Stopwatch.t.c +++ /dev/null @@ -1,132 +0,0 @@ -#include "c_Stopwatch.h" -#include -#include - -#include -#include -#include -#include - -// Your updated line tracing diagnostic macro -#define EXPECT_EQ(actual, expected, msg) \ - do { \ - if ((actual) != (expected)) { \ - printf(" [X] Assert Failed: %s (Expected %d, got %d) %s:%d\n", msg, (int)(expected), (int)(actual), __FILE__, __LINE__); \ - return C_FALSE; \ - } \ - } while(0) - -// Helper macro for double comparisons with floating-point tolerance -#define EXPECT_NEAR(actual, expected, tolerance, msg) \ - do { \ - if (fabs((actual) - (expected)) > (tolerance)) { \ - printf(" [X] Assert Failed: %s (Expected %f, got %f) %s:%d\n", msg, (double)(expected), (double)(actual), __FILE__, __LINE__); \ - return C_FALSE; \ - } \ - } while(0) - -// External references to previous core modules -extern void c_Stopwatch_GetTimePoint(c_TimePoint_t* tp); - -/** - * Mocks active OS-level processing delays using portable nanosleep/Sleep interfaces. - */ -static void c_Framework_MockExecutionDelayMs(int ms) { -#if defined(_WIN32) || defined(_WIN64) - Sleep(ms); -#else - struct timespec ts; - ts.tv_sec = ms / 1000; - ts.tv_nsec = (ms % 1000) * 1000000L; - nanosleep(&ts, NULL); -#endif -} - -c_bool_t test_stopwatch_compute_diff_in_ms(void) { - c_TimePoint_t t_start, t_end; - - // Test Case 1: Param Parameter Enforcement Boundary Checks - EXPECT_NEAR(c_Stopwatch_ComputeDiffInMS(NULL, &t_end), -1.0, 1e-6, "NULL start point guard missed"); - EXPECT_NEAR(c_Stopwatch_ComputeDiffInMS(&t_start, NULL), -1.0, 1e-6, "NULL end point guard missed"); - - // Test Case 2: Standard Interval Difference Evaluation - printf(" [LOG] Capturing timestamp benchmarks across a 60ms thread stall scenario...\n"); - c_Stopwatch_GetTimePoint(&t_start); - - c_Framework_MockExecutionDelayMs(60); - - c_Stopwatch_GetTimePoint(&t_end); - - double delta_ms = c_Stopwatch_ComputeDiffInMS(&t_start, &t_end); - - // Allow a flexible tolerance boundary for generic OS context switching variances - EXPECT_EQ(delta_ms >= 55.0, C_TRUE, "Computed millisecond difference fell short of target delay thresholds"); - printf(" [STAT] Clock cycle delta computed: %f ms\n", delta_ms); - - // Test Case 3: Identity Time Check (Difference between identical points must equal 0.0) - EXPECT_NEAR(c_Stopwatch_ComputeDiffInMS(&t_start, &t_start), 0.0, 1e-6, "Identity point calculation returned non-zero value"); - - return C_TRUE; -} - - -c_bool_t test_stopwatch_lifecycle(void) { - c_Stopwatch_t sw; - - // Test Case 1: Param Checking Guards & Initial Conditions - EXPECT_EQ(c_Stopwatch_Init(NULL), C_ERR_PARAM, "NULL stopwatch handler guard missed"); - EXPECT_EQ(c_Stopwatch_Init(&sw), C_ERR_OK, "Stopwatch init initialization failed"); - EXPECT_NEAR(c_Stopwatch_GetElapsedSeconds(&sw), 0.0, 1e-6, "Freshly initialized stopwatch reported non-zero runtime"); - - // Test Case 2: Standard Interval Measurement Tracking Check - printf(" [LOG] Launching Stopwatch profile tracking (100ms thread stall scenario)...\n"); - EXPECT_EQ(c_Stopwatch_Start(&sw), C_ERR_OK, "Stopwatch engine start pass failed"); - - c_Framework_MockExecutionDelayMs(100); - - // Check lap peeking capabilities while running - double lap_peek_ms = c_Stopwatch_GetElapsedMilliseconds(&sw); - EXPECT_EQ(lap_peek_ms >= 90.0, C_TRUE, "Lap peeking reported impossibly low runtime under active intervals"); - - EXPECT_EQ(c_Stopwatch_Stop(&sw), C_ERR_OK, "Stopwatch engine stop pass failed"); - EXPECT_EQ(sw.is_running, C_FALSE, "Stop execution failed to flag active timeline states offline"); - - double final_seconds = c_Stopwatch_GetElapsedSeconds(&sw); - // Allow a wide tolerance for generic OS process scheduling variances - EXPECT_NEAR(final_seconds >= 0.09, C_TRUE, 0.0, "Measured timing fell short of target delay thresholds"); - - // Test Case 3: Accumulated Timing Checks (Resume feature validation) - printf(" [LOG] Resuming stopwatch profile tracking (Additional 50ms delay path)...\n"); - EXPECT_EQ(c_Stopwatch_Start(&sw), C_ERR_OK, "Stopwatch engine resume phase failed"); - - c_Framework_MockExecutionDelayMs(50); - - EXPECT_EQ(c_Stopwatch_Stop(&sw), C_ERR_OK, "Stopwatch subsequent interval termination failed"); - double cumulative_ms = c_Stopwatch_GetElapsedMilliseconds(&sw); - EXPECT_EQ(cumulative_ms >= 140.0, C_TRUE, "Stopwatch failed to accumulate consecutive interval data layers"); - - // Test Case 4: Soft Clear Verification - EXPECT_EQ(c_Stopwatch_Clear(&sw), C_ERR_OK, "Stopwatch clear execution crashed"); - EXPECT_NEAR(c_Stopwatch_GetElapsedSeconds(&sw), 0.0, 1e-6, "Clear protocol left residual timing tracking metrics inside buffer"); - - return C_TRUE; -} - -int main(void) { - printf("=== Starting Framework Verification: c_Stopwatch_ComputeDiffInMS ===\n"); - if (test_stopwatch_compute_diff_in_ms()) { - printf(" [PASS] Standalone Monotonic Delta Millisecond Compute Engine Verified Successfully.\n"); - } else { - printf(" [FAIL] Delta Resolution Pipeline Processing Mismatches Detected.\n"); - } - - - printf("=== Starting Framework Verification: c_Stopwatch ===\n"); - if (test_stopwatch_lifecycle()) { - printf(" [PASS] High-Precision Monotonic Stopwatch Lifecycle Pipelines Verified Successfully.\n"); - } else { - printf(" [FAIL] Stopwatch Engine Processing or State Tracking Mismatches Intercepted.\n"); - } - - return 0; -} diff --git a/Foundation/c_Str.c b/Foundation/c_Str.c deleted file mode 100644 index 5ed7d5f..0000000 --- a/Foundation/c_Str.c +++ /dev/null @@ -1,301 +0,0 @@ -#include -#include -#include -#include - -#define idx(i, len) ((i) <= 0 ? (i) + (len) : (i) - 1) - -#define convert(s, i, j) do { int _len; \ - assert(s); _len = (int)strlen(s); \ - i = idx(i, _len); j = idx(j, _len); \ - if (i > j) { int t = i; i = j; j = t; } \ - assert(i >= 0 && j <= _len); } while (0) - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -char *c_Str_sub(const char *s, int i, int j) { - char *str, *p; - convert(s, i, j); - p = str = C_ALLOC(j - i + 1); - while (i < j) - *p++ = s[i++]; - *p = '\0'; - return str; -} - -char *c_Str_dup(const char *s, int i, int j, int n) { - int k; - char *str, *p; - assert(n >= 0); - convert(s, i, j); - p = str = C_ALLOC(n*(j - i) + 1); - if (j - i > 0) - while (n-- > 0) - for (k = i; k < j; k++) - *p++ = s[k]; - *p = '\0'; - return str; -} - -char *c_Str_reverse(const char *s, int i, int j) { - char *str, *p; - convert(s, i, j); - p = str = C_ALLOC(j - i + 1); - while (j > i) - *p++ = s[--j]; - *p = '\0'; - return str; -} - -char *c_Str_cat(const char *s1, int i1, int j1, - const char *s2, int i2, int j2) { - char *str, *p; - convert(s1, i1, j1); - convert(s2, i2, j2); - p = str = C_ALLOC(j1 - i1 + j2 - i2 + 1); - while (i1 < j1) - *p++ = s1[i1++]; - while (i2 < j2) - *p++ = s2[i2++]; - *p = '\0'; - return str; -} - -char *c_Str_catv(const char *s, ...) { - char *str, *p; - const char *save = s; - int i, j, len = 0; - va_list ap; - va_start(ap, s); - while (s) { - i = va_arg(ap, int); - j = va_arg(ap, int); - convert(s, i, j); - len += j - i; - s = va_arg(ap, const char *); - } - va_end(ap); - p = str = C_ALLOC(len + 1); - s = save; - va_start(ap, s); - while (s) { - i = va_arg(ap, int); - j = va_arg(ap, int); - convert(s, i, j); - while (i < j) - *p++ = s[i++]; - s = va_arg(ap, const char *); - } - va_end(ap); - *p = '\0'; - return str; -} - -char *c_Str_map(const char *s, int i, int j, - const char *from, const char *to) { - static char map[256] = { 0 }; - if (from && to) { - unsigned c; - for (c = 0; c < sizeof map; c++) - map[c] = c; - while (*from && *to) - map[(unsigned char)*from++] = *to++; - assert(*from == 0 && *to == 0); - } else { - assert(from == NULL && to == NULL && s); - assert(map['a']); - } - if (s) { - char *str, *p; - convert(s, i, j); - p = str = C_ALLOC(j - i + 1); - while (i < j) - *p++ = map[(unsigned char)s[i++]]; - *p = '\0'; - return str; - } else - return NULL; -} - -int c_Str_pos(const char *s, int i) { - assert(s); - const int len = (int) strlen(s); - i = idx(i, len); - assert(i >= 0 && i <= len); - return i + 1; -} - -int c_Str_len(const char *s, int i, int j) { - convert(s, i, j); - return j - i; -} - -int c_Str_cmp(const char *s1, int i1, int j1, - const char *s2, int i2, int j2) { - convert(s1, i1, j1); - convert(s2, i2, j2); - s1 += i1; - s2 += i2; - if (j1 - i1 < j2 - i2) { - int cond = strncmp(s1, s2, j1 - i1); - return cond == 0 ? -1 : cond; - } else if (j1 - i1 > j2 - i2) { - const int cond = strncmp(s1, s2, j2 - i2); - return cond == 0 ? +1 : cond; - } else - return strncmp(s1, s2, j1 - i1); -} - -int c_Str_chr(const char *s, int i, int j, int c) { - convert(s, i, j); - for ( ; i < j; i++) - if (s[i] == c) - return i + 1; - return 0; -} - -int c_Str_rchr(const char *s, int i, int j, int c) { - convert(s, i, j); - while (j > i) - if (s[--j] == c) - return j + 1; - return 0; -} - -int c_Str_upto(const char *s, int i, int j, - const char *set) { - assert(set); - convert(s, i, j); - for ( ; i < j; i++) - if (strchr(set, s[i])) - return i + 1; - return 0; -} - -int c_Str_rupto(const char *s, int i, int j, - const char *set) { - assert(set); - convert(s, i, j); - while (j > i) - if (strchr(set, s[--j])) - return j + 1; - return 0; -} - -int c_Str_find(const char *s, int i, int j, - const char *str) { - convert(s, i, j); - assert(str); - const int len = (int)strlen(str); - if (len == 0) - return i + 1; - else if (len == 1) { - for ( ; i < j; i++) - if (s[i] == *str) - return i + 1; - } else - for ( ; i + len <= j; i++) - if ((strncmp(&s[i], str, len) == 0)) - return i + 1; - return 0; -} - -int c_Str_rfind(const char *s, int i, int j, const char *str) { - convert(s, i, j); - assert(str); - const int len =(int)strlen(str); - if (len == 0) - return j + 1; - else if (len == 1) { - while (j > i) - if (s[--j] == *str) - return j + 1; - } else - for ( ; j - len >= i; j--) - if (strncmp(&s[j-len], str, len) == 0) - return j - len + 1; - return 0; -} - -int c_Str_any(const char *s, int i, const char *set) { - assert(s); - assert(set); - const int len =(int)strlen(s); - i = idx(i, len); - assert(i >= 0 && i <= len); - if (i < len && strchr(set, s[i])) - return i + 2; - return 0; -} -int c_Str_many(const char *s, int i, int j, - const char *set) { - assert(set); - convert(s, i, j); - if (i < j && strchr(set, s[i])) { - do - i++; - while (i < j && strchr(set, s[i])); - return i + 1; - } - return 0; -} - -int c_Str_rmany(const char *s, int i, int j, - const char *set) { - assert(set); - convert(s, i, j); - if (j > i && strchr(set, s[j-1])) { - do - --j; - while (j >= i && strchr(set, s[j])); - return j + 2; - } - return 0; -} - -int c_Str_match(const char *s, int i, int j, const char *str) { - convert(s, i, j); - assert(str); - const int len =(int)strlen(str); - if (len == 0) - return i + 1; - else if (len == 1) { - if (i < j && s[i] == *str) - return i + 2; - } else if (i + len <= j && (strncmp(&s[i], str, len) == 0)) - return i + len + 1; - return 0; -} - -int c_Str_rmatch(const char *s, int i, int j, const char *str) { - convert(s, i, j); - assert(str); - const int len =(int)strlen(str); - if (len == 0) - return j + 1; - else if (len == 1) { - if (j > i && s[j-1] == *str) - return j; - } else if (j - len >= i - && strncmp(&s[j-len], str, len) == 0) - return j - len + 1; - return 0; -} - -void c_Str_fmt(int code, va_list_box *box, - int put(int c, void *cl), void *cl, - unsigned char flags[], int width, int precision) { - assert(box && flags); - char *s = va_arg(box->ap, char *); - int i = va_arg(box->ap, int); - int j = va_arg(box->ap, int); - convert(s, i, j); - c_Fmt_puts(s + i, j - i, put, cl, flags, - width, precision); -} - -void c_Str_free(char* s) { - C_FREE(s); -} - diff --git a/Foundation/c_Str.h b/Foundation/c_Str.h deleted file mode 100644 index 27bf215..0000000 --- a/Foundation/c_Str.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef INCLUDED_C_STR_H -#define INCLUDED_C_STR_H - -#ifndef INCLUDED_C_FMT_H -#include -#endif /*INCLUDED_C_FMT_H*/ - - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -char *c_Str_sub(const char *s, int i, int j); -char *c_Str_dup(const char *s, int i, int j, int n); -char *c_Str_cat(const char *s1, int i1, int j1, - const char *s2, int i2, int j2); -char *c_Str_catv (const char *s, ...); -char *c_Str_reverse(const char *s, int i, int j); -char *c_Str_map (const char *s, int i, int j, - const char *from, const char *to); -void c_Str_free(char* s); -int c_Str_pos(const char *s, int i); -int c_Str_len(const char *s, int i, int j); -int c_Str_cmp(const char *s1, int i1, int j1, - const char *s2, int i2, int j2); -int c_Str_chr (const char *s, int i, int j, int c); -int c_Str_rchr (const char *s, int i, int j, int c); -int c_Str_upto (const char *s, int i, int j, - const char *set); -int c_Str_rupto(const char *s, int i, int j, - const char *set); -int c_Str_find (const char *s, int i, int j, - const char *str); -int c_Str_rfind(const char *s, int i, int j, - const char *str); -int c_Str_any (const char *s, int i, - const char *set); -int c_Str_many (const char *s, int i, int j, - const char *set); -int c_Str_rmany (const char *s, int i, int j, - const char *set); -int c_Str_match (const char *s, int i, int j, - const char *str); -int c_Str_rmatch(const char *s, int i, int j, - const char *str); -void c_Str_fmt(int code, va_list_box *box, - int put(int c, void *cl), void *cl, - unsigned char flags[], int width, int precision); - -#endif /*INCLUDED_C_STR_H*/ diff --git a/Foundation/c_Str.t.c b/Foundation/c_Str.t.c deleted file mode 100644 index f11a835..0000000 --- a/Foundation/c_Str.t.c +++ /dev/null @@ -1,187 +0,0 @@ -#include - -#include "c_Str.h" -#include -#include -const char *test_str = "abcdefg"; // 長度為 7 - -char test_output_buffer[128]; -int buf_idx = 0; - -int test_put(int c, void *cl) { - if (buf_idx < 127) { - test_output_buffer[buf_idx++] = (char)c; - } - return c; -} - -// Global print wrapper to test formatting execution -void test_printf(const char *fmt, ...) { - va_list_box ap; - va_start(ap.ap, fmt); - c_Fmt_vfmt(test_put, NULL, fmt, &ap); - va_end(ap.ap); -} - -void test_log(const char* name) { - printf("[PASS] %s\n", name); -} - - -int main() { - printf("==================================================\n"); - printf(" 開始執行 c_Str 核心功能組件 最終整合單元測試\n"); - printf("==================================================\n\n"); - - char *res_str = NULL; - - // 1. 測試 c_Str_pos - // test_str = "abcdefg" (len=7) - // 1 -> index 0 -> 位置 1 - // 0 -> 尾端倒數 (0+7) = index 7 -> 位置 8 - // -1 -> 尾端倒數 (-1+7) = index 6 -> 位置 7 - assert(c_Str_pos(test_str, 1) == 1); - assert(c_Str_pos(test_str, 0) == 8); - assert(c_Str_pos(test_str, -1) == 7); - test_log("c_Str_pos (1-based 位置計算驗證)"); - - // 2. 測試 c_Str_len - // 從 1 (開頭) 到 0 (結尾) -> 全長 7 - // 從 2 ('b') 到 5 ('e' 後方) -> 5 - 1 = 4 ('bcde') - assert(c_Str_len(test_str, 1, 0) == 7); - assert(c_Str_len(test_str, 2, 5) == 3); - test_log("c_Str_len (區間長度計算驗證)"); - - // 3. 測試 c_Str_sub - res_str = c_Str_sub(test_str, 2, 5); // 提取 'bcd' - assert(strcmp(res_str, "bcd") == 0); - c_Str_free(res_str); - test_log("c_Str_sub (子字串提取驗證)"); - - // 4. 測試 c_Str_dup - res_str = c_Str_dup(test_str, 2, 4, 3); // 'bc' 重複 3 次 - assert(strcmp(res_str, "bcbcbc") == 0); - c_Str_free(res_str); - test_log("c_Str_dup (子字串重複複製驗證)"); - - // 5. 測試 c_Str_reverse - res_str = c_Str_reverse(test_str, 2, 5); // 'bcd' 反轉 -> 'dcb' - assert(strcmp(res_str, "dcb") == 0); - c_Str_free(res_str); - test_log("c_Str_reverse (子字串反轉驗證)"); - - // 6. 測試 c_Str_cat - res_str = c_Str_cat("XYZ", 1, 0, "123", 1, 3); // "XYZ" + "12" -> "XYZ12" - assert(strcmp(res_str, "XYZ12") == 0); - c_Str_free(res_str); - test_log("c_Str_cat (雙字串區間拼接驗證)"); - - // 7. 測試 c_Str_catv (多字串可變參數拼接,必須以 NULL 結尾) - res_str = c_Str_catv("ABC", 1, 0, "XYZ", 2, 4, (char*)NULL); // "ABC" + "YZ" - assert(strcmp(res_str, "ABCYZ") == 0); - c_Str_free(res_str); - test_log("c_Str_catv (多參數變長字串拼接驗證)"); - - // 8. 測試 c_Str_map (字元映射/置換) - // 初始化對照表:將 'b' 換成 'X','d' 換成 'Y' - c_Str_map(NULL, 0, 0, "bd", "XY"); - res_str = c_Str_map(test_str, 1, 0, NULL, NULL); // "abcdefg" -> "aXcYe f g" - assert(strcmp(res_str, "aXcYefg") == 0); - c_Str_free(res_str); - test_log("c_Str_map (字元對照表置換驗證)"); - - // 9. 測試 c_Str_cmp - // "abcdefg" 區間 [2,4] 是 "bc";"abc" 區間 [2,4] 是 "bc" -> 相等 (0) - assert(c_Str_cmp(test_str, 2, 4, "abc", 2, 4) == 0); - // "bc" 與 "bcd" 比對 -> 前者較短且完全匹配,預期回傳 -1 - assert(c_Str_cmp(test_str, 2, 4, "abcdefg", 2, 5) == -1); - test_log("c_Str_cmp (區間字串深度比對驗證)"); - - // 10. 測試 c_Str_chr (正向尋找字元,回傳 1-based 位置) - // 在 "abcdefg" 中找 'c' -> 位於 index 2 -> 回傳 3 - assert(c_Str_chr(test_str, 1, 0, 'c') == 3); - assert(c_Str_chr(test_str, 1, 0, 'z') == 0); // 找不到 - test_log("c_Str_chr (正向字元查找位置驗證)"); - - // 11. 測試 c_Str_rchr (反向尋找字元) - // 在 "abcdecd" 中找 'c' - assert(c_Str_rchr("abcdecd", 1, 0, 'c') == 6); - test_log("c_Str_rchr (反向字元查找位置驗證)"); - - // 12. 測試 c_Str_upto (正向尋找集合中任一字元首次出現位置) - // "abcdefg" 中尋找 "xyz" 或 "d" -> 'd' 最先被匹配 (index 3) -> 回傳 4 - assert(c_Str_upto(test_str, 1, 0, "xyz d") == 4); - test_log("c_Str_upto (字元集合正向切分點驗證)"); - - // 13. 測試 c_Str_rupto (反向尋找集合中任一字元首次出現位置) - // "abcdefg" 中反向找 "ab" -> 'b' 最先被找到 (index 1) -> 回傳 2 - assert(c_Str_rupto(test_str, 1, 0, "ab") == 2); - test_log("c_Str_rupto (字元集合反向切分點驗證)"); - - // 14. 測試 c_Str_find (正向尋找子字串) - // "abcdefg" 中找 "cde" -> 開始於 index 2 -> 回傳 3 - assert(c_Str_find(test_str, 1, 0, "cde") == 3); - test_log("c_Str_find (正向子字串搜尋匹配驗證)"); - - // 15. 測試 c_Str_rfind (反向尋找子字串) - // "ababax" 中反向找 "aba" -> 應匹配到 index 2 開始的 "aba" -> 回傳 3 - assert(c_Str_rfind("ababax", 1, 0, "aba") == 3); - test_log("c_Str_rfind (反向子字串搜尋匹配驗證)"); - - // 16. 測試 c_Str_any (檢查指定 index 的單一字元是否在集合中) - // test_str="abcdefg", i=3 -> index 2 ('c')。'c' 有在 "cba" 之中 -> 回傳 index+2 = 4 - assert(c_Str_any(test_str, 3, "cba") == 4); - assert(c_Str_any(test_str, 3, "xyz") == 0); // 'c' 不在 xyz 中 - test_log("c_Str_any (特定點字元集命中檢查驗證)"); - - // 17. 測試 c_Str_many (從指定起點向後匹配連續屬於集合的字元,直到不屬於為止) - // "aaabX" 從 1 開始,連續符合 "abc" 的有 'a','a','a','b' (4個) -> 停止於 index 4 -> 回傳 4+1 = 5 - assert(c_Str_many("aaabX", 1, 0, "abc") == 5); - test_log("c_Str_many (正向連續字元集跨越範圍驗證)"); - - // 18. 測試 c_Str_rmany (從指定終點向前匹配連續屬於集合的字元) - // "Xbbba" 從 0(結尾) 向前,符合 "abc" 的有 'a','b','b','b' (4個) -> 停止於 index 0 ('X') -> 回傳 index+2 = 2 - assert(c_Str_rmany("Xbbba", 1, 0, "abc") == 2); - test_log("c_Str_rmany (反向連續字元集跨越範圍驗證)"); - - // 19. 測試 c_Str_match (檢查指定起點是否「精準開頭匹配」該子字串) - // "abcdefg" 在位置 3 (index 2, 'c') 是否精準匹配 "cde" -> 是,符合長度 3 -> 回傳 index+len+1 = 2+3+1 = 6 - assert(c_Str_match(test_str, 3, 0, "cde") == 6); - assert(c_Str_match(test_str, 3, 0, "xyz") == 0); - test_log("c_Str_match (指定起點子字串精準頭匹配驗證)"); - - // 20. 測試 c_Str_rmatch (檢查指定終點是否「精準結尾匹配」該子字串) - // "abcde" 在 0(結尾, index 5) 向前看是否精準匹配 "cde" (len=3) -> index 5-3=2 開始是 "cde" -> 成功,回傳 2+1 = 3 - assert(c_Str_rmatch("abcde", 1, 0, "cde") == 3); - test_log("c_Str_rmatch (指定終點子字串精準尾匹配驗證)"); - - // 21. 測試 c_Str_fmt (驗證自訂格式化回呼整合) -#if 0 - unsigned char flags[256] = { 0 }; - mock_put_count = 0; - // 傳入字串 "hello", 起點 2 ('e'), 終點 5 ('o' 後方) -> 預期提取出 "ell" - run_str_fmt_test(0, flags, 0, 0, "hello", 2, 5); - assert(mock_put_count == 3); // "ell" 長度為 3,應呼叫 3 次 put - test_log("c_Str_fmt (格式化輸出器區間提取回呼驗證)"); -#endif - - memset(test_output_buffer, 0, sizeof(test_output_buffer)); - buf_idx = 0; - c_Fmt_t old_handler = c_Fmt_register('S', c_Str_fmt); - assert(old_handler == NULL); - printf("[PASS] c_Str_fmt successfully registered to specifier character 'S'.\n"); - - const char* sample_sentence = "the c-container-library platform"; - test_printf("Extracted Token: [%S]", sample_sentence, 5, 16); - test_output_buffer[buf_idx] = '\0'; - - printf(" Rendered Output String: %s\n", test_output_buffer); - assert(strcmp(test_output_buffer, "Extracted Token: [c-container]") == 0); - printf("[PASS] Core Fmt engine correctly processed parameters via c_Str_fmt.\n"); - - printf("\n==================================================\n"); - printf(" 恭喜!c_Str 基礎工具類共計 22 個核心介面全數單元測試通過!\n"); - printf("==================================================\n"); - - return 0; -} \ No newline at end of file diff --git a/Foundation/c_StrIndexKmp.c b/Foundation/c_StrIndexKmp.c deleted file mode 100644 index 73e57d7..0000000 --- a/Foundation/c_StrIndexKmp.c +++ /dev/null @@ -1,76 +0,0 @@ -#include -#include - -#define MAX_STACK_LPS 128 - -static void compute_LPS_table(const char* pattern, c_size_t m, long long* lps) { - c_size_t len = 0; // Length of the previous longest prefix suffix - lps[0] = 0; // lps[0] is always 0 - c_size_t i = 1; - - while (i < m) { - if (pattern[i] == pattern[len]) { - len++; - lps[i] = (long long)len; - i++; - } else { - if (len != 0) { - len = (c_size_t)lps[len - 1]; // Backtrack without shifting 'i' - } else { - lps[i] = 0; - i++; - } - } - } -} - -long long c_StrIndexKmp(const char* text, const char* pattern) { - if (!text || !pattern) return -1; - - const c_size_t n = strlen(text); - const c_size_t m = strlen(pattern); - - if (m == 0) return 0; // An empty pattern matches at the very beginning - if (m > n) return -1; // Pattern is longer than the text container - - // Optimization: Use a stack buffer if the pattern length fits, avoiding heap allocation cycles - long long stack_lps[MAX_STACK_LPS]; - long long* lps = (m <= MAX_STACK_LPS) ? stack_lps : (long long*)C_ALLOC(m * sizeof(long long)); - if (!lps) return -1; // Allocation failure fallback - - // Step 1: Precompute the lookup table - compute_LPS_table(pattern, m, lps); - - // Step 2: Linear string matching phase - c_size_t i = 0; // Index for text - c_size_t j = 0; // Index for pattern - long long matched_index = -1; - - while (i < n) { - if (pattern[j] == text[i]) { - i++; - j++; - } - - if (j == m) { - matched_index = (long long)(i - j); // Found match at index (i - j) - break; // Terminate early for the first occurrence - } - // Mismatch after j matches - else if (i < n && pattern[j] != text[i]) { - if (j != 0) { - j = (size_t)lps[j - 1]; // Slide the pattern using the precomputed LPS table - } else { - i++; - } - } - } - - // Clean up heap memory if it was allocated - if (lps != stack_lps) { - C_FREE(lps); - } - - return matched_index; -} - diff --git a/Foundation/c_StrIndexKmp.h b/Foundation/c_StrIndexKmp.h deleted file mode 100644 index bc489ae..0000000 --- a/Foundation/c_StrIndexKmp.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef INCLUDED_C_STRINDEXKMP_H -#define INCLUDED_C_STRINDEXKMP_H - -#ifndef INCLUDED_C_TYPES_H -#include -#endif /*INCLUDED_C_TYPES_H*/ - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -long long c_StrIndexKmp(const char* text, const char* pattern); - -#endif /*INCLUDED_C_STRINDEXKMP_H*/ diff --git a/Foundation/c_StrIndexKmp.t.c b/Foundation/c_StrIndexKmp.t.c deleted file mode 100644 index 56da8be..0000000 --- a/Foundation/c_StrIndexKmp.t.c +++ /dev/null @@ -1,49 +0,0 @@ -#include - -#include "c_StrIndexKmp.h" -#include -#include - -void test_log(const char* test_name) { - printf("[PASS] %s\n", test_name); -} - -int main() { - printf("==================================================\n"); - printf(" Starting KMP String Search Algorithm Unit Tests\n"); - printf("==================================================\n\n"); - - // Test 1: Standard match discovery - const char* text1 = "ABABDABACDABABCABAB"; - long long idx1 = c_StrIndexKmp(text1, "ABABCABAB"); - assert(idx1 == 10); - test_log("1. Pattern found at index 10 successfully"); - - // Test 2: Repeating partial pattern fallback (Corrected text and pattern) - // At index 0, text matches "ABABA" but mismatches on the 6th char ('B' vs 'C'). - // The LPS table causes j to backtrack smoothly, discovering the real match starting at index 2. - const char* text2 = "ABABABACATA"; - long long idx2 = c_StrIndexKmp(text2, "ABABAC"); - assert(idx2 == 2); - test_log("2. Partial-match backtracking table lookup verified at index 2"); - - // Test 3: Pattern not present in text - long long idx3 = c_StrIndexKmp(text1, "XYZ"); - assert(idx3 == -1); - test_log("3. Non-existent substring pattern returns -1 safely"); - - // Test 4: Empty pattern handling boundary check - long long idx4 = c_StrIndexKmp(text1, ""); - assert(idx4 == 0); - test_log("4. Empty string matches target index 0"); - - // Test 5: Pattern longer than string payload boundary check - long long idx5 = c_StrIndexKmp("short", "extremely_long_pattern"); - assert(idx5 == -1); - test_log("5. Length mismatch constraints handled gracefully"); - - printf("\n==================================================\n"); - printf(" Success! All KMP test assertions passed successfully!\n"); - printf("==================================================\n"); - return 0; -} \ No newline at end of file diff --git a/Foundation/c_StrUtil.c b/Foundation/c_StrUtil.c deleted file mode 100644 index 0ace9f8..0000000 --- a/Foundation/c_StrUtil.c +++ /dev/null @@ -1,193 +0,0 @@ -#include -#include -#include - -#include "c_ArrayList.h" - -// Reverses a string in-place -void c_StrUtil_Reverse(char* str) { - if (!str) return; - const c_size_t len = strlen(str); - if (len <= 1) return; - - c_size_t i = 0; - c_size_t j = len - 1; - while (i < j) { - char temp = str[i]; - str[i] = str[j]; - str[j] = temp; - i++; - j--; - } -} - -// Converts a string to lowercase into a destination buffer -c_err_t c_StrUtil_ToLower(char* out_dest, const char* src, c_size_t dest_capacity) { - if (!out_dest || !src || dest_capacity == 0) return C_ERR_PARAM; - - c_size_t i = 0; - while (src[i] != '\0') { - if (i >= dest_capacity - 1) { - out_dest[i] = '\0'; - return C_ERR_FAIL; - } - out_dest[i] = (char)tolower((unsigned char)src[i]); - i++; - } - out_dest[i] = '\0'; - return C_ERR_OK; -} - -// Converts a string to uppercase into a destination buffer -c_err_t c_StrUtil_ToUpper(char* out_dest, const char* src, c_size_t dest_capacity) { - if (!out_dest || !src || dest_capacity == 0) return C_ERR_PARAM; - - c_size_t i = 0; - while (src[i] != '\0') { - if (i >= dest_capacity - 1) { - out_dest[i] = '\0'; - return C_ERR_FAIL; - } - out_dest[i] = (char)toupper((unsigned char)src[i]); - i++; - } - out_dest[i] = '\0'; - return C_ERR_OK; -} - -// Removes leading and trailing whitespaces into a destination buffer -c_err_t c_StrUtil_Trim(char* out_dest, const char* src, c_size_t dest_capacity) { - if (!out_dest || !src || dest_capacity == 0) return C_ERR_PARAM; - - // Find first non-whitespace character - while (*src && isspace((unsigned char)*src)) { - src++; - } - - // Find the end of the string - c_size_t len = strlen(src); - while (len > 0 && isspace((unsigned char)src[len - 1])) { - len--; - } - - if (len >= dest_capacity) { - return C_ERR_FAIL; - } - - // Copy trimmed substring - memmove(out_dest, src, len); - out_dest[len] = '\0'; - return C_ERR_OK; -} - -c_bool_t c_StrUtil_StartsWith(const char* str, const char* prefix) { - if (!str || !prefix) return C_FALSE; - return strncmp(str, prefix, strlen(prefix)) == 0 ? C_TRUE : C_FALSE; -} - -c_bool_t c_StrUtil_EndsWith(const char* str, const char* suffix) { - if (!str || !suffix) return C_FALSE; - c_size_t str_len = strlen(str); - c_size_t suf_len = strlen(suffix); - if (suf_len > str_len) return C_FALSE; - return strcmp(str + str_len - suf_len, suffix) == 0 ? C_TRUE : C_FALSE; -} - -// Safely extracts a substring with full bounds verification -c_err_t c_StrUtil_Substring(char* out_dest, const char* src, c_size_t start, c_size_t len, c_size_t dest_capacity) { - if (!out_dest || !src || dest_capacity == 0) return C_ERR_PARAM; - - c_size_t src_len = strlen(src); - if (start > src_len) return C_ERR_OUTOFBOUND; - - // Adjust requested length if it overflows source string boundaries - if (start + len > src_len) { - len = src_len - start; - } - - if (len >= dest_capacity) { - return C_ERR_OUTOFBOUND; - } - - memcpy(out_dest, src + start, len); - out_dest[len] = '\0'; - return C_ERR_OK; -} - -// Replaces occurrences of a substring inside a buffer safely -c_err_t c_StrUtil_Replace(char* out_dest, const char* src, const char* find, const char* replace_with, c_size_t dest_capacity) { - if (!out_dest || !src || !find || !replace_with || dest_capacity == 0) return C_ERR_PARAM; - - c_size_t find_len = strlen(find); - c_size_t replace_len = strlen(replace_with); - c_size_t dest_len = 0; - - if (find_len == 0) return C_ERR_PARAM; - - while (*src) { - // If match found, inject replacement string - if (strncmp(src, find, find_len) == 0) { - if (dest_len + replace_len >= dest_capacity) { - out_dest[dest_len] = '\0'; - return C_ERR_OUTOFBOUND; - } - strcpy(out_dest + dest_len, replace_with); - dest_len += replace_len; - src += find_len; - } else { - // Otherwise, inject individual source character - if (dest_len + 1 >= dest_capacity) { - out_dest[dest_len] = '\0'; - return C_ERR_OUTOFBOUND; - } - out_dest[dest_len] = *src; - dest_len++; - src++; - } - } - out_dest[dest_len] = '\0'; - return C_ERR_OK; -} - -c_err_t c_StrUtil_Split(c_ArrayList_t* out_list, const char* src, const char* delimiter) { - if (!out_list || !src || !delimiter) return C_ERR_PARAM; - if (out_list->obj_size != sizeof(c_StrToken_t)) return C_ERR_PARAM; // Type safety assert - - const c_size_t delim_len = strlen(delimiter); - if (delim_len == 0) return C_ERR_PARAM; - - const char* current = src; - const char* next_match; - - while ((next_match = strstr(current, delimiter)) != NULL) { - size_t token_len = next_match - current; - - if (token_len > 0) { - c_StrToken_t new_token; - // Bound checking to ensure long strings don't cause buffer overflows - size_t copy_len = (token_len >= C_STR_TOKEN_MAX_LEN) ? (C_STR_TOKEN_MAX_LEN - 1) : token_len; - - memcpy(new_token.text, current, copy_len); - new_token.text[copy_len] = '\0'; - - // Deep-copy token structure payload straight into the dynamic ArrayList - c_ArrayList_Add(out_list, &new_token); - } - current = next_match + delim_len; - } - - // Capture the final token remaining after the last delimiter match - if (*current != '\0') { - c_StrToken_t new_token; - size_t token_len = strlen(current); - size_t copy_len = (token_len >= C_STR_TOKEN_MAX_LEN) ? (C_STR_TOKEN_MAX_LEN - 1) : token_len; - - memcpy(new_token.text, current, copy_len); - new_token.text[copy_len] = '\0'; - - c_ArrayList_Add(out_list, &new_token); - } - - return C_ERR_OK; -} - diff --git a/Foundation/c_StrUtil.h b/Foundation/c_StrUtil.h deleted file mode 100644 index 50acece..0000000 --- a/Foundation/c_StrUtil.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef INCLUDED_C_STRUTIL_H -#define INCLUDED_C_STRUTIL_H - -#ifndef INCLUDED_C_TYPES_H -#include -#endif /*INCLUDED_C_TYPES_H*/ - -#ifndef INCLUDED_C_ARRAYLIST_H -#include -#endif /*INCLUDED_C_ARRAYLIST_H*/ - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -#ifndef C_STR_TOKEN_MAX_LEN -#define C_STR_TOKEN_MAX_LEN 64 -#endif - - -typedef struct { - char text[C_STR_TOKEN_MAX_LEN]; -} c_StrToken_t; - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -void c_StrUtil_Reverse(char* str); -c_err_t c_StrUtil_ToLower(char* out_dest, const char* src, c_size_t dest_capacity); -c_err_t c_StrUtil_ToUpper(char* out_dest, const char* src, c_size_t dest_capacity); - -// Trimming whitespace (' ', '\t', '\r', '\n') -c_err_t c_StrUtil_Trim(char* out_dest, const char* src, c_size_t dest_capacity); - -// Search & Matching operations -c_bool_t c_StrUtil_StartsWith(const char* str, const char* prefix); -c_bool_t c_StrUtil_EndsWith(const char* str, const char* suffix); - -// Substring extraction (Safe, boundary checked) -c_err_t c_StrUtil_Substring(char* out_dest, const char* src, c_size_t start, c_size_t len, c_size_t dest_capacity); - -// String replacements (Safely handles different length replacements) -c_err_t c_StrUtil_Replace(char* out_dest, const char* src, const char* find, const char* replace_with, c_size_t dest_capacity); - -// Tokenizer that breaks down a source string and appends results to an initialized ArrayList -c_err_t c_StrUtil_Split(c_ArrayList_t* out_list, const char* src, const char* delimiter) ; - -#endif /*INCLUDED_C_STRUTIL_H*/ diff --git a/Foundation/c_StrUtil.t.c b/Foundation/c_StrUtil.t.c deleted file mode 100644 index fea5f21..0000000 --- a/Foundation/c_StrUtil.t.c +++ /dev/null @@ -1,116 +0,0 @@ -#include - -#include "c_StrUtil.h" -#include -#include - - -void test_log(const char* test_name) { - printf("[PASS] %s\n", test_name); -} - -static void test_split(void) { - printf("==================================================\n"); - printf(" Starting Tokenizer & ArrayList Integration Tests\n"); - printf("==================================================\n\n"); - - // Initialize your generic ArrayList to accept your structured token elements - c_ArrayList_t token_list; - c_err_t err = c_ArrayList_Init(&token_list, sizeof(c_StrToken_t), 4); - assert(err == C_ERR_OK); - - const char* csv_data = "GND,VCC,TX_PIN,RX_PIN,SPI_CLK"; - - // Split the comma-delimited configuration values - err = c_StrUtil_Split(&token_list, csv_data, ","); - assert(err == C_ERR_OK); - - // 1. Validate parsed sizing counts matching expected segmentations - assert(token_list.size == 5); - test_log("1. String segmented into 5 individual structural elements"); - - // 2. Sequential range checking verifying index preservation - c_StrToken_t* t_ptr; - - t_ptr = (c_StrToken_t*)c_ArrayList_Get(&token_list, 0); - assert(strcmp(t_ptr->text, "GND") == 0); - - t_ptr = (c_StrToken_t*)c_ArrayList_Get(&token_list, 2); - assert(strcmp(t_ptr->text, "TX_PIN") == 0); - - t_ptr = (c_StrToken_t*)c_ArrayList_Get(&token_list, 4); - assert(strcmp(t_ptr->text, "SPI_CLK") == 0); - test_log("2. Target indices verify correct sub-string capture sequence"); - - // 3. Clear container lifecycle properties cleanly - c_ArrayList_Destroy(&token_list); - test_log("3. Array container memory teardown success"); - - printf("\n==================================================\n"); - printf(" Success! Token parsing and container layers fit perfectly!\n"); - printf("==================================================\n"); -} - -int main() { - printf("==================================================\n"); - printf(" Starting C String Utility Unit Tests\n"); - printf("==================================================\n\n"); - - char buffer[128]; - c_err_t err; - - // 1. Test Reverse - strcpy(buffer, "A man a plan a canal Panama"); - c_StrUtil_Reverse(buffer); - assert(strcmp(buffer, "amanaP lanac a nalp a nam A") == 0); - test_log("1. In-place string reversal"); - - // 2. Test Case Conversions - err = c_StrUtil_ToLower(buffer, "C_Language_123!", sizeof(buffer)); - assert(err == C_ERR_OK); - assert(strcmp(buffer, "c_language_123!") == 0); - - err = c_StrUtil_ToUpper(buffer, "embedded c", sizeof(buffer)); - assert(err == C_ERR_OK); - assert(strcmp(buffer, "EMBEDDED C") == 0); - test_log("2. Casing conversions"); - - // 3. Test Trim - err = c_StrUtil_Trim(buffer, " \t Hello World \r\n ", sizeof(buffer)); - assert(err == C_ERR_OK); - assert(strcmp(buffer, "Hello World") == 0); - test_log("3. Whitespace trimming"); - - // 4. Test Starts/Ends With - assert(c_StrUtil_StartsWith("libcontainer.so", "lib") == C_TRUE); - assert(c_StrUtil_StartsWith("libcontainer.so", "bin") == C_FALSE); - assert(c_StrUtil_EndsWith("document.txt", ".txt") == C_TRUE); - assert(c_StrUtil_EndsWith("document.txt", ".pdf") == C_FALSE); - test_log("4. Prefix/Suffix conditional checks"); - - // 5. Test Substring - err = c_StrUtil_Substring(buffer, "Microcontroller", 5, 7, sizeof(buffer)); - assert(err == C_ERR_OK); - assert(strcmp(buffer, "control") == 0); - test_log("5. Substring range isolation"); - - // 6. Test Replace - err = c_StrUtil_Replace(buffer, "The quick brown fox jumps over the lazy dog", "quick brown fox", "slow green turtle", sizeof(buffer)); - assert(err == C_ERR_OK); - assert(strcmp(buffer, "The slow green turtle jumps over the lazy dog") == 0); - test_log("6. Substring template injection matching"); - - // 7. Overflow Protection - char small_buffer[6]; - err = c_StrUtil_ToUpper(small_buffer, "OVERFLOW_TEST", sizeof(small_buffer)); - assert(err == C_ERR_FAIL); - assert(strlen(small_buffer) == 5); // Ensure safe null truncation occurred - test_log("7. Buffer overflow bounds interception"); - - printf("\n==================================================\n"); - printf(" Success! String utilities match defensive safety layouts!\n"); - printf("==================================================\n"); - - test_split(); - return 0; -} \ No newline at end of file diff --git a/Foundation/c_StringBuffer.c b/Foundation/c_StringBuffer.c deleted file mode 100644 index ab7641b..0000000 --- a/Foundation/c_StringBuffer.c +++ /dev/null @@ -1,955 +0,0 @@ -#include -#include -#include -#include - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -#define DEFAULT_INIT_CAPACITY 16 -#define GROWTH_FACTOR 2 - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -C_STATIC_FORCE_INLINE -c_err_t c_StringBuffer_EnsureCapacity(c_StringBuffer_t* self, c_size_t required_len) { - c_size_t needed_capacity = self->size + required_len + 1; // +1 for trailing '\0' - if (needed_capacity <= self->capacity) { - return C_ERR_OK; - } - - c_size_t new_capacity = self->capacity == 0 ? DEFAULT_INIT_CAPACITY : self->capacity; - while (new_capacity < needed_capacity) { - new_capacity *= GROWTH_FACTOR; // Exponential doubling strategy - } - - char* new_buffer = (char*)C_ALLOC(new_capacity); - if (!new_buffer) { - return C_ERR_NOMEM; - } - - if (self->buffer && self->size > 0) { - memcpy(new_buffer, self->buffer, self->size); - } - new_buffer[self->size] = '\0'; - - C_FREE(self->buffer); - self->buffer = new_buffer; - self->capacity = new_capacity; - - return C_ERR_OK; -} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - - -c_err_t c_StringBuffer_Init(c_StringBuffer_t* self, c_size_t capacity) { - if (!self) return C_ERR_PARAM; - - self->size = 0; - self->capacity = capacity > 0 ? capacity : DEFAULT_INIT_CAPACITY; // Enforce minimum initial allocation - self->buffer = (char*)C_ALLOC(self->capacity); - if (!self->buffer) { - self->capacity = 0; - return C_ERR_NOMEM; - } - self->buffer[0] = '\0'; - - return C_ERR_OK; -} - -void c_StringBuffer_Destroy(c_StringBuffer_t* self) { - if (!self) return; - if (self->buffer) { - C_FREE(self->buffer); - } - self->size = 0; - self->capacity = 0; -} - -c_err_t c_StringBuffer_Append(c_StringBuffer_t* self, const char* string, c_size_t length) { - if (!self || !self->buffer || !string || length == 0) return C_ERR_PARAM; - - c_err_t err = c_StringBuffer_EnsureCapacity(self, length); - if (err != C_ERR_OK) return err; - - memcpy(self->buffer + self->size, string, length); - self->size += length; - self->buffer[self->size] = '\0'; - - return C_ERR_OK; -} - -c_err_t c_StringBuffer_Prepend(c_StringBuffer_t* self, const char* string, c_size_t length) { - return c_StringBuffer_InsertAt(self, 0, string, length); -} - -c_err_t c_StringBuffer_InsertAt(c_StringBuffer_t* self, c_size_t index, const char* string, c_size_t length) { - if (!self || !self->buffer || !string || length == 0) return C_ERR_PARAM; - if (index > self->size) return C_ERR_OUTOFBOUND; - - c_err_t err = c_StringBuffer_EnsureCapacity(self, length); - if (err != C_ERR_OK) return err; - - // Shift memory to the right using memmove to prevent overlapping issues - memmove(self->buffer + index + length, self->buffer + index, self->size - index); - memcpy(self->buffer + index, string, length); - - self->size += length; - self->buffer[self->size] = '\0'; - - return C_ERR_OK; -} - -c_err_t c_StringBuffer_RemoveAt(c_StringBuffer_t* self, c_size_t index, c_size_t length) { - if (!self || !self->buffer) return C_ERR_PARAM; - if (index >= self->size) return C_ERR_OUTOFBOUND; - if (length ==0) return C_SUCCESS; - - // Clamp length if it attempts to read past the end of the current buffer - if (index + length > self->size) { - length = self->size - index; - } - - // Shift trailing memory to the left to close the character gap - memmove(self->buffer + index, self->buffer + index + length, self->size - (index + length)); - self->size -= length; - self->buffer[self->size] = '\0'; - - return C_ERR_OK; -} - -void c_StringBuffer_Clear(c_StringBuffer_t* self) { - if (!self || !self->buffer) return; - self->size = 0; - self->buffer[0] = '\0'; -} - -/* --- Explicit String-Wrapper Interfaces --- */ - -c_err_t c_StringBuffer_AppendStr(c_StringBuffer_t* self, const char* string) { - if (!string) return C_ERR_PARAM; - return c_StringBuffer_Append(self, string, strlen(string)); -} - -c_err_t c_StringBuffer_PrependStr(c_StringBuffer_t* self, const char* string) { - if (!string) return C_ERR_PARAM; - return c_StringBuffer_Prepend(self, string, strlen(string)); -} - -c_err_t c_StringBuffer_InsertStrAt(c_StringBuffer_t* self, const char* string, c_size_t index) { - if (!string) return C_ERR_PARAM; - return c_StringBuffer_InsertAt(self, index, string, strlen(string)); -} - -c_err_t c_StringBuffer_CopyTo(c_StringBuffer_t* self, c_size_t index, c_size_t length, char* buffer, c_size_t buffer_length) { - // 1. Guard against invalid pointers, empty destinations, or index out-of-bounds - if (!self || !self->buffer || !buffer || buffer_length == 0) { - return C_ERR_PARAM; - } - if (index > self->size) { - return C_ERR_OUTOFBOUND; - } - - // 2. Clamp requested copy length if it exceeds the remaining data payload bounds - if (index + length > self->size) { - length = self->size - index; - } - - // 3. Enforce destination buffer capacity threshold checks - // The requested segment requires at least (length + 1) bytes for safe null-termination - if (length >= buffer_length) { - return C_ERR_OUTOFBOUND; // Destination buffer is too small to store the segment safely - } - - // 4. Perform the raw memory copy if there are valid characters to process - if (length > 0) { - memcpy(buffer, self->buffer + index, length); - } - - // 5. Always apply a deterministic trailing null terminator - buffer[length] = '\0'; - - return C_ERR_OK; -} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - - -c_err_t c_StringBuffer_VPrintf(c_StringBuffer_t* self, const char* format, va_list args) { - if (!self || !format) return C_ERR_PARAM; - - // Make a copy of args to measure the required layout length safely - va_list args_copy; - va_copy(args_copy, args); - int formatted_len = vsnprintf(NULL, 0, format, args_copy); - va_end(args_copy); - - if (formatted_len < 0) return C_ERR_PARAM; - if (formatted_len == 0) return C_SUCCESS; - - c_size_t length = (c_size_t)formatted_len; - - c_err_t err = c_StringBuffer_EnsureCapacity(self, length); - if (err != C_SUCCESS) return err; - - // Use the original args list for writing directly into the structure block - vsnprintf(self->buffer + self->size, length + 1, format, args); - - self->size += length; - self->buffer[self->size] = '\0'; - - return C_SUCCESS; -} - -c_err_t c_StringBuffer_VPrintfAt(c_StringBuffer_t* self, c_size_t index, const char* format, va_list args) { - if (!self || !format) return C_ERR_PARAM; - if (index > self->size) return C_ERR_OUTOFBOUND; - - // Measure the length of the new formatted slice - va_list args_copy; - va_copy(args_copy, args); - int formatted_len = vsnprintf(NULL, 0, format, args_copy); - va_end(args_copy); - - if (formatted_len < 0) return C_ERR_PARAM; - if (formatted_len == 0) return C_SUCCESS; - - c_size_t length = (c_size_t)formatted_len; - - c_err_t err = c_StringBuffer_EnsureCapacity(self, length); - if (err != C_SUCCESS) return err; - - // Safely backup the target downstream character that will be stomped by vsnprintf's '\0' - char backup_char = '\0'; - if (index < self->size) { - backup_char = self->buffer[index]; - } - - // Shift the existing string buffer memory forward - memmove(self->buffer + index + length, self->buffer + index, self->size - index); - - // Render formatted string fragments safely into the newly allocated block gap - vsnprintf(self->buffer + index, length + 1, format, args); - - // Overwrite the accidental inner null-terminator using our clean structural backup - if (index < self->size) { - self->buffer[index + length] = backup_char; - } - - self->size += length; - self->buffer[self->size] = '\0'; - - return C_SUCCESS; -} - -c_err_t c_StringBuffer_Printf(c_StringBuffer_t* self, const char* format, ...) { - va_list args; - va_start(args, format); - c_err_t err = c_StringBuffer_VPrintf(self, format, args); - va_end(args); - return err; -} - -c_err_t c_StringBuffer_PrintfAt(c_StringBuffer_t* self, c_size_t index, const char* format, ...) { - va_list args; - va_start(args, format); - c_err_t err = c_StringBuffer_VPrintfAt(self, index, format, args); - va_end(args); - return err; -} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -#include -#include - -c_err_t c_StringBuffer_AppendTimestamp(c_StringBuffer_t* self, const char* format, const struct tm* time_info) { - if (!self || !format || !time_info) return C_ERR_PARAM; - - // Start with a reasonable initial guess for max timestamp length. - // Most standard timestamps (%Y-%m-%d %H:%M:%S) fit in under 32 or 64 bytes. - c_size_t guess_space = 64; - c_err_t err; - - while (1) { - err = c_StringBuffer_EnsureCapacity(self, guess_space); - if (err != C_SUCCESS) return err; - - // strftime writes into the remaining available capacity space. - // self->capacity - self->size calculation leaves room for the null-terminator. - c_size_t max_write = self->capacity - self->size; - size_t written = strftime(self->buffer + self->size, max_write, format, time_info); - - // strftime returns 0 if the string didn't fit into the provided buffer size - if (written == 0) { - // Check if the pattern genuinely produces a 0-length output (like an empty format string "") - if (format[0] == '\0') { - return C_SUCCESS; - } - // Double the guess size space and try again - guess_space *= 2; - - // Put an upper bound sanity check to prevent infinite loops on broken formatting parameters - if (guess_space > 4096) { - return C_ERR_PARAM; - } - continue; - } - - // Success! Advance size tracking variable - self->size += (c_size_t)written; - // strftime automatically guarantees a null terminator at self->buffer[self->size] - break; - } - - return C_SUCCESS; -} - -c_err_t c_StringBuffer_AppendCurrentTimestamp(c_StringBuffer_t* self, const char* format, int use_utc) { - if (!self || !format) return C_ERR_PARAM; - - time_t raw_time = time(NULL); - if (raw_time == (time_t)-1) { - return C_ERR_PARAM; // Failed to retrieve system clock time - } - - struct tm time_struct; - struct tm* time_ptr; - - // Thread-safe structure assembly variants (fallback to standard if platform requires it) - if (use_utc) { -#if defined(_WIN32) || defined(_WIN64) - if (gmtime_s(&time_struct, &raw_time) != 0) return C_ERR_PARAM; - time_ptr = &time_struct; -#else - time_ptr = gmtime_r(&raw_time, &time_struct); -#endif - } else { -#if defined(_WIN32) || defined(_WIN64) - if (localtime_s(&time_struct, &raw_time) != 0) return C_ERR_PARAM; - time_ptr = &time_struct; -#else - time_ptr = localtime_r(&raw_time, &time_struct); -#endif - } - - if (!time_ptr) return C_ERR_PARAM; - - return c_StringBuffer_AppendTimestamp(self, format, time_ptr); -} - - -c_err_t c_StringBuffer_InsertTimestampAt(c_StringBuffer_t* self, c_size_t index, const char* format, const struct tm* time_info) { - if (!self || !format || !time_info) return C_ERR_PARAM; - if (index > self->size) return C_ERR_OUTOFBOUND; - - // Use a conservative local stack frame memory allocation. - // Standard timestamp strings comfortably fit within 128 bytes. - char temp_stack_buffer[128]; - char* target_buffer = temp_stack_buffer; - c_size_t allocated_size = sizeof(temp_stack_buffer); - c_size_t final_len = 0; - c_err_t result = C_SUCCESS; - - while (1) { - size_t written = strftime(target_buffer, allocated_size, format, time_info); - - if (written == 0) { - // Check if the format string pattern is intentionally empty "" - if (format[0] == '\0') { - final_len = 0; - break; - } - - // If the timestamp string didn't fit, scale up the workspace dynamically on the heap - c_size_t new_allocated_size = allocated_size * 2; - - // Loop sanity guard limit to prevent infinite allocations on bad layout configurations - if (new_allocated_size > 4096) { - if (target_buffer != temp_stack_buffer) { - free(target_buffer); - } - return C_ERR_PARAM; - } - - char* new_buffer = (target_buffer == temp_stack_buffer) - ? (char*)malloc(new_allocated_size) - : (char*)realloc(target_buffer, new_allocated_size); - - if (!new_buffer) { - if (target_buffer != temp_stack_buffer) { - free(target_buffer); - } - return C_ERR_NOMEM; - } - - // Copy data over if migrating from stack array block allocation initially - if (target_buffer == temp_stack_buffer) { - // No need to copy old data because strftime failed completely anyway - } - - target_buffer = new_buffer; - allocated_size = new_allocated_size; - continue; - } - - final_len = (c_size_t)written; - break; - } - - // Call your existing InsertAt implementation to open the gap and safely shift the array characters downstream - if (final_len > 0) { - result = c_StringBuffer_InsertAt(self, index, target_buffer, final_len); - } - - // Clean up heap space allocations if we outgrew the default 128-byte stack array footprint - if (target_buffer != temp_stack_buffer) { - free(target_buffer); - } - - return result; -} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -c_index_t c_StringBuffer_IndexOfStr(c_StringBuffer_t* self, c_size_t start_index, const char* substr) { - if (!self || !self->buffer || !substr) return C_ERR_FAIL; - if (start_index >= self->size) return C_ERR_FAIL; - - // Utilize optimized standard strstr starting from our targeted index offset - char* match = strstr(self->buffer + start_index, substr); - if (!match) return C_ERR_FAIL; - - return (c_index_t)(match - self->buffer); -} - -c_index_t c_StringBuffer_IndexOfChar(c_StringBuffer_t* self, c_size_t start_index, char target) { - if (!self || !self->buffer) return C_ERR_FAIL; - if (start_index >= self->size) return C_ERR_FAIL; - - // memchr is highly optimized by compilers using SIMD assembly operations under the hood - c_size_t search_len = self->size - start_index; - char* match = (char*)memchr(self->buffer + start_index, target, search_len); - if (!match) return C_ERR_FAIL; - - return (c_index_t)(match - self->buffer); -} - -c_index_t c_StringBuffer_LastIndexOfStr(c_StringBuffer_t* self, c_size_t start_index, const char* substr) { - if (!self || !self->buffer || !substr) return C_ERR_FAIL; - - c_size_t sub_len = strlen(substr); - if (sub_len == 0) return C_ERR_FAIL; - - // Clamp start_index to structural string boundary maximums - c_size_t upper_bound = (start_index >= self->size) ? (self->size == 0 ? 0 : self->size - 1) : start_index; - if (upper_bound < sub_len - 1) return C_ERR_FAIL; - - // Scan backwards sequentially to find the last occurrence match context - for (c_size_t i = upper_bound + 1 - sub_len; ; i--) { - if (strncmp(self->buffer + i, substr, sub_len) == 0) { - return (c_index_t)i; - } - if (i == 0) break; // Terminate condition for unsigned down-counting loops - } - - return C_ERR_FAIL; -} - -c_index_t c_StringBuffer_LastIndexOfChar(c_StringBuffer_t* self, c_size_t start_index, char target) { - if (!self || !self->buffer || self->size == 0) return C_ERR_PARAM; - - c_size_t upper_bound = (start_index >= self->size) ? (self->size - 1) : start_index; - - // Backwards structural loop checking character identities cleanly - for (c_size_t i = upper_bound; ; i--) { - if (self->buffer[i] == target) { - return (c_index_t)i; - } - if (i == 0) break; - } - - return C_ERR_FAIL; -} - - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - - -c_err_t c_StringBuffer_ReplaceStr(c_StringBuffer_t* self, const char* old_str, const char* new_str) { - if (!self || !old_str || !new_str) return C_ERR_PARAM; - - c_size_t old_len = strlen(old_str); - if (old_len == 0) return C_SUCCESS; // Replacing an empty string is a no-op - - c_size_t new_len = strlen(new_str); - - // Pass 1: Count total occurrences to evaluate memory requirements safely - c_size_t occurrences = 0; - const char* scan = self->buffer; - if (scan) { - while ((scan = strstr(scan, old_str)) != NULL) { - occurrences++; - scan += old_len; - } - } - - if (occurrences == 0) return C_SUCCESS; // No matches found - - // Calculate structural payload delta modifications - long long delta = (long long)new_len - (long long)old_len; - c_size_t final_size = self->size + (occurrences * delta); - - // Expand buffer layout upfront if the replacement string expands the footprint - if (delta > 0) { - c_err_t err = c_StringBuffer_EnsureCapacity(self, occurrences * delta); - if (err != C_SUCCESS) return err; - } - - // Pass 2: Apply the substitution matrix via pointer offsets - char* read_ptr = self->buffer; - char* write_ptr = self->buffer; - - // If the string expands, we must write from right-to-left to prevent stomping data. - // However, an easy and clean way to handle all deltas without complex memory logic - // is utilizing a temporary buffer, or shifting segments sequentially. - // Let's implement an in-place single-buffer scan-and-shift variant: - c_size_t current_index = 0; - while (current_index < self->size) { - char* match = strstr(self->buffer + current_index, old_str); - if (!match) break; - - c_index_t match_idx = (c_index_t)(match - self->buffer); - - if (delta != 0) { - // Shift the trailing data behind the old string block configuration - c_size_t tail_len = self->size - (match_idx + old_len); - memmove(self->buffer + match_idx + new_len, self->buffer + match_idx + old_len, tail_len); - } - - // Copy the replacement string elements into the target slot - if (new_len > 0) { - memcpy(self->buffer + match_idx, new_str, new_len); - } - - // Adjust tracking dimensions - self->size += delta; - current_index = match_idx + new_len; - } - - self->buffer[self->size] = '\0'; // Strictly enforce final null-termination - return C_SUCCESS; -} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -#include -#include - -c_err_t c_StringBuffer_TrimLeft(c_StringBuffer_t* self) { - if (!self) return C_ERR_PARAM; - if (self->size == 0) return C_SUCCESS; - - c_size_t spaces = 0; - - // Scan forward to count leading whitespace characters - // isspace covers: ' ', '\t', '\n', '\v', '\f', '\r' - while (spaces < self->size && isspace((unsigned char)self->buffer[spaces])) { - spaces++; - } - - if (spaces == 0) return C_SUCCESS; // No leading whitespace found - - // Shift the remaining structural payload left to overwrite the whitespace - c_size_t remaining_bytes = self->size - spaces; - if (remaining_bytes > 0) { - memmove(self->buffer, self->buffer + spaces, remaining_bytes); - } - - self->size = remaining_bytes; - self->buffer[self->size] = '\0'; // Strictly enforce structural null-termination - - return C_SUCCESS; -} - -c_err_t c_StringBuffer_TrimRight(c_StringBuffer_t* self) { - if (!self) return C_ERR_PARAM; - if (self->size == 0) return C_SUCCESS; - - // Scan backwards from the tail using unsigned down-counting loop guard rails - c_size_t i = self->size; - while (i > 0 && isspace((unsigned char)self->buffer[i - 1])) { - i--; - } - - // Adjust structural sizes down directly without moving memory arrays - self->size = i; - if (self->buffer && self->capacity > 0) { - self->buffer[self->size] = '\0'; - } - - return C_SUCCESS; -} - -c_err_t c_StringBuffer_Trim(c_StringBuffer_t* self) { - if (!self) return C_ERR_PARAM; - - // Performance optimization: Clean up tail bytes first to minimize memory movement blocks - c_err_t err = c_StringBuffer_TrimRight(self); - if (err != C_SUCCESS) return err; - - return c_StringBuffer_TrimLeft(self); -} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - - -c_err_t c_StringBuffer_ToLower(c_StringBuffer_t* self) { - if (!self || !self->buffer) return C_ERR_PARAM; - - for (c_size_t i = 0; i < self->size; i++) { - self->buffer[i] = (char)tolower((unsigned char)self->buffer[i]); - } - return C_SUCCESS; -} - -c_err_t c_StringBuffer_ToUpper(c_StringBuffer_t* self) { - if (!self || !self->buffer) return C_ERR_PARAM; - - for (c_size_t i = 0; i < self->size; i++) { - self->buffer[i] = (char)toupper((unsigned char)self->buffer[i]); - } - return C_SUCCESS; -} - - -c_err_t c_StringBuffer_Split(c_StringBuffer_t* self, const char* delimiter, c_StringBuffer_t** out_tokens, c_size_t* out_count) { - // 1. 严格的参数校验 - if (!self || !self->buffer || !delimiter || !out_tokens || !out_count) { - return C_ERR_PARAM; - } - - // 显式将输出重置,防止调用方读取未初始化的脏数据 - *out_tokens = NULL; - *out_count = 0; - - c_size_t delim_len = strlen(delimiter); - if (delim_len == 0) { - return C_ERR_PARAM; // 分隔符不能为空字符串 - } - - // 2. 第一轮扫描:计算一共会拆分出多少个 Token,以便一次性分配连续数组空间 - c_size_t token_count = 1; - const char* scan = self->buffer; - while ((scan = strstr(scan, delimiter)) != NULL) { - token_count++; - scan += delim_len; // 跳过当前分隔符继续匹配 - } - - // 3. 一次性分配容纳所有结构体的数组 - c_StringBuffer_t* tokens = (c_StringBuffer_t*)malloc(token_count * sizeof(c_StringBuffer_t)); - if (!tokens) { - return C_ERR_NOMEM; - } - - // 预先清空结构体数组,使后续的防御性回滚清理更加安全 - for (c_size_t i = 0; i < token_count; i++) { - tokens[i].buffer = NULL; - tokens[i].capacity = 0; - tokens[i].size = 0; - } - - // 4. 第二轮扫描:精准切片并填充到独立的结构体中 - c_size_t current_token = 0; - c_size_t start_idx = 0; - - while (start_idx <= self->size) { - // 寻找下一个分隔符的位置 - char* match = strstr(self->buffer + start_idx, delimiter); - - // 计算当前 Token 的字节长度 - c_size_t token_len = match ? (c_size_t)(match - (self->buffer + start_idx)) : (self->size - start_idx); - - // 初始化子 StringBuffer(分配其内部的 char* 缓冲区) - c_err_t err = c_StringBuffer_Init(&tokens[current_token], token_len); - if (err != C_SUCCESS) goto error_cleanup; - - // 如果长度大于 0,将片段内容追加拷贝进去 - if (token_len > 0) { - err = c_StringBuffer_Append(&tokens[current_token], self->buffer + start_idx, token_len); - if (err != C_SUCCESS) goto error_cleanup; - } - - current_token++; - if (!match) break; // 已处理完最后一个片段,退出循环 - - // 步进索引:当前片段长度 + 分隔符长度 - start_idx += token_len + delim_len; - } - - // 5. 成功赋值输出 - *out_tokens = tokens; - *out_count = token_count; - return C_SUCCESS; - -// 防御性垃圾回收:如果中途任何一个 Token 内存分配失败,完整回滚,绝不泄露 -error_cleanup: - for (c_size_t i = 0; i < token_count; i++) { - // c_StringBuffer_Destroy 内部有对 NULL 的安全校验 - c_StringBuffer_Destroy(&tokens[i]); - } - free(tokens); - return C_ERR_NOMEM; -} - - - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -c_err_t c_StringBuffer_Join(c_StringBuffer_t* self, const c_StringBuffer_t tokens[], c_size_t count, const char* separator) { - if (!self || (!tokens && count > 0) || !separator) return C_ERR_PARAM; - - c_StringBuffer_Clear(self); - if (count == 0) return C_SUCCESS; - - c_size_t sep_len = strlen(separator); - c_size_t total_required_space = 0; - - // Pass 1: Compute exactly how much capacity is needed upfront to prevent intermediate reallocations - for (c_size_t i = 0; i < count; i++) { - total_required_space += tokens[i].size; - if (i < count - 1) { - total_required_space += sep_len; - } - } - - c_err_t err = c_StringBuffer_EnsureCapacity(self, total_required_space); - if (err != C_SUCCESS) return err; - - // Pass 2: Fast sequential data copying into the pre-sized buffer - for (c_size_t i = 0; i < count; i++) { - if (tokens[i].size > 0) { - memcpy(self->buffer + self->size, tokens[i].buffer, tokens[i].size); - self->size += tokens[i].size; - } - - if (i < count - 1 && sep_len > 0) { - memcpy(self->buffer + self->size, separator, sep_len); - self->size += sep_len; - } - } - - self->buffer[self->size] = '\0'; // Strictly enforce final null-termination - return C_SUCCESS; -} - -int c_StringBuffer_Equals(const c_StringBuffer_t* self, const char* string) { - if (!self || !string) return 0; - if (!self->buffer) return (string[0] == '\0'); - - // Optimization: Check sizing footprints first before comparing bytes - c_size_t str_len = strlen(string); - if (self->size != str_len) return 0; - - return (strcmp(self->buffer, string) == 0); -} - -int c_StringBuffer_EqualsIgnoreCase(const c_StringBuffer_t* self, const char* string) { - if (!self || !string) return 0; - if (!self->buffer) return (string[0] == '\0'); - - c_size_t str_len = strlen(string); - if (self->size != str_len) return 0; - - // Character-by-character validation mapped safely onto tolower limits - for (c_size_t i = 0; i < self->size; i++) { - if (tolower((unsigned char)self->buffer[i]) != tolower((unsigned char)string[i])) { - return 0; // Immediate mismatch exit - } - } - - return 1; // Content identities match perfectly -} - -int c_StringBuffer_Compare(const c_StringBuffer_t* self, const char* string) { - // Standardize null pointers to make safety deterministic - const char* s1 = (self && self->buffer) ? self->buffer : ""; - const char* s2 = string ? string : ""; - - return strcmp(s1, s2); -} - -c_err_t c_StringBuffer_Reverse(c_StringBuffer_t* self) { - if (!self) return C_ERR_PARAM; - if (self->size <= 1) return C_SUCCESS; // No-op if empty or single character - - c_size_t left = 0; - c_size_t right = self->size - 1; - - // Fast symmetric swap loop executing entirely in-place - while (left < right) { - char temp = self->buffer[left]; - self->buffer[left] = self->buffer[right]; - self->buffer[right] = temp; - - left++; - right--; - } - - // Maintain safety by preserving the existing null-terminator position - self->buffer[self->size] = '\0'; - return C_SUCCESS; -} - - -c_err_t c_StringBuffer_Substr(const c_StringBuffer_t* self, c_size_t index, c_size_t length, c_StringBuffer_t* out_substring) { - if (!self || !out_substring) return C_ERR_PARAM; - - // Explicitly zero out the target structure descriptor up front to prevent undefined state access on failure - out_substring->buffer = NULL; - out_substring->capacity = 0; - out_substring->size = 0; - - if (index > self->size) return C_ERR_OUTOFBOUND; - - // Clamp the target length parameter dynamically if it exceeds the remaining data payload bounds - if (index + length > self->size) { - length = self->size - index; - } - - // Initialize the out string buffer with the exact exact footprint space required - c_err_t err = c_StringBuffer_Init(out_substring, length); - if (err != C_SUCCESS) return err; - - if (length > 0) { - err = c_StringBuffer_Append(out_substring, self->buffer + index, length); - if (err != C_SUCCESS) { - c_StringBuffer_Destroy(out_substring); - return err; - } - } - - return C_SUCCESS; -} - -c_err_t c_StringBuffer_Slice(const c_StringBuffer_t* self, c_size_t start_index, c_size_t end_index, c_StringBuffer_t* out_slice) { - if (!self || !out_slice) return C_ERR_PARAM; - - out_slice->buffer = NULL; - out_slice->capacity = 0; - out_slice->size = 0; - - if (start_index > self->size) return C_ERR_OUTOFBOUND; - - // Clamp end_index if it exceeds the structural size boundary limits - if (end_index > self->size) { - end_index = self->size; - } - - // If indices are out of order or equal, return an empty initialized string buffer instance safely - c_size_t length = (end_index > start_index) ? (end_index - start_index) : 0; - - c_err_t err = c_StringBuffer_Init(out_slice, length); - if (err != C_SUCCESS) return err; - - if (length > 0) { - err = c_StringBuffer_Append(out_slice, self->buffer + start_index, length); - if (err != C_SUCCESS) { - c_StringBuffer_Destroy(out_slice); - return err; - } - } - - return C_SUCCESS; -} - - -c_err_t c_StringBuffer_strtoul(const c_StringBuffer_t* self, c_size_t start_index, int base, unsigned long* out_value, c_size_t* out_end_index) { - if (!self || !self->buffer || !out_value) return C_ERR_PARAM; - if (start_index >= self->size) return C_ERR_OUTOFBOUND; - - // Reset errno before executing standard parsing functions to isolate previous system actions - int current_errno = errno; - errno = 0; - - char* parse_end = NULL; - const char* start_ptr = self->buffer + start_index; - - unsigned long result = strtoul(start_ptr, &parse_end, base); - - // Error Validation Condition 1: Check for standard numerical overflow/underflow - if (errno == ERANGE) { - return C_ERR_OUTOFBOUND; // Numerical envelope exceeded bounds - } - - // Error Validation Condition 2: No structural digits could be parsed at all - if (parse_end == start_ptr) { - errno = current_errno; // Restore system errno - return C_ERR_PARAM; - } - - // Assign the computed scalar result out safely - *out_value = result; - - // Map pointer arithmetic distances back into the context of our indexing structural offset - if (out_end_index) { - *out_end_index = start_index + (c_size_t)(parse_end - start_ptr); - } - - errno = current_errno; // Restore system errno - return C_SUCCESS; -} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -c_err_t c_StringBuffer_SetLength(c_StringBuffer_t* sb, c_size_t new_length) { - // 1. Core safety verification of structural parameters - if (!sb) { - return C_ERR_PARAM; - } - - // 2. Case A: Truncation step (new_length is within current memory boundaries) - if (new_length <= sb->size) { - sb->size = new_length; - if (sb->buffer && sb->size < sb->capacity) { - sb->buffer[sb->size] = '\0'; // Seal the new structural boundary line instantly - } - return C_ERR_OK; - } - - // 3. Case B: Buffer Expansion step (new_length exceeds current logical boundary size) - // Verify if we need to resize the dynamic backing heap array matrix - if (new_length >= sb->capacity) { - c_size_t new_capacity = sb->capacity == 0 ? 16 : sb->capacity * 2; - if (new_capacity <= new_length) { - new_capacity = new_length + 1; // Secure extra room for the trailing null-terminator - } - - char* new_array = (char*)C_REALLOC(sb->buffer, new_capacity * sizeof(char)); - if (!new_array) { - return C_ERR_NOMEM; // Bubble up out-of-memory errors cleanly - } - sb->buffer = new_array; - sb->capacity = new_capacity; - } - - // 4. Zero-pad the newly appended logical spacing area segment - memset(sb->buffer + sb->size, 0, new_length - sb->size); - - // 5. Commit trailing metadata fields and place the final structural terminator string hook - sb->size = new_length; - sb->buffer[sb->size] = '\0'; - - return C_ERR_OK; -} diff --git a/Foundation/c_StringBuffer.h b/Foundation/c_StringBuffer.h deleted file mode 100644 index e620c8e..0000000 --- a/Foundation/c_StringBuffer.h +++ /dev/null @@ -1,116 +0,0 @@ -#ifndef INCLUDED_C_STRINGBUFFER_H -#define INCLUDED_C_STRINGBUFFER_H - -#ifndef INCLUDED_C_TYPES_H -#include -#endif /*INCLUDED_C_TYPES_H*/ - -#ifndef INCLUDED_STDARG_H -#define INCLUDED_STDARG_H -#include -#endif /*INCLUDED_STDARG_H*/ - - - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -typedef struct { - char* buffer; - c_size_t capacity; - c_size_t size; -}c_StringBuffer_t; - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -c_err_t c_StringBuffer_Init(c_StringBuffer_t* self, c_size_t capacity); - -void c_StringBuffer_Destroy(c_StringBuffer_t* self); - -c_err_t c_StringBuffer_Append(c_StringBuffer_t* self, const char* string, c_size_t length); - -c_err_t c_StringBuffer_Prepend(c_StringBuffer_t* self, const char* string, c_size_t length); - -c_err_t c_StringBuffer_InsertAt(c_StringBuffer_t* self, c_size_t index, const char* string, c_size_t length); - -c_err_t c_StringBuffer_RemoveAt(c_StringBuffer_t* self, c_size_t index, c_size_t length); - -void c_StringBuffer_Clear(c_StringBuffer_t* self); - -c_err_t c_StringBuffer_AppendStr(c_StringBuffer_t* self, const char* string); -c_err_t c_StringBuffer_PrependStr(c_StringBuffer_t* self, const char* string); -c_err_t c_StringBuffer_InsertStrAt(c_StringBuffer_t* self, const char* string, c_size_t index); - -c_err_t c_StringBuffer_CopyTo(c_StringBuffer_t* self, c_size_t index, c_size_t length, char* buffer, c_size_t buffer_length); - -c_err_t c_StringBuffer_Printf(c_StringBuffer_t* self, const char* format, ...); -c_err_t c_StringBuffer_PrintfAt(c_StringBuffer_t* self, c_size_t index, const char* format, ...); - -c_err_t c_StringBuffer_VPrintf(c_StringBuffer_t* self, const char* format, va_list args); -c_err_t c_StringBuffer_VPrintfAt(c_StringBuffer_t* self, c_size_t index, const char* format, va_list args); - -c_err_t c_StringBuffer_AppendTimestamp(c_StringBuffer_t* self, const char* format, const struct tm* time_info); -c_err_t c_StringBuffer_AppendCurrentTimestamp(c_StringBuffer_t* self, const char* format, int use_utc); -c_err_t c_StringBuffer_InsertTimestampAt(c_StringBuffer_t* self, c_size_t index, const char* format, const struct tm* time_info); - -c_index_t c_StringBuffer_IndexOfStr(c_StringBuffer_t* self, c_size_t start_index, const char* substr); -c_index_t c_StringBuffer_IndexOfChar(c_StringBuffer_t* self, c_size_t start_index, char target); -c_index_t c_StringBuffer_LastIndexOfStr(c_StringBuffer_t* self, c_size_t start_index, const char* substr); -c_index_t c_StringBuffer_LastIndexOfChar(c_StringBuffer_t* self, c_size_t start_index, char target); - -c_err_t c_StringBuffer_ReplaceStr(c_StringBuffer_t* self, const char* old_str, const char* new_str); - -c_err_t c_StringBuffer_Trim(c_StringBuffer_t* self); -c_err_t c_StringBuffer_TrimLeft(c_StringBuffer_t* self); -c_err_t c_StringBuffer_TrimRight(c_StringBuffer_t* self); - -c_err_t c_StringBuffer_ToLower(c_StringBuffer_t* self); -c_err_t c_StringBuffer_ToUpper(c_StringBuffer_t* self); - -/* - * 重新设计的 Split 函数 - * @param self: 原始字符串缓冲区指针 - * @param delimiter: 分隔符字符串(不能为 NULL 或空字符串) - * @param out_tokens: 输出参数,用于接收分配的 c_StringBuffer_t 结构体数组指针 - * @param out_count: 输出参数,用于接收拆分出来的 Token 总数 - */ -c_err_t c_StringBuffer_Split(c_StringBuffer_t* self, const char* delimiter, c_StringBuffer_t** out_tokens, c_size_t* out_count); - -c_err_t c_StringBuffer_Join(c_StringBuffer_t* self, const c_StringBuffer_t tokens[], c_size_t count, const char* separator); - -int c_StringBuffer_Equals(const c_StringBuffer_t* self, const char* string); -int c_StringBuffer_EqualsIgnoreCase(const c_StringBuffer_t* self, const char* string); - -int c_StringBuffer_Compare(const c_StringBuffer_t* self, const char* string); -c_err_t c_StringBuffer_Reverse(c_StringBuffer_t* self); - -c_err_t c_StringBuffer_Substr(const c_StringBuffer_t* self, c_size_t index, c_size_t length, c_StringBuffer_t* out_substring); -c_err_t c_StringBuffer_Slice(const c_StringBuffer_t* self, c_size_t start_index, c_size_t end_index, c_StringBuffer_t* out_slice); - -/* - * Parses an unsigned long value from the buffer starting at a specific index. - * @param self: The string buffer instance. - * @param start_index: The index position to start scanning from. - * @param base: The number base system to parse (0, 2-36). - * @param out_value: Destination pointer for the parsed unsigned long. - * @param out_end_index: Optional destination pointer for the index of the first character after the number. - */ -c_err_t c_StringBuffer_strtoul(const c_StringBuffer_t* self, c_size_t start_index, int base, unsigned long* out_value, c_size_t* out_end_index); - - -/** - * Set the logical character length of the string buffer. - * If the new length is less than the current size, the string is truncated. - * If the new length is greater, the buffer expands and is zero-padded. - * - * @param sb Pointer to the active c_StringBuffer_t instance - * @param new_length The targeted logical length boundary to apply - * @return - * - C_ERR_OK if success - * - C_ERR_PARAM if parameters are invalid - * - C_ERR_NOMEM if expansion fails due to system exhaustion - */ -c_err_t c_StringBuffer_SetLength(c_StringBuffer_t* sb, c_size_t new_length); - -#endif /*INCLUDED_C_STRINGBUFFER_H*/ diff --git a/Foundation/c_StringList.c b/Foundation/c_StringList.c deleted file mode 100644 index 48fd9a4..0000000 --- a/Foundation/c_StringList.c +++ /dev/null @@ -1,124 +0,0 @@ -#include -#include - -c_err_t c_StringList_Init(c_StringList* list, c_size_t initial_capacity) { - if (!list) return C_ERR_PARAM; - list->size = 0; - list->capacity = initial_capacity; - if (initial_capacity > 0) { - list->strings = (char**)C_ALLOC(initial_capacity * sizeof(char*)); - if (!list->strings) { - list->capacity = 0; - return C_ERR_NOMEM; - } - } else { - list->strings = NULL; - } - return C_ERR_OK; -} - -void c_StringList_Destroy(c_StringList* list) { - if (!list) return; - if (list->strings) { - for (c_size_t i = 0; i < list->size; i++) { - C_FREE(list->strings[i]); - } - C_FREE(list->strings); - } - list->size = 0; - list->capacity = 0; -} - -c_err_t c_StringList_Append(c_StringList* list, const char* str) { - if (!list || !str) return C_ERR_PARAM; - if (list->size >= list->capacity) { - c_size_t new_capacity = (list->capacity == 0) ? 4 : list->capacity * 2; - char** new_array = (char**)C_REALLOC(list->strings, new_capacity * sizeof(char*)); - if (!new_array) return C_ERR_NOMEM; - list->strings = new_array; - list->capacity = new_capacity; - } - char* copy = (char*)C_ALLOC(strlen(str) + 1); - if (!copy) return C_ERR_NOMEM; - strcpy(copy, str); - list->strings[list->size++] = copy; - return C_ERR_OK; -} - - -/** - * Insert a new null-terminated string copy row at the very front of the collection list (Index 0) - */ -c_err_t c_StringList_Prepend(c_StringList* list, const char* str) { - if (!list || !str) { - return C_ERR_PARAM; - } - - // 1. Dynamic scale check and array reallocation if capacity bounds are reached - if (list->size >= list->capacity) { - c_size_t new_capacity = (list->capacity == 0) ? 4 : list->capacity * 2; - char** new_array = (char**)C_REALLOC(list->strings, new_capacity * sizeof(char*)); - if (!new_array) { - return C_ERR_NOMEM; - } - list->strings = new_array; - list->capacity = new_capacity; - } - - // 2. Allocate an isolated deep-copy heap buffer for the incoming string characters - char* str_copy = (char*)C_ALLOC(strlen(str) + 1); - if (!str_copy) { - return C_ERR_NOMEM; - } - strcpy(str_copy, str); - - // 3. Shift all existing string pointer entries rightward by 1 to make room at index 0 - for (c_size_t i = list->size; i > 0; i--) { - list->strings[i] = list->strings[i - 1]; - } - - // 4. Place the newly allocated string capsule at the front and increment tracking metrics - list->strings[0] = str_copy; - list->size++; - - return C_ERR_OK; -} - -/** - * Remove the first occurrence of a string value from the collection. - * Cleans up memory allocations and tightly shifts elements to prevent layout leaks. - */ -c_err_t c_StringList_Remove(c_StringList* list, const char* str) { - if (!list || !list->strings || !str) { - return C_ERR_PARAM; - } - - c_size_t target_idx = (c_size_t)-1; - - // 1. Linearly scan the string array to locate a matching value match - for (c_size_t i = 0; i < list->size; i++) { - if (list->strings[i] != NULL && strcmp(list->strings[i], str) == 0) { - target_idx = i; - break; - } - } - - // If the targeted string value does not exist, return an error code parameter - if (target_idx == (c_size_t)-1) { - return C_ERR_PARAM; - } - - // 2. Safely free the individual string characters heap capsule - C_FREE(list->strings[target_idx]); // Safe macro automatically sets index entry to NULL - - // 3. Shift subsequent array entries leftward to maintain dense cache prefetching locality - for (c_size_t i = target_idx; i < list->size - 1; i++) { - list->strings[i] = list->strings[i + 1]; - } - - // 4. Update trailing metadata bounds - list->size--; - list->strings[list->size] = NULL; // Ensure the newly vacant tail slot is nullified safely - - return C_ERR_OK; -} diff --git a/Foundation/c_StringList.h b/Foundation/c_StringList.h deleted file mode 100644 index c88c9e5..0000000 --- a/Foundation/c_StringList.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef INCLUDED_C_STRINGLIST_H -#define INCLUDED_C_STRINGLIST_H - -#ifndef INCLUDED_C_TYPES_H -#include -#endif /*INCLUDED_C_TYPES_H*/ -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - - -typedef struct { - char** strings; // Dynamic array of self-owned null-terminated strings - c_size_t size; // Current active string rows stored - c_size_t capacity; // Max allocated capacity bounds of the internal pointer matrix -} c_StringList; - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -c_err_t c_StringList_Init(c_StringList* list, c_size_t initial_capacity); - -void c_StringList_Destroy(c_StringList* list); - -c_err_t c_StringList_Append(c_StringList* list, const char* str); - -c_err_t c_StringList_Prepend(c_StringList* list, const char* str); - -c_err_t c_StringList_Remove(c_StringList* list, const char* str); - -#endif /*INCLUDED_C_STRINGLIST_H*/ diff --git a/Foundation/c_Thread.c b/Foundation/c_Thread.c deleted file mode 100644 index 3884e29..0000000 --- a/Foundation/c_Thread.c +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/Foundation/c_Thread.h b/Foundation/c_Thread.h deleted file mode 100644 index bebb118..0000000 --- a/Foundation/c_Thread.h +++ /dev/null @@ -1,125 +0,0 @@ -#ifndef INCLUDED_C_THREAD_H -#define INCLUDED_C_THREAD_H - -#ifndef INCLUDED_C_TYPES_H -#include -#endif /*INCLUDED_C_TYPES_H*/ - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -typedef void* c_ThreadResult_t; - -#if defined(_WIN32) || defined(_WIN64) - #include - #include - typedef HANDLE c_Thread_t; - typedef DWORD c_ThreadId_t; // Windows 使用 DWORD 作为线程 ID - #define C_THREAD_FUNC_RETURN_TYPE unsigned __stdcall - #define C_THREAD_FUNC_RETURN_VTYPE unsigned -#else - #include - typedef pthread_t c_Thread_t; - typedef unsigned long c_ThreadId_t; // POSIX 转换为数字 ID - #define C_THREAD_FUNC_RETURN_TYPE void* - #define C_THREAD_FUNC_RETURN_VTYPE C_THREAD_FUNC_RETURN_TYPE -#endif - -// Universal thread creation signature -typedef C_THREAD_FUNC_RETURN_TYPE (*c_ThreadFn_t)(void*); - -C_STATIC_FORCE_INLINE -c_bool_t c_Thread_Create(c_Thread_t* thread, c_ThreadFn_t func, void* arg) { -#if defined(_WIN32) || defined(_WIN64) - // *thread = CreateThread(NULL, 0, func, arg, 0, NULL); - // return (*thread != NULL); - *thread = (HANDLE)_beginthreadex(NULL, 0, (unsigned (__stdcall *)(void*))func, arg, 0, NULL); - return (*thread != NULL); -#else - return (pthread_create(thread, NULL, func, arg) == 0); -#endif -} - -C_STATIC_FORCE_INLINE -void c_Thread_Join(c_Thread_t thread) { -#if defined(_WIN32) || defined(_WIN64) - WaitForSingleObject(thread, INFINITE); - CloseHandle(thread); -#else - pthread_join(thread, NULL); -#endif -} - -C_STATIC_FORCE_INLINE -void c_Thread_Sleep(unsigned int milliseconds) { - #if defined(_WIN32) || defined(_WIN64) - Sleep(milliseconds); - #else - usleep(milliseconds * 1000); - #endif -} - -C_STATIC_FORCE_INLINE -c_ThreadId_t c_Thread_SelfId(void) { -#if defined(_WIN32) || defined(_WIN64) - return GetCurrentThreadId(); -#else - return (c_ThreadId_t)pthread_self(); -#endif -} - -C_STATIC_FORCE_INLINE -c_bool_t c_Thread_Detach(c_Thread_t thread) { -#if defined(_WIN32) || defined(_WIN64) - // Windows 中,关闭线程句柄并不等于终止线程。 - // 它只是减少内核对象的引用计数。线程运行结束时,内核对象会自动销毁。 - // 这与 POSIX 的 detach 行为完全一致。 - if (thread != NULL) { - return (CloseHandle(thread) != 0); - } - return C_FALSE; -#else - // POSIX 直接使用 pthread_detach - return (pthread_detach(thread) == 0); -#endif -} - -C_STATIC_FORCE_INLINE -c_bool_t c_Thread_Equal(c_Thread_t t1, c_Thread_t t2) { -#if defined(_WIN32) || defined(_WIN64) - // Windows 下可以通过比较线程 ID 来判断是否为同一个线程 - // 即使其中一个是 GetCurrentThread() 产生的伪句柄,GetThreadId 也能正确识别 - return (GetThreadId(t1) == GetThreadId(t2)); -#else - // POSIX 提供专用的比较函数 - return (pthread_equal(t1, t2) != 0); -#endif -} - -C_STATIC_FORCE_INLINE -c_bool_t c_Thread_JoinWithResult(c_Thread_t thread, c_ThreadResult_t* out_result) { -#if defined(_WIN32) || defined(_WIN64) - if (WaitForSingleObject(thread, INFINITE) == WAIT_OBJECT_0) { - DWORD exit_code = 0; - if (GetExitCodeThread(thread, &exit_code)) { - if (out_result) { - // 将 DWORD 转换为指针类型输出 - *out_result = (c_ThreadResult_t)(uintptr_t)exit_code; - } - CloseHandle(thread); - return C_TRUE; - } - } - CloseHandle(thread); // 即使失败也尝试关闭句柄 - return C_FALSE; -#else - // POSIX 直接在 join 时传入指针变量的地址 - return (pthread_join(thread, out_result) == 0); -#endif -} - -#define c_Thread_Exit(x) return (C_THREAD_FUNC_RETURN_VTYPE)(x) - -#define c_Thread_Fn(fn) C_THREAD_FUNC_RETURN_TYPE fn - -#endif /*INCLUDED_C_THREAD_H*/ diff --git a/Foundation/c_ThreadPool.c b/Foundation/c_ThreadPool.c deleted file mode 100644 index 651d64e..0000000 --- a/Foundation/c_ThreadPool.c +++ /dev/null @@ -1,122 +0,0 @@ -#include -#include - -// Worker thread routine -static c_Thread_Fn(thread_pool_worker(void* arg)) { - c_ThreadPool_t* pool = (c_ThreadPool_t*)arg; - c_ThreadPoolTask_t* task; - while (!pool->is_shutdown) { - task = NULL; - - // Use a 500ms timeout for timedpop to allow periodic shutdown condition verification - if (c_LockQueue_TimedPop(&pool->task_queue, (void**)&task, pool->check_interval_ms)!=C_ERR_OK) { - if (task) { - if (task->function) { - // Execute user payload safely - task->function(task->argument); - } - // C_FREE(task); // Free the memory allocated for the task wrapper - c_Pool_Free(&pool->task_pool, task); - } - } - } - c_Thread_Exit(0); -} - -/** - * @brief Initializes a fixed-size thread pool. - */ -c_err_t c_ThreadPool_Init(c_ThreadPool_t* pool, int thread_count, int queue_capacity, int task_pool_size, int check_interval_ms) { - if (!pool || thread_count <= 0 || queue_capacity <= 0) return C_ERR_PARAM; - - pool->is_shutdown = C_FALSE; - pool->thread_count = thread_count; - pool->check_interval_ms = check_interval_ms; - - if (c_Pool_Init(&pool->task_pool, sizeof(c_ThreadPoolTask_t), task_pool_size)!=C_ERR_OK) { - return C_ERR_FAIL; - } - - // Allocate the thread handle array - pool->threads = (c_Thread_t*)C_ALLOC(sizeof(c_Thread_t) * thread_count); - if (!pool->threads) { - return C_ERR_NOMEM; - } - - // Initialize our previously constructed cross-platform thread-safe queue - c_err_t err = c_LockQueue_Init(&pool->task_queue, queue_capacity); - if (err!=C_ERR_OK) { - C_FREE(pool->threads); - return err; - } - - // Spawn the requested worker threads - for (int i = 0; i < thread_count; i++) { - if (!c_Thread_Create(&pool->threads[i], thread_pool_worker, pool)) { - // Rollback strategy on failures - pool->is_shutdown = C_TRUE; - c_LockQueue_Shutdown(&pool->task_queue); - for (int j = 0; j < i; j++) { - c_Thread_Join(pool->threads[j]); - } - c_LockQueue_Destroy(&pool->task_queue); - C_FREE(pool->threads); - return C_ERR_FAIL; - } - } - - return C_ERR_OK; -} - -/** - * @brief Submits a work payload to the pool. - */ -c_bool_t c_ThreadPool_Submit(c_ThreadPool_t* pool, void (*function)(void*), void* argument){ - if (!pool || !function || pool->is_shutdown) return C_FALSE; - - // c_ThreadPoolTask_t* task = (c_ThreadPoolTask_t*)C_ALLOC(sizeof(*task)); - c_ThreadPoolTask_t* task = c_Pool_Alloc(&pool->task_pool); - if (!task) return C_FALSE; - - task->function = function; - task->argument = argument; - - // Push the task into our thread-safe buffer. If full, this blocks the calling thread - if (c_LockQueue_Push(&pool->task_queue, task)!=C_ERR_OK) { - C_FREE(task); - return C_FALSE; - } - - return C_TRUE; -} - -/** - * @brief Orderly terminates the thread pool, waiting for running jobs to finish. - */ -void c_ThreadPool_Destroy(c_ThreadPool_t* pool) { - if (!pool) return; - - // 1. Terminate the processing loop - pool->is_shutdown = C_TRUE; - - // 2. Shut down the queue to unblock workers waiting indefinitely - c_LockQueue_Shutdown(&pool->task_queue); - - // 3. Join all worker threads safely - for (int i = 0; i < pool->thread_count; i++) { - c_Thread_Join(pool->threads[i]); - } - - // 4. Drain any remaining unexecuted tasks to prevent memory leaks - // void* unexecuted_task = NULL; - // while (c_LockQueue_Pop(&pool->task_queue, &unexecuted_task)==C_ERR_SUCCESS) { - // C_FREE(unexecuted_task); - // } - c_Pool_DryUp(&pool->task_pool); - c_Pool_Destroy(&pool->task_pool); - - // 5. Reclaim memory structures - c_LockQueue_Destroy(&pool->task_queue); - C_FREE(pool->threads); -} - diff --git a/Foundation/c_ThreadPool.h b/Foundation/c_ThreadPool.h deleted file mode 100644 index 248ce5c..0000000 --- a/Foundation/c_ThreadPool.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef INCLUDED_C_THREADPOOL_H -#define INCLUDED_C_THREADPOOL_H - -#ifndef INCLUDED_C_LOCKQUEUE_H -#include -#endif /*INCLUDED_C_LOCKQUEUE_H*/ - -#ifndef INCLUDED_C_THREAD_H -#include -#endif /*INCLUDED_C_THREAD_H*/ - -#ifndef INCLUDED_C_POOL_H -#include -#endif /*INCLUDED_C_POOL_H*/ - - - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -// Struct representing a single executable unit of work -typedef struct { - void (*function)(void*); // Pointer to the user function - void* argument; // Argument passed to the function -} c_ThreadPoolTask_t; - -typedef struct { - c_LockQueue_t task_queue; // Safe queue storing thread_pool_task_t pointers - c_Thread_t* threads; // Array of worker thread handles - int thread_count; // Total number of worker threads - volatile c_bool_t is_shutdown; // Shutdown flag - int check_interval_ms; - c_Pool_t task_pool; -} c_ThreadPool_t; - -// Public Core API -c_err_t c_ThreadPool_Init(c_ThreadPool_t* pool, int thread_count, int queue_capacity, int task_pool_size, int check_interval_ms); - -void c_ThreadPool_Destroy(c_ThreadPool_t* pool); - -c_bool_t c_ThreadPool_Submit(c_ThreadPool_t* pool, void (*function)(void*), void* argument); - - -#endif /*INCLUDED_C_THREADPOOL_H*/ diff --git a/Foundation/c_ThreadPool.t.c b/Foundation/c_ThreadPool.t.c deleted file mode 100644 index be18b81..0000000 --- a/Foundation/c_ThreadPool.t.c +++ /dev/null @@ -1,39 +0,0 @@ -#include "c_ThreadPool.h" -#include -#include - -// Sample payload mimicking work -void compute_square(void* arg) { - int val = *(int*)arg; - printf("[Thread Pool Task] Processing square of %d = %d\n", val, val * val); - free(arg); // Free parameter memory passed during submission -} - - -int main(int argc, char** argv){ - // Create a pool with 4 worker threads and a max capacity of 20 pending tasks - c_ThreadPool_t pool = {0}; - c_ThreadPool_Init(&pool, 4, 20, 10, 500); - - printf("--- Thread Pool Initialized with 4 Workers ---\n"); - - // Queue 10 dynamic processing computations - for (int i = 1; i <= 10; i++) { - int* num = (int*)malloc(sizeof(int)); - *num = i; - if (!c_ThreadPool_Submit(&pool, compute_square, num)) { - fprintf(stderr, "[Thread Pool Task] Submit %d failed\n", i); - } - } - - // Force main to simulate work before cleaning up - printf("All tasks submitted. Waiting for processing to settle...\n"); - - c_Thread_Sleep(2000); - - printf("--- Destroying Thread Pool ---\n"); - c_ThreadPool_Destroy(&pool); - printf("Thread pool destroyed cleanly.\n"); - - return 0; -} diff --git a/Foundation/c_timespec.c b/Foundation/c_timespec.c deleted file mode 100644 index c3bc468..0000000 --- a/Foundation/c_timespec.c +++ /dev/null @@ -1,98 +0,0 @@ -#include -#include - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - - -struct timespec c_timespec_mod(struct timespec ts1, struct timespec ts2) -{ - int i = 0; - bool neg1 = false; - bool neg2 = false; - - /* Normalise inputs to prevent tv_nsec rollover if whole-second values - * are packed in it. - */ - ts1 = c_timespec_normalise(ts1); - ts2 = c_timespec_normalise(ts2); - - /* If ts2 is zero, just return ts1 - */ - if (ts2.tv_sec == 0 && ts2.tv_nsec == 0) - { - return ts1; - } - - /* If inputs are negative, flip and record sign - */ - if (ts1.tv_sec < 0 || ts1.tv_nsec < 0) - { - neg1 = true; - ts1.tv_sec = -ts1.tv_sec; - ts1.tv_nsec = -ts1.tv_nsec; - } - - if (ts2.tv_sec < 0 || ts2.tv_nsec < 0) - { - neg2 = true; - ts2.tv_sec = -ts2.tv_sec; - ts2.tv_nsec = -ts2.tv_nsec; - } - - /* Shift ts2 until it is larger than ts1 or is about to overflow - */ - while ((ts2.tv_sec < (LONG_MAX >> 1)) && c_timespec_ge(ts1, ts2)) - { - i++; - ts2.tv_nsec <<= 1; - ts2.tv_sec <<= 1; - if (ts2.tv_nsec > C_NSEC_PER_SEC) - { - ts2.tv_nsec -= C_NSEC_PER_SEC; - ts2.tv_sec++; - } - } - - /* Division by repeated subtraction - */ - while (i >= 0) - { - if (c_timespec_ge(ts1, ts2)) - { - ts1 = c_timespec_sub(ts1, ts2); - } - - if (i == 0) - { - break; - } - - i--; - if (ts2.tv_sec & 1) - { - ts2.tv_nsec += C_NSEC_PER_SEC; - } - ts2.tv_nsec >>= 1; - ts2.tv_sec >>= 1; - } - - /* If signs differ and result is nonzero, subtract once more to cross zero - */ - if (neg1 ^ neg2 && (ts1.tv_sec != 0 || ts1.tv_nsec != 0)) - { - ts1 = c_timespec_sub(ts1, ts2); - } - - /* Restore sign - */ - if (neg1) - { - ts1.tv_sec = -ts1.tv_sec; - ts1.tv_nsec = -ts1.tv_nsec; - } - - return ts1; -} - - diff --git a/Foundation/c_timespec.h b/Foundation/c_timespec.h deleted file mode 100644 index 8596777..0000000 --- a/Foundation/c_timespec.h +++ /dev/null @@ -1,258 +0,0 @@ -#ifndef INCLUDED_C_TIMESPEC_H -#define INCLUDED_C_TIMESPEC_H - -#ifndef INCLUDED_C_TYPES_H -#include -#endif /*INCLUDED_C_TYPES_H*/ - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -#define C_NSEC_PER_USEC 1000L -#define C_USEC_PER_MSEC 1000L -#define C_MSEC_PER_SEC 1000L -#define C_NSEC_PER_MSEC 1000000L -#define C_USEC_PER_SEC 1000000L -#define C_NSEC_PER_SEC 1000000000L - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -C_STATIC_FORCE_INLINE -struct timespec c_timespec_normalise(struct timespec ts) -{ - while(ts.tv_nsec >= C_NSEC_PER_SEC) - { - ++(ts.tv_sec); - ts.tv_nsec -= C_NSEC_PER_SEC; - } - - while(ts.tv_nsec <= -C_NSEC_PER_SEC) - { - --(ts.tv_sec); - ts.tv_nsec += C_NSEC_PER_SEC; - } - - if(ts.tv_nsec < 0) - { - /* Negative nanoseconds isn't valid according to POSIX. - * Decrement tv_sec and roll tv_nsec over. - */ - - --(ts.tv_sec); - ts.tv_nsec = (C_NSEC_PER_SEC + ts.tv_nsec); - } - - return ts; -} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -C_STATIC_FORCE_INLINE -struct timespec c_timespec_add(struct timespec ts1, struct timespec ts2) -{ - /* Normalise inputs to prevent tv_nsec rollover if whole-second values - * are packed in it. - */ - ts1 = c_timespec_normalise(ts1); - ts2 = c_timespec_normalise(ts2); - - ts1.tv_sec += ts2.tv_sec; - ts1.tv_nsec += ts2.tv_nsec; - - return c_timespec_normalise(ts1); -} - -C_STATIC_FORCE_INLINE -struct timespec c_timespec_sub(struct timespec ts1, struct timespec ts2) -{ - /* Normalise inputs to prevent tv_nsec rollover if whole-second values - * are packed in it. - */ - ts1 = c_timespec_normalise(ts1); - ts2 = c_timespec_normalise(ts2); - - ts1.tv_sec -= ts2.tv_sec; - ts1.tv_nsec -= ts2.tv_nsec; - - return c_timespec_normalise(ts1); -} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - - - -C_STATIC_FORCE_INLINE -int c_timespec_cmp(struct timespec ts1, struct timespec ts2) -{ - ts1 = c_timespec_normalise(ts1); - ts2 = c_timespec_normalise(ts2); - - if(ts1.tv_sec == ts2.tv_sec && ts1.tv_nsec == ts2.tv_nsec) - { - return 0; - } - else if((ts1.tv_sec > ts2.tv_sec) - || (ts1.tv_sec == ts2.tv_sec && ts1.tv_nsec > ts2.tv_nsec)) - { - return 1; - } - else { - return -1; - } -} - -C_STATIC_FORCE_INLINE -bool c_timespec_eq(struct timespec ts1, struct timespec ts2) -{ - ts1 = c_timespec_normalise(ts1); - ts2 = c_timespec_normalise(ts2); - - return (ts1.tv_sec == ts2.tv_sec && ts1.tv_nsec == ts2.tv_nsec); -} - -C_STATIC_FORCE_INLINE -bool c_timespec_gt(struct timespec ts1, struct timespec ts2) -{ - ts1 = c_timespec_normalise(ts1); - ts2 = c_timespec_normalise(ts2); - - return (ts1.tv_sec > ts2.tv_sec || (ts1.tv_sec == ts2.tv_sec && ts1.tv_nsec > ts2.tv_nsec)); -} - -C_STATIC_FORCE_INLINE -bool c_timespec_ge(struct timespec ts1, struct timespec ts2) -{ - ts1 = c_timespec_normalise(ts1); - ts2 = c_timespec_normalise(ts2); - - return (ts1.tv_sec > ts2.tv_sec || (ts1.tv_sec == ts2.tv_sec && ts1.tv_nsec >= ts2.tv_nsec)); -} - -C_STATIC_FORCE_INLINE -bool c_timespec_lt(struct timespec ts1, struct timespec ts2) -{ - ts1 = c_timespec_normalise(ts1); - ts2 = c_timespec_normalise(ts2); - - return (ts1.tv_sec < ts2.tv_sec || (ts1.tv_sec == ts2.tv_sec && ts1.tv_nsec < ts2.tv_nsec)); -} - -C_STATIC_FORCE_INLINE -bool c_timespec_le(struct timespec ts1, struct timespec ts2) -{ - ts1 = c_timespec_normalise(ts1); - ts2 = c_timespec_normalise(ts2); - - return (ts1.tv_sec < ts2.tv_sec || (ts1.tv_sec == ts2.tv_sec && ts1.tv_nsec <= ts2.tv_nsec)); -} - -C_STATIC_FORCE_INLINE -struct timespec c_timespec_min(struct timespec ts1, struct timespec ts2) { - if(c_timespec_le(ts1, ts2)) { - return ts1; - } else { - return ts2; - } -} - -C_STATIC_FORCE_INLINE -struct timespec c_timespec_max(struct timespec ts1, struct timespec ts2) { - if(c_timespec_ge(ts1, ts2)) { - return ts1; - } else { - return ts2; - } -} - -C_STATIC_FORCE_INLINE -struct timespec c_timespec_clamp(struct timespec ts, struct timespec min, struct timespec max) { - if(c_timespec_gt(ts, max)) { - return max; - } - if(c_timespec_lt(ts, min)) { - return min; - } - return ts; -} - - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - - -C_STATIC_FORCE_INLINE -struct timespec c_timespec_from_double(double s) -{ - struct timespec ts = { - .tv_sec = s, - .tv_nsec = (s - (long)(s)) * C_NSEC_PER_SEC, - }; - - return c_timespec_normalise(ts); -} - - - -C_STATIC_FORCE_INLINE -double c_timespec_to_double(struct timespec ts) -{ - return ((double)(ts.tv_sec) + ((double)(ts.tv_nsec) / C_NSEC_PER_SEC)); -} - - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -C_STATIC_FORCE_INLINE -struct timespec c_timespec_from_timeval(struct timeval tv) -{ - struct timespec ts = { - .tv_sec = tv.tv_sec, - .tv_nsec = tv.tv_usec * C_NSEC_PER_USEC - }; - - return c_timespec_normalise(ts); -} - -C_STATIC_FORCE_INLINE -struct timeval c_timespec_to_timeval(struct timespec ts) -{ - ts = c_timespec_normalise(ts); - - struct timeval tv = { - .tv_sec = ts.tv_sec, - .tv_usec = ts.tv_nsec / C_NSEC_PER_USEC, - }; - - return tv; -} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -C_STATIC_FORCE_INLINE -struct timespec c_timespec_from_ms(long milliseconds) -{ - struct timespec ts = { - .tv_sec = (milliseconds / C_MSEC_PER_SEC), - .tv_nsec = (milliseconds % C_MSEC_PER_SEC) * C_NSEC_PER_MSEC, - }; - - return c_timespec_normalise(ts); -} - -C_STATIC_FORCE_INLINE -long c_timespec_to_ms(struct timespec ts) -{ - return (ts.tv_sec * C_MSEC_PER_SEC) + (ts.tv_nsec / C_NSEC_PER_MSEC); -} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -struct timespec c_timespec_mod(struct timespec ts1, struct timespec ts2); - -#endif /*INCLUDED_C_TIMESPEC_H*/ diff --git a/Foundation/c_utf8.c b/Foundation/c_utf8.c deleted file mode 100644 index 37b7147..0000000 --- a/Foundation/c_utf8.c +++ /dev/null @@ -1,817 +0,0 @@ -#include - -c_size_t c_utf8_strlen(const char* str) { - if (!str) return 0; - - c_size_t char_count = 0; - c_size_t i = 0; - - while (str[i] != '\0') { - i += c_utf8_char_len(str[i]); // 跳过当前字符占用的全部字节 - char_count++; - } - - return char_count; -} - -const char* c_utf8_strchr(const char* str, const char* utf8_char) { - if (!str || !utf8_char || utf8_char[0] == '\0') return NULL; - - c_size_t target_bytes = c_utf8_char_len(utf8_char[0]); - c_size_t i = 0; - - while (str[i] != '\0') { - c_size_t curr_bytes = c_utf8_char_len(str[i]); - - // 当且仅当两个字符占用的字节数相同,且多字节内容完全一致时匹配成功 - if (curr_bytes == target_bytes) { - if (memcmp(&str[i], utf8_char, target_bytes) == 0) { - return &str[i]; - } - } - i += curr_bytes; // 移动到下一个 UTF-8 字符 - } - - return NULL; -} - -char* c_utf8_strncpy(char* dest, const char* src, c_size_t char_num) { - if (!dest || !src || char_num == 0) return dest; - - c_size_t src_idx = 0; - c_size_t dest_idx = 0; - c_size_t copied_chars = 0; - - while (src[src_idx] != '\0' && copied_chars < char_num) { - c_size_t char_bytes = c_utf8_char_len(src[src_idx]); - - // 批量精确拷贝当前完整字符的 N 个字节 - memcpy(&dest[dest_idx], &src[src_idx], char_bytes); - - src_idx += char_bytes; - dest_idx += char_bytes; - copied_chars++; - } - - // 兼容 strncpy 标准:如果源串长度小于 char_num,则用 '\0' 填充剩余的空隙 - // 注意:这里的剩余空隙在实际工程中通常按字节填充更安全 - dest[dest_idx] = '\0'; - - return dest; -} - -int c_utf8_strncmp(const char* str1, const char* str2, c_size_t char_num) { - if (!str1 || !str2 || char_num == 0) return 0; - - c_size_t idx1 = 0; - c_size_t idx2 = 0; - c_size_t compared_chars = 0; - - while (compared_chars < char_num) { - // 任意一端到达末尾 - if (str1[idx1] == '\0' || str2[idx2] == '\0') { - return (int)((unsigned char)str1[idx1] - (unsigned char)str2[idx2]); - } - - c_size_t len1 = c_utf8_char_len(str1[idx1]); - c_size_t len2 = c_utf8_char_len(str2[idx2]); - - // 如果单字长字节不相等,直接根据当前字符进行排序比较 - if (len1 != len2) { - return (int)((unsigned char)str1[idx1] - (unsigned char)str2[idx2]); - } - - // 长度相同时,直接比较当前单个 UTF-8 字符的内容 - int res = memcmp(&str1[idx1], &str2[idx2], len1); - if (res != 0) { - return res; - } - - idx1 += len1; - idx2 += len2; - compared_chars++; - } - - return 0; -} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -char* c_utf8_tolower(char* str) { - if (!str) return NULL; - - c_size_t i = 0; - while (str[i] != '\0') { - unsigned char b1 = (unsigned char)str[i]; - c_size_t len = c_utf8_char_len(str[i]); - - // Case A: Standard Single-byte ASCII Case Folding - if (len == 1) { - if (b1 >= 'A' && b1 <= 'Z') { - str[i] = (char)(b1 + 32); - } - } - // Case B: Double-byte UTF-8 Case Folding (e.g., Cyrillic / Greek scripts) - else if (len == 2) { - unsigned char b2 = (unsigned char)str[i + 1]; - - // Cyrillic script transformations (Capital letters: 0xD0 0x80 to 0xD0 0xBF) - if (b1 == 0xD0) { - if (b2 >= 0x90 && b2 <= 0xAF) { - // Shift to lowercase variant range located inside 0xD0 / 0xD1 blocks - str[i + 1] = (char)(b2 + 0x20); - } else if (b2 >= 0xB0 && b2 <= 0xBF) { - str[i] = (char)0xD1; - str[i + 1] = (char)(b2 - 0x20); - } - } - // Greek script transformations (Capital letters: 0xCE 0x91 to 0xCE 0xAB) - else if (b1 == 0xCE) { - if (b2 >= 0x91 && b2 <= 0xAB && b2 != 0xA2) { // 0xA2 is a special variant - // Shift down to lowercase variant range block inside 0xCE / 0xCF - if (b2 <= 0x9F) { - str[i + 1] = (char)(b2 + 0x20); - } else { - str[i] = (char)0xCF; - str[i + 1] = (char)(b2 - 0x20); - } - } - } - } - // Multi-byte Chinese ideographs (3 bytes) and Emojis (4 bytes) lack casing concepts; step past them - i += len; - } - - return str; -} - - -char* c_utf8_toupper(char* str) { - if (!str) return NULL; - - c_size_t i = 0; - while (str[i] != '\0') { - unsigned char b1 = (unsigned char)str[i]; - c_size_t len = c_utf8_char_len(str[i]); - - // Case A: Standard Single-byte ASCII Case Folding - if (len == 1) { - if (b1 >= 'a' && b1 <= 'z') { - str[i] = (char)(b1 - 32); - } - } - // Case B: Double-byte UTF-8 Case Folding (e.g., Cyrillic / Greek scripts) - else if (len == 2) { - unsigned char b2 = (unsigned char)str[i + 1]; - - // Cyrillic script transformations (Lowercase letters: 0xD0 0xB0 to 0xD0 0xBF, and 0xD1 0x80 to 0xD1 0x8F) - if (b1 == 0xD0) { - if (b2 >= 0xB0 && b2 <= 0xBF) { - // Shift up to uppercase variant range located inside the 0xD0 block - str[i + 1] = (char)(b2 - 0x20); - } - } else if (b1 == 0xD1) { - if (b2 >= 0x80 && b2 <= 0x8F) { - // Convert leading byte from 0xD1 back to 0xD0 and realign low byte - str[i] = (char)0xD0; - str[i + 1] = (char)(b2 + 0x20); - } - } - // Greek script transformations (Lowercase letters: 0xCE 0xB1 to 0xCE 0xBF, and 0xCF 0x80 to 0xCF 0x8B) - else if (b1 == 0xCE) { - if (b2 >= 0xB1 && b2 <= 0xBF) { - // Shift down to uppercase variant range block inside 0xCE - str[i + 1] = (char)(b2 - 0x20); - } - } else if (b1 == 0xCF) { - if (b2 >= 0x80 && b2 <= 0x8B) { - // Convert leading byte from 0xCF back to 0xCE and realign low byte - str[i] = (char)0xCE; - str[i + 1] = (char)(b2 + 0x20); - } - } - } - // 3-byte characters (Chinese Ideographs) and 4-byte characters (Emojis) lack casing concepts; jump past them safely - i += len; - } - - return str; -} - - -char* c_utf8_strcat(char* dest, const char* src) { - if (!dest || !src) return dest; - - // Locate the termination boundary point of the original destination array - c_size_t dest_idx = 0; - while (dest[dest_idx] != '\0') { - dest_idx++; - } - - // Continuously append source bytes until hitting the terminator character - c_size_t src_idx = 0; - while (src[src_idx] != '\0') { - dest[dest_idx++] = src[src_idx++]; - } - - // Force secure terminal character sealing - dest[dest_idx] = '\0'; - - return dest; -} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -const char* c_utf8_strstr(const char* haystack, const char* needle) { - if (!haystack || !needle) return NULL; - - // An empty needle matches the beginning of the haystack per standard strstr specification - if (needle[0] == '\0') { - return haystack; - } - - c_size_t h_idx = 0; - while (haystack[h_idx] != '\0') { - c_size_t n_idx = 0; - c_size_t current_match_idx = h_idx; - - // Perform byte-by-byte substring evaluation from the current boundary anchor - while (haystack[current_match_idx] != '\0' && needle[n_idx] != '\0' && - haystack[current_match_idx] == needle[n_idx]) { - current_match_idx++; - n_idx++; - } - - // If we successfully traversed the entire needle string, a match is found - if (needle[n_idx] == '\0') { - return &haystack[h_idx]; - } - - // Advance to the next valid UTF-8 character point in the haystack - h_idx += c_utf8_char_len(haystack[h_idx]); - } - - return NULL; -} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ -#include - -const char* c_utf8_strrchr(const char* str, const char* utf8_char) { - if (!str || !utf8_char || utf8_char[0] == '\0') return NULL; - - c_size_t target_bytes = c_utf8_char_len(utf8_char[0]); - c_size_t i = 0; - const char* last_match = NULL; - - while (str[i] != '\0') { - c_size_t curr_bytes = c_utf8_char_len(str[i]); - - // Continuous linear check, updating our tracker to keep the furthest matched offset - if (curr_bytes == target_bytes) { - if (memcmp(&str[i], utf8_char, target_bytes) == 0) { - last_match = &str[i]; - } - } - i += curr_bytes; // Jump forward explicitly across whole multi-byte characters - } - - return last_match; -} - -/** - * @brief Internal helper to verify if a specific UTF-8 character pointer matches any delimiter in the list. - */ -C_STATIC_FORCE_INLINE -c_bool_t c_utf8_is_delim(const char* current_char, const char* delims, c_size_t* delim_len) { - c_size_t d_idx = 0; - c_size_t c_len = c_utf8_char_len(*current_char); - - while (delims[d_idx] != '\0') { - c_size_t d_len = c_utf8_char_len(delims[d_idx]); - if (c_len == d_len && memcmp(current_char, &delims[d_idx], c_len) == 0) { - *delim_len = d_len; - return C_TRUE; - } - d_idx += d_len; - } - return C_FALSE; -} - -char* c_utf8_strtok(char* str, const char* delims, char** saveptr) { - if (!delims || !saveptr) return NULL; - - // Use our saved pointer context if str is passed as NULL - char* token_cursor = (str != NULL) ? str : *saveptr; - if (!token_cursor || *token_cursor == '\0') { - return NULL; - } - - // Step 1: Skip over any leading delimiter sequences to locate the token start - c_size_t skip_len = 0; - while (*token_cursor != '\0' && c_utf8_is_delim(token_cursor, delims, &skip_len)) { - token_cursor += skip_len; - } - - // If we hit the absolute end of the input string while skipping delims, no tokens exist - if (*token_cursor == '\0') { - *saveptr = token_cursor; - return NULL; - } - - char* token_start = token_cursor; - - // Step 2: Track forward to locate the terminal delimiter boundary of this token - while (*token_cursor != '\0') { - c_size_t next_char_len = c_utf8_char_len(*token_cursor); - c_size_t match_delim_len = 0; - - if (c_utf8_is_delim(token_cursor, delims, &match_delim_len)) { - // Found a boundary delimiter! Overwrite its leading byte with a null terminator - *token_cursor = '\0'; - // Save state context tracking pointing immediately past the clipped delimiter - *saveptr = token_cursor + match_delim_len; - return token_start; - } - token_cursor += next_char_len; - } - - // If we reached the end of the text string naturally, ensure the saveptr updates to string termination - *saveptr = token_cursor; - return token_start; -} - - -/** - * @brief Internal helper to return the uppercase variant value of a single ASCII or 2-byte UTF-8 character. - * Returns the original trailing byte structure if no case mapping applies. - */ -C_STATIC_FORCE_INLINE -void c_utf8_fold_char(const char* src, size_t len, unsigned char* out_b1, unsigned char* out_b2) { - *out_b1 = (unsigned char)src[0]; - *out_b2 = (len > 1) ? (unsigned char)src[1] : 0; - - // Single-byte ASCII case folding - if (len == 1) { - if (*out_b1 >= 'a' && *out_b1 <= 'z') { - *out_b1 -= 32; - } - } - // Double-byte UTF-8 case folding (Cyrillic & Greek scripts) - else if (len == 2) { - // Cyrillic script: 0xD0 0xB0...0xBF to 0xD0 0x90...0x9F; 0xD1 0x80...0x8F to 0xD0 0xA0...0xAF - if (*out_b1 == 0xD0) { - if (*out_b2 >= 0xB0 && *out_b2 <= 0xBF) { - *out_b2 -= 0x20; - } - } else if (*out_b1 == 0xD1) { - if (*out_b2 >= 0x80 && *out_b2 <= 0x8F) { - *out_b1 = 0xD0; - *out_b2 += 0x20; - } - } - // Greek script: 0xCE 0xB1...0xBF to 0xCE 0x91...0x9F; 0xCF 0x80...0x8B to 0xCE 0xA0...0xAB - else if (*out_b1 == 0xCE) { - if (*out_b2 >= 0xB1 && *out_b2 <= 0xBF) { - *out_b2 -= 0x20; - } - } else if (*out_b1 == 0xCF) { - if (*out_b2 >= 0x80 && *out_b2 <= 0x8B) { - *out_b1 = 0xCE; - *out_b2 += 0x20; - } - } - } -} - -int c_utf8_strncasecmp(const char* str1, const char* str2, c_size_t char_num) { - if (!str1 || !str2 || char_num == 0) return 0; - - c_size_t idx1 = 0; - c_size_t idx2 = 0; - c_size_t compared_chars = 0; - - while (compared_chars < char_num) { - // Handle termination boundaries gracefully - if (str1[idx1] == '\0' || str2[idx2] == '\0') { - return (int)((unsigned char)str1[idx1] - (unsigned char)str2[idx2]); - } - - c_size_t len1 = c_utf8_char_len(str1[idx1]); - c_size_t len2 = c_utf8_char_len(str2[idx2]); - - // Fold characters to uppercase form for comparison - unsigned char f1_b1, f1_b2; - unsigned char f2_b1, f2_b2; - c_utf8_fold_char(&str1[idx1], len1, &f1_b1, &f1_b2); - c_utf8_fold_char(&str2[idx2], len2, &f2_b1, &f2_b2); - - // Compare first bytes or script widths - if (f1_b1 != f2_b1) { - return (int)f1_b1 - (int)f2_b1; - } - - // Compare second bytes (relevant for 2-byte sequences) - if (f1_b2 != f2_b2) { - return (int)f1_b2 - (int)f2_b2; - } - - // For 3-byte (Chinese) or 4-byte characters, fallback to raw memory comparison if lead bytes matched - if (len1 > 2) { - if (len1 != len2) { - return (int)len1 - (int)len2; - } - int raw_res = memcmp(&str1[idx1], &str2[idx2], len1); - if (raw_res != 0) { - return raw_res; - } - } - - // Advance iteration offsets - idx1 += len1; - idx2 += len2; - compared_chars++; - } - - return 0; -} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -c_err_t c_utf8_to_unicode(const char* str, c_ucs4_t* out_codepoint, c_size_t* out_bytes_consumed) { - if (!str || *str == '\0' || !out_codepoint || !out_bytes_consumed) { - return C_ERR_PARAM; - } - - unsigned char b1 = (unsigned char)str[0]; - c_size_t len = c_utf8_char_len(str[0]); - c_ucs4_t cp = 0; - - // Case 1: 1-Byte ASCII (0xxxxxxx) - if (len == 1) { - if (b1 >= 0x80) return C_ERR_PARAM; // Guard against malformed lead bytes - cp = b1; - } - // Case 2: 2-Byte Sequence (110xxxxx 10xxxxxx) - else if (len == 2) { - unsigned char b2 = (unsigned char)str[1]; - if ((b2 & 0xC0) != 0x80) return C_ERR_PARAM; // Validate continuation byte - - cp = ((b1 & 0x1F) << 6) | (b2 & 0x3F); - if (cp < 0x80) return C_ERR_PARAM; // Overlong encoding defense - } - // Case 3: 3-Byte Sequence (1110xxxx 10xxxxxx 10xxxxxx) - else if (len == 3) { - unsigned char b2 = (unsigned char)str[1]; - unsigned char b3 = (unsigned char)str[2]; - if ((b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80) return C_ERR_PARAM; - - cp = ((b1 & 0x0F) << 12) | ((b2 & 0x3F) << 6) | (b3 & 0x3F); - if (cp < 0x0800) return C_ERR_PARAM; // Overlong encoding defense - if (cp >= 0xD800 && cp <= 0xDFFF) return C_ERR_PARAM; // Surrogate pairs rejection - } - // Case 4: 4-Byte Sequence (11110xxx 10xxxxxx 10xxxxxx 10xxxxxx) - else if (len == 4) { - unsigned char b2 = (unsigned char)str[1]; - unsigned char b3 = (unsigned char)str[2]; - unsigned char b4 = (unsigned char)str[3]; - if ((b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80 || (b4 & 0xC0) != 0x80) return C_ERR_PARAM; - - cp = ((b1 & 0x07) << 18) | ((b2 & 0x3F) << 12) | ((b3 & 0x3F) << 6) | (b4 & 0x3F); - if (cp < 0x010000) return C_ERR_PARAM; // Overlong encoding defense - } - else { - return C_ERR_PARAM; - } - - // Limit validation (Unicode max standard is U+10FFFF) - if (cp > 0x10FFFF) { - return C_ERR_PARAM; - } - - *out_codepoint = cp; - *out_bytes_consumed = len; - return C_ERR_OK; -} - - -c_err_t c_utf8_from_unicode(c_ucs4_t codepoint, char* dest_buffer, c_size_t* out_bytes_written) { - if (!dest_buffer || !out_bytes_written) { - return C_ERR_PARAM; - } - - // Reject out-of-range codepoints or UTF-16 surrogate pairs (reserved for UTF-16 only) - if (codepoint > 0x10FFFF || (codepoint >= 0xD800 && codepoint <= 0xDFFF)) { - return C_ERR_PARAM; - } - - // Case 1: Standard ASCII range (U+0000 to U+007F) -> Requires 1 byte - if (codepoint <= 0x7F) { - dest_buffer[0] = (char)codepoint; - *out_bytes_written = 1; - } - // Case 2: U+0080 to U+07FF -> Requires 2 bytes - else if (codepoint <= 0x7FF) { - dest_buffer[0] = (char)(0xC0 | ((codepoint >> 6) & 0x1F)); - dest_buffer[1] = (char)(0x80 | (codepoint & 0x3F)); - *out_bytes_written = 2; - } - // Case 3: U+0800 to U+FFFF -> Requires 3 bytes (Handles most Chinese characters) - else if (codepoint <= 0xFFFF) { - dest_buffer[0] = (char)(0xE0 | ((codepoint >> 12) & 0x0F)); - dest_buffer[1] = (char)(0x80 | ((codepoint >> 6) & 0x3F)); - dest_buffer[2] = (char)(0x80 | (codepoint & 0x3F)); - *out_bytes_written = 3; - } - // Case 4: U+10000 to U+10FFFF -> Requires 4 bytes (Handles Emojis and ancient scripts) - else { - dest_buffer[0] = (char)(0xF0 | ((codepoint >> 18) & 0x07)); - dest_buffer[1] = (char)(0x80 | ((codepoint >> 12) & 0x3F)); - dest_buffer[2] = (char)(0x80 | ((codepoint >> 6) & 0x3F)); - dest_buffer[3] = (char)(0x80 | (codepoint & 0x3F)); - *out_bytes_written = 4; - } - - // Securely seal the local buffer layout array with a trailing null terminator - dest_buffer[*out_bytes_written] = '\0'; - - return C_ERR_OK; -} - - -c_err_t c_utf8_to_unicode_array(const char* str, c_ucs4_t* dest_array, c_size_t array_capacity, c_size_t* out_chars_written) { - if (!str || !dest_array || !out_chars_written) { - return C_ERR_PARAM; - } - - c_size_t src_idx = 0; - c_size_t chars_count = 0; - - while (str[src_idx] != '\0') { - // Enforce array capacity threshold constraints - if (chars_count >= array_capacity) { - *out_chars_written = chars_count; - return C_ERR_PARAM; // Destination array is too small to fit the remaining string - } - - c_ucs4_t cp = 0; - c_size_t bytes_consumed = 0; - - // Decode the single character point via your core decoding function - c_err_t err = c_utf8_to_unicode(&str[src_idx], &cp, &bytes_consumed); - if (err != C_ERR_OK) { - *out_chars_written = chars_count; - return err; // Propagate the malformed stream error up - } - - dest_array[chars_count++] = cp; - src_idx += bytes_consumed; - } - - *out_chars_written = chars_count; - return C_ERR_OK; -} - -c_err_t c_utf8_from_unicode_array(const c_ucs4_t* src_array, c_size_t src_array_len, char* dest_buffer, c_size_t dest_capacity, c_size_t* out_bytes_written) { - if (!src_array || !dest_buffer || !out_bytes_written) { - return C_ERR_PARAM; - } - - c_size_t dest_idx = 0; - - for (c_size_t i = 0; i < src_array_len; i++) { - char temp_char_buf[5]; // Temporary standalone slot buffer - c_size_t bytes_written = 0; - - // Encode single code point state back to byte wrappers - c_err_t err = c_utf8_from_unicode(src_array[i], temp_char_buf, &bytes_written); - if (err != C_ERR_OK) { - *out_bytes_written = dest_idx; - return err; - } - - // Verify if destination capacity bounds can hold the new character block (+1 for terminal null) - if (dest_idx + bytes_written + 1 > dest_capacity) { - *out_bytes_written = dest_idx; - dest_buffer[dest_idx] = '\0'; // Gracefully terminate the current chunk before failing - return C_ERR_PARAM; - } - - // Copy raw encoded data bytes into our tracking stream layout - memcpy(dest_buffer + dest_idx, temp_char_buf, bytes_written); - dest_idx += bytes_written; - } - - // Force strict trailing character termination closure - dest_buffer[dest_idx] = '\0'; - *out_bytes_written = dest_idx; - - return C_ERR_OK; -} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - - -c_err_t c_utf8_to_utf16(const char* str, c_uint16_t* dest_array, c_size_t array_capacity, c_size_t* out_units_written) { - if (!str || !dest_array || !out_units_written) { - return C_ERR_PARAM; - } - - c_size_t src_idx = 0; - c_size_t units_count = 0; - - while (str[src_idx] != '\0') { - c_ucs4_t cp = 0; - c_size_t bytes_consumed = 0; - - // 1. Decode the UTF-8 sequence into a Unicode codepoint - c_err_t err = c_utf8_to_unicode(&str[src_idx], &cp, &bytes_consumed); - if (err != C_ERR_OK) { - *out_units_written = units_count; - return err; - } - - // 2. Encode the codepoint into UTF-16 - if (cp <= 0xFFFF) { - // BMP Range: Requires exactly one 16-bit code unit - if (units_count + 1 >= array_capacity) { - *out_units_written = units_count; - return C_ERR_PARAM; // Out of bounds - } - dest_array[units_count++] = (c_uint16_t)cp; - } else { - // Supplementary Planes (Astral): Requires a surrogate pair (two 16-bit units) - if (units_count + 2 >= array_capacity) { - *out_units_written = units_count; - return C_ERR_PARAM; // Out of bounds - } - cp -= 0x10000; - dest_array[units_count++] = (c_uint16_t)(0xD800 | ((cp >> 10) & 0x3FF)); // High Surrogate - dest_array[units_count++] = (c_uint16_t)(0xDC00 | (cp & 0x3FF)); // Low Surrogate - } - - src_idx += bytes_consumed; - } - - // Append the trailing null terminator to make it a valid UTF-16 string - if (units_count < array_capacity) { - dest_array[units_count] = 0; - } else { - *out_units_written = units_count; - return C_ERR_PARAM; - } - - *out_units_written = units_count; - return C_ERR_OK; -} - -c_err_t c_utf8_from_utf16(const c_uint16_t* src_array, c_size_t src_array_len, char* dest_buffer, c_size_t dest_capacity, c_size_t* out_bytes_written) { - if (!src_array || !dest_buffer || !out_bytes_written) { - return C_ERR_PARAM; - } - - c_size_t src_idx = 0; - c_size_t dest_idx = 0; - - while (src_idx < src_array_len) { - c_ucs4_t cp = 0; - c_uint16_t u1 = src_array[src_idx++]; - - // 1. Decode UTF-16 to Unicode codepoint - if (u1 >= 0xD800 && u1 <= 0xDBFF) { - // High surrogate detected, look ahead for the matching low surrogate - if (src_idx >= src_array_len) { - *out_bytes_written = dest_idx; - return C_ERR_PARAM; // Truncated/Malformed surrogate pair - } - c_uint16_t u2 = src_array[src_idx++]; - if (u2 < 0xDC00 || u2 > 0xDFFF) { - *out_bytes_written = dest_idx; - return C_ERR_PARAM; // Missing or invalid low surrogate - } - cp = (((u1 & 0x3FF) << 10) | (u2 & 0x3FF)) + 0x10000; - } else if (u1 >= 0xDC00 && u1 <= 0xDFFF) { - // Isolated low surrogate is invalid in a lead position - *out_bytes_written = dest_idx; - return C_ERR_PARAM; - } else { - // Normal BMP character - cp = u1; - } - - // 2. Encode the Unicode codepoint back into the destination UTF-8 buffer - char temp_buf[5]; - c_size_t bytes_written = 0; - c_err_t err = c_utf8_from_unicode(cp, temp_buf, &bytes_written); - if (err != C_ERR_OK) { - *out_bytes_written = dest_idx; - return err; - } - - // Verify if destination capacity bounds can hold the new block (+1 for terminal null) - if (dest_idx + bytes_written + 1 > dest_capacity) { - *out_bytes_written = dest_idx; - dest_buffer[dest_idx] = '\0'; - return C_ERR_PARAM; // Overflow protection - } - - memcpy(dest_buffer + dest_idx, temp_buf, bytes_written); - dest_idx += bytes_written; - } - - // Force strict trailing character termination closure - dest_buffer[dest_idx] = '\0'; - *out_bytes_written = dest_idx; - - return C_ERR_OK; -} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -c_err_t c_utf16_swap_endian(c_uint16_t* utf16_array, c_size_t length) { - if (!utf16_array) { - return C_ERR_PARAM; - } - - for (c_size_t i = 0; i < length; i++) { - c_uint16_t value = utf16_array[i]; - // Bitwise swap: (value >> 8) extracts the high byte, (value << 8) extracts the low byte - utf16_array[i] = (c_uint16_t)(((value & 0x00FF) << 8) | ((value & 0xFF00) >> 8)); - } - - return C_ERR_OK; -} - - -c_err_t c_utf16_to_unicode(const c_uint16_t* src_units, c_size_t src_capacity, c_ucs4_t* out_codepoint, c_size_t* out_units_read) { - if (!src_units || src_capacity == 0 || !out_codepoint || !out_units_read) { - return C_ERR_PARAM; - } - - c_uint16_t u1 = src_units[0]; - - // Case 1: High Surrogate Point Detection (0xD800 to 0xDBFF) - if (u1 >= 0xD800 && u1 <= 0xDBFF) { - if (src_capacity < 2) { - return C_ERR_PARAM; // Truncated sequence: expected a matching low surrogate - } - - c_uint16_t u2 = src_units[1]; - if (u2 < 0xDC00 || u2 > 0xDFFF) { - return C_ERR_PARAM; // Malformed sequence: missing a valid trailing low surrogate - } - - // Reconstruct Astral Plane Codepoint via formula: ((High - 0xD800) << 10) + (Low - 0xDC00) + 0x10000 - *out_codepoint = (c_ucs4_t)((((u1 & 0x3FF) << 10) | (u2 & 0x3FF)) + 0x10000); - *out_units_read = 2; - } - // Case 2: Isolated Low Surrogate Error Check (0xDC00 to 0xDFFF) - else if (u1 >= 0xDC00 && u1 <= 0xDFFF) { - return C_ERR_PARAM; // Isolated low surrogate is mathematically invalid in a lead position - } - // Case 3: Standard BMP Range Character - else { - *out_codepoint = (c_ucs4_t)u1; - *out_units_read = 1; - } - - return C_ERR_OK; -} - -c_err_t c_utf16_from_unicode(c_ucs4_t codepoint, c_uint16_t* dest_units, c_size_t dest_capacity, c_size_t* out_units_written) { - if (!dest_units || dest_capacity == 0 || !out_units_written) { - return C_ERR_PARAM; - } - - // Limit Validation: Reject invalid Astral values or illegal UTF-16 surrogate codepoint blocks - if (codepoint > 0x10FFFF || (codepoint >= 0xD800 && codepoint <= 0xDFFF)) { - return C_ERR_PARAM; - } - - // Case 1: BMP Range (U+0000 to U+FFFF) -> Requires 1 code unit - if (codepoint <= 0xFFFF) { - dest_units[0] = (c_uint16_t)codepoint; - *out_units_written = 1; - } - // Case 2: Supplementary Planes (U+10000 to U+10FFFF) -> Requires 2 code units (Surrogate Pair) - else { - if (dest_capacity < 2) { - return C_ERR_PARAM; // Insufficient buffer capacity - } - - c_ucs4_t adjusted = codepoint - 0x10000; - dest_units[0] = (c_uint16_t)(0xD800 | ((adjusted >> 10) & 0x3FF)); // High Surrogate - dest_units[1] = (c_uint16_t)(0xDC00 | (adjusted & 0x3FF)); // Low Surrogate - *out_units_written = 2; - } - - return C_ERR_OK; -} - - diff --git a/Foundation/c_utf8.h b/Foundation/c_utf8.h deleted file mode 100644 index c374880..0000000 --- a/Foundation/c_utf8.h +++ /dev/null @@ -1,242 +0,0 @@ -#ifndef INCLUDED_C_UTF8_H -#define INCLUDED_C_UTF8_H - -#ifndef INCLUDED_C_TYPES_H -#include -#endif /*INCLUDED_C_TYPES_H*/ - - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -#ifndef C_UNICODE_MAX -#define C_UNICODE_MAX 0x10FFFFU -#endif - - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -/* --- Unicode Codepoint Type Definition --- */ -typedef uint32_t c_ucs4_t; // UCS-4 / UTF-32 representation for a single Unicode Codepoint -typedef uint16_t c_uint16_t; - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -C_STATIC_FORCE_INLINE -bool c_is_valid_unicode(uint32_t code) { - // Unicode 码点不能超过 0x10FFFF,且必须排除 UTF-16 代理对范围 (0xD800 ~ 0xDFFF) - if (code > C_UNICODE_MAX) return false; - if (code >= 0xD800 && code <= 0xDFFF) return false; - return true; -} - -/** - * @brief 获取一个 UTF-8 字符在当前指针位置所占用的实际字节数 (1 ~ 4 字节) - */ -C_STATIC_FORCE_INLINE c_size_t c_utf8_char_len(char leading_byte) { - unsigned char b = (unsigned char)leading_byte; - if (b < 0x80) return 1; // 单字节 ASCII: 0xxxxxxx - if ((b & 0xE0) == 0xC0) return 2; // 双字节字符: 110xxxxx - if ((b & 0xF0) == 0xE0) return 3; // 三字节字符(大部分汉字): 1110xxxx - if ((b & 0xF8) == 0xF0) return 4; // 四字节字符(Emoji等): 11110xxx - return 1; // 非法 UTF-8 引导字节,防御性返回 1 防止死循环 -} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -/** - * @brief 计算一个 UTF-8 字符串的有效字形数(字符数),而非字节数 (兼容 strlen) - */ -c_size_t c_utf8_strlen(const char* str); - -/** - * @brief 查找字符在 UTF-8 字符串中第一次出现的位置 (兼容 strchr) - * @param str 源字符串 - * @param utf8_char 待查找的 UTF-8 字符(支持多字节字符,如 "中") - * @return const char* 指向找到的第一个字节的指针,未找到返回 NULL - */ -const char* c_utf8_strchr(const char* str, const char* utf8_char); - -/** - * @brief 复制指定字形数量的 UTF-8 字符串 (兼容 strncpy) - * @note 能够完美感知 UTF-8 字符边界,绝不会切断汉字,且自动在末尾补 '\0' - * @param dest 目标缓冲区 - * @param src 源字符串 - * @param char_num 要复制的 UTF-8 字符/字形数量 - * @return char* 指向目标缓冲区 dest 的指针 - */ -char* c_utf8_strncpy(char* dest, const char* src, c_size_t char_num); - -/** - * @brief 比较两个 UTF-8 字符串的前 n 个字符 (兼容 strncmp) - * @param str1 字符串 1 - * @param str2 字符串 2 - * @param char_num 要比较的 UTF-8 字符/字形数量 - * @return int 小于 0、等于 0 或大于 0 - */ -int c_utf8_strncmp(const char* str1, const char* str2, c_size_t char_num); - - -/** - * @brief Converts a UTF-8 character string to lowercase in-place. - * Supports standard ASCII case folding and common multi-byte scripts. - * @param str Pointer to the mutable null-terminated UTF-8 string. - * @return char* Pointer to the original string. - */ -char* c_utf8_tolower(char* str); - -/** - * @brief Converts a UTF-8 character string to uppercase in-place. - * Supports standard ASCII case folding and common multi-byte scripts. - * @param str Pointer to the mutable null-terminated UTF-8 string. - * @return char* Pointer to the original string. - */ -char* c_utf8_toupper(char* str); - -/** - * @brief Appends the source UTF-8 string to the destination string buffer (Compatible with strcat). - * @param dest Pointer to the null-terminated destination buffer. - * @param src Pointer to the null-terminated source string. - * @return char* Pointer to the destination string destination pointer. - */ -char* c_utf8_strcat(char* dest, const char* src); - -/** - * @brief Finds the first occurrence of a substring in a UTF-8 string (Compatible with strstr). - * @param haystack The null-terminated UTF-8 string to scan. - * @param needle The null-terminated UTF-8 substring to search for. - * @return const char* Pointer to the first byte of the matched substring in haystack, or NULL if not found. - */ -const char* c_utf8_strstr(const char* haystack, const char* needle); - -/** - * @brief Finds the last occurrence of a specific character in a UTF-8 string (Compatible with strrchr). - * @param str The null-terminated UTF-8 string to scan. - * @param utf8_char The null-terminated UTF-8 character string to find (can be a multi-byte sequence like "中"). - * @return const char* Pointer to the last occurrence of the matched character in str, or NULL if not found. - */ -const char* c_utf8_strrchr(const char* str, const char* utf8_char); - -/** - * @brief Tokenizes a string into a series of tokens based on multiple multi-byte delimiters. - * This function is thread-safe and reentrant, operating similarly to POSIX strtok_r. - * @param str The mutable UTF-8 string to tokenize. Pass NULL on subsequent calls. - * @param delims A raw byte sequence containing multi-byte UTF-8 delimiters. - * @param saveptr A user-allocated tracking pointer to maintain state context across consecutive calls. - * @return char* Pointer to the beginning of the next valid token, or NULL when no more tokens are found. - */ -char* c_utf8_strtok(char* str, const char* delims, char** saveptr); - -/** - * @brief Compares two UTF-8 strings case-insensitively up to a specified number of characters. - * @param str1 Pointer to the first null-terminated UTF-8 string. - * @param str2 Pointer to the second null-terminated UTF-8 string. - * @param char_num Maximum number of UTF-8 characters (codepoints) to compare. - * @return int An integer less than, equal to, or greater than zero if str1 is found, - * respectively, to be less than, to match, or be greater than str2. - */ -int c_utf8_strncasecmp(const char* str1, const char* str2, c_size_t char_num); - - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -/** - * @brief Converts the next UTF-8 byte sequence at a given pointer into a single Unicode Codepoint. - * @param str Pointer to the current position in a null-terminated UTF-8 string. - * @param out_codepoint Pointer to the destination where the decoded Unicode integer is saved. - * @param out_bytes_consumed Pointer to save the number of source bytes processed (1 to 4). - * @return c_err_t C_ERR_OK on success, or C_ERR_PARAM on invalid/corrupted UTF-8 byte streams. - */ -c_err_t c_utf8_to_unicode(const char* str, c_ucs4_t* out_codepoint, c_size_t* out_bytes_consumed); - - -/** - * @brief Encodes a single Unicode Codepoint (UCS-4) into a destination UTF-8 byte array. - * @param codepoint The source Unicode integer character point to encode. - * @param dest_buffer Pointer to a char array buffer (must have at least 5 bytes capacity). - * @param out_bytes_written Pointer to save the number of encoded bytes stored in dest_buffer. - * @return c_err_t C_ERR_OK on success, or C_ERR_PARAM if the codepoint is out of valid Unicode ranges or parameters are NULL. - */ -c_err_t c_utf8_from_unicode(c_ucs4_t codepoint, char* dest_buffer, c_size_t* out_bytes_written); - -/** - * @brief Decodes an entire null-terminated UTF-8 string into an array of Unicode Codepoints. - * @param str Pointer to the null-terminated source UTF-8 string. - * @param dest_array Pointer to the destination array where decoded codepoints will be stored. - * @param array_capacity Maximum number of elements that dest_array can hold. - * @param out_chars_written Pointer to save the total number of codepoints successfully stored. - * @return c_err_t C_ERR_OK on success, C_ERR_PARAM on invalid/NULL parameters or if the destination array capacity is exceeded. - */ -c_err_t c_utf8_to_unicode_array(const char* str, c_ucs4_t* dest_array, c_size_t array_capacity, c_size_t* out_chars_written); - -/** - * @brief Encodes an array of Unicode Codepoints back into a null-terminated UTF-8 byte stream. - * @param src_array Pointer to the source array of Unicode codepoints. - * @param src_array_len The number of codepoint elements inside src_array to process. - * @param dest_buffer Pointer to the destination char buffer. - * @param dest_capacity Maximum byte capacity of the destination buffer (including room for '\0'). - * @param out_bytes_written Pointer to save the total number of bytes written to dest_buffer (excluding '\0'). - * @return c_err_t C_ERR_OK on success, C_ERR_PARAM on invalid/NULL parameters or if dest_capacity is exceeded. - */ -c_err_t c_utf8_from_unicode_array(const c_ucs4_t* src_array, c_size_t src_array_len, char* dest_buffer, c_size_t dest_capacity, c_size_t* out_bytes_written); - -/** - * @brief Converts an entire null-terminated UTF-8 string into an array of UTF-16 code units. - * @param str Pointer to the null-terminated source UTF-8 string. - * @param dest_array Pointer to the destination array where UTF-16 code units will be stored. - * @param array_capacity Maximum number of 16-bit elements that dest_array can hold. - * @param out_units_written Pointer to save the total number of UTF-16 code units successfully stored (excluding terminal '\0'). - * @return c_err_t C_ERR_OK on success, C_ERR_PARAM on invalid/NULL parameters or if capacity is exceeded. - */ -c_err_t c_utf8_to_utf16(const char* str, c_uint16_t* dest_array, c_size_t array_capacity, c_size_t* out_units_written); - -/** - * @brief Converts an array of UTF-16 code units back into a null-terminated UTF-8 byte stream. - * @param src_array Pointer to the source array of UTF-16 code units. - * @param src_array_len The number of 16-bit elements inside src_array to process. - * @param dest_buffer Pointer to the destination char buffer. - * @param dest_capacity Maximum byte capacity of the destination buffer (including room for '\0'). - * @param out_bytes_written Pointer to save the total number of bytes written to dest_buffer (excluding '\0'). - * @return c_err_t C_ERR_OK on success, C_ERR_PARAM on invalid/NULL parameters, malformed surrogates, or if dest_capacity is exceeded. - */ -c_err_t c_utf8_from_utf16(const c_uint16_t* src_array, c_size_t src_array_len, char* dest_buffer, c_size_t dest_capacity, c_size_t* out_bytes_written); - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -/** - * @brief Swaps the byte order (endianness) of a UTF-16 string array in-place. - * @param utf16_array Pointer to the source/destination array of UTF-16 code units. - * @param length The number of 16-bit elements inside the array to process. - * @return c_err_t C_ERR_OK on success, or C_ERR_PARAM if the array pointer is NULL. - */ -c_err_t c_utf16_swap_endian(c_uint16_t* utf16_array, c_size_t length); - - -/** - * @brief Decodes a UTF-16 character stream starting at a given pointer into a single Unicode codepoint. - * @param src_units Pointer to the current code unit position in a UTF-16 array. - * @param src_capacity Remaining elements left available to read inside the source array. - * @param out_codepoint Pointer to the destination where the decoded Unicode integer is saved. - * @param out_units_read Pointer to save the number of 16-bit code units processed (1 for BMP, 2 for Surrogate Pairs). - * @return c_err_t C_ERR_OK on success, or C_ERR_PARAM on malformed surrogate sequences or missing parameters. - */ -c_err_t c_utf16_to_unicode(const c_uint16_t* src_units, c_size_t src_capacity, c_ucs4_t* out_codepoint, c_size_t* out_units_read); - -/** - * @brief Encodes a single Unicode codepoint into a target UTF-16 array buffer. - * @param codepoint The source Unicode integer character point to encode. - * @param dest_units Pointer to the destination 16-bit code unit array buffer. - * @param dest_capacity Maximum number of 16-bit elements the destination buffer can accept. - * @param out_units_written Pointer to save the number of 16-bit code units generated (1 or 2). - * @return c_err_t C_ERR_OK on success, or C_ERR_PARAM if the codepoint is invalid or destination space is insufficient. - */ -c_err_t c_utf16_from_unicode(c_ucs4_t codepoint, c_uint16_t* dest_units, c_size_t dest_capacity, c_size_t* out_units_written); - - - -#endif /*INCLUDED_C_UTF8_H*/ diff --git a/Foundation/c_utf8.t.c b/Foundation/c_utf8.t.c deleted file mode 100644 index aedcaec..0000000 --- a/Foundation/c_utf8.t.c +++ /dev/null @@ -1,302 +0,0 @@ -#include "c_utf8.h" -#include -#include - -/* --- 单元测试模块集成 --- */ -#define RUN_TEST(test_case, name) \ - do { \ - printf("[RUN] %s... ", name); \ - if (test_case) { \ - printf("\033[32mPASSED\033[0m\n"); \ - } else { \ - printf("\033[31mFAILED\033[0m (%s:%d)\n", __FILE__, __LINE__); \ - return C_ERR_FAIL; \ - } \ - } while(0) - -c_err_t c_Utf8String_UnitTest(void) { - printf("==================================================\n"); - printf(" STARTING C_UTF8STRING UNIT TESTING \n"); - printf("==================================================\n"); - - const char* sample = "NLP大模型_2026"; // 包含 3个大写英文、3个汉字、1个下划线、4个数字 = 11个字符 - - /* 1. c_utf8_strlen 测试 */ - // 传统的 strlen(sample) 会返回 3 + 3*3 + 1 + 4 = 17 字节 - RUN_TEST(c_utf8_strlen(sample) == 11, "c_utf8_strlen correctly counts character points"); - RUN_TEST(c_utf8_strlen("") == 0, "c_utf8_strlen handles empty strings"); - - /* 2. c_utf8_strchr 测试 */ - const char* find_eng = c_utf8_strchr(sample, "P"); - const char* find_chn = c_utf8_strchr(sample, "模"); - const char* find_none = c_utf8_strchr(sample, "国"); - - RUN_TEST(find_eng != NULL && *find_eng == 'P', "c_utf8_strchr locate ASCII element"); - // "模" 在 "模型_2026" 头部,其后紧跟 "型" - RUN_TEST(find_chn != NULL && strncmp(find_chn, "模型", 6) == 0, "c_utf8_strchr locate multi-byte Chinese word"); - RUN_TEST(find_none == NULL, "c_utf8_strchr returns NULL for non-existing chars"); - - /* 3. c_utf8_strncpy 安全截断测试 */ - char dest_buf[64]; - // 截断前 5 个字符 -> "NLP大模" (绝不会出现半个汉字或乱码断裂) - c_utf8_strncpy(dest_buf, sample, 5); - RUN_TEST(c_utf8_strlen(dest_buf) == 5, "c_utf8_strncpy slices correct character width"); - RUN_TEST(strcmp(dest_buf, "NLP大模") == 0, "c_utf8_strncpy safe boundary isolation checked"); - - /* 4. c_utf8_strncmp 字符匹配测试 */ - RUN_TEST(c_utf8_strncmp("自然语言", "自然选择", 2) == 0, "c_utf8_strncmp matches first 2 shared Chinese words"); - RUN_TEST(c_utf8_strncmp("自然语言", "自然选择", 3) != 0, "c_utf8_strncmp detects variance at 3rd word slot"); - - /* ------------------------------------------------------------------------------------------------------------------ */ - /* */ - /* 5. Lowercase Transform Verification (c_utf8_tolower) */ - char case_buf[64] = "NLP大模型_2026_Go!"; - c_utf8_tolower(case_buf); - RUN_TEST(strcmp(case_buf, "nlp大模型_2026_go!") == 0, "c_utf8_tolower translates ASCII while isolating Chinese layout characters"); - - // Cyrillic multi-byte letter test ("П" -> 0xD0 0x9F converted down to "п" -> 0xD0 0xBF) - char cyrillic_buf[8] = { (char)0xD0, (char)0x9F, '\0' }; - c_utf8_tolower(cyrillic_buf); - RUN_TEST((unsigned char)cyrillic_buf[1] == 0xBF, "c_utf8_tolower successfully transforms multi-byte Cyrillic characters"); - - /* 6. Concatenation Verification (c_utf8_strcat) */ - char cat_dest[32] = "自然"; - c_utf8_strcat(cat_dest, "语言"); - RUN_TEST(strcmp(cat_dest, "自然语言") == 0, "c_utf8_strcat appends string tokens cleanly"); - RUN_TEST(c_utf8_strlen(cat_dest) == 4, "Post-concatenation size checks out at 4 characters total"); - - /* ------------------------------------------------------------------------------------------------------------------ */ - /* */ - - /* 24. Uppercase Transform Verification (c_utf8_toupper) */ - char upper_buf[] = "nlp大模型_2026_go!"; - c_utf8_toupper(upper_buf); - RUN_TEST(strcmp(upper_buf, "NLP大模型_2026_GO!") == 0, "c_utf8_toupper translates ASCII while isolating Chinese layout characters"); - - // Cyrillic multi-byte lowercase letter test ("п" -> 0xD0 0xBF converted up to "П" -> 0xD0 0x9F) - char cyr_upper_buf[] = { (char)0xD0, (char)0xBF, '\0' }; - c_utf8_toupper(cyr_upper_buf); - RUN_TEST((unsigned char)cyr_upper_buf[1] == 0x9F, "c_utf8_toupper successfully transforms multi-byte Cyrillic lowercase characters"); - - - /* ------------------------------------------------------------------------------------------------------------------ */ - /* */ - - /* 7. Character Scanning Verification (c_utf8_strchr) */ - const char* scan_base = "NLP大模型_2026"; - - /* 8. Substring Scanning Verification (c_utf8_strstr) */ - const char* match_str = c_utf8_strstr(scan_base, "大模型"); - const char* miss_str = c_utf8_strstr(scan_base, "小模型"); - const char* empty_str = c_utf8_strstr(scan_base, ""); - - RUN_TEST(match_str != NULL && strncmp(match_str, "大模型_2026", 14) == 0, "c_utf8_strstr fetches multi-byte string locations"); - RUN_TEST(miss_str == NULL, "c_utf8_strstr returns NULL cleanly on substring mismatch"); - RUN_TEST(empty_str == scan_base, "c_utf8_strstr returns parent head context given empty needle input"); - - /* ------------------------------------------------------------------------------------------------------------------ */ - /* */ - - /* 16. Reverse Scanning Verification (c_utf8_strrchr) */ - const char* r_base = "自然_模型_自然_2026"; - const char* last_match = c_utf8_strrchr(r_base, "自然"); - const char* first_match = c_utf8_strchr(r_base, "自然"); - - RUN_TEST(last_match != NULL && last_match != first_match, "c_utf8_strrchr skips the first match to pull the last occurrence"); - RUN_TEST(strncmp(last_match, "自然_2026", 11) == 0, "c_utf8_strrchr locates the correct trailing block address"); - - /* 17. Reentrant Tokenization Verification (c_utf8_strtok) */ - char token_source[] = ",NLP,,大模型,2026,"; // Multi-byte Chinese comma delimiters - const char* delimiters = ","; - char* save_context = NULL; - - // First Call - char* token = c_utf8_strtok(token_source, delimiters, &save_context); - RUN_TEST(token != NULL && strcmp(token, "NLP") == 0, "c_utf8_strtok parses the first token and skips leading delims"); - - // Second Call (Pass NULL to proceed) - token = c_utf8_strtok(NULL, delimiters, &save_context); - RUN_TEST(token != NULL && strcmp(token, "大模型") == 0, "c_utf8_strtok correctly extracts multi-byte Chinese '大模型'"); - - // Third Call - token = c_utf8_strtok(NULL, delimiters, &save_context); - RUN_TEST(token != NULL && strcmp(token, "2026") == 0, "c_utf8_strtok extracts '2026'"); - - // Fourth Call - Termination - token = c_utf8_strtok(NULL, delimiters, &save_context); - RUN_TEST(token == NULL, "c_utf8_strtok returns NULL cleanly when parsing is finished"); - - /* ------------------------------------------------------------------------------------------------------------------ */ - /* */ - - /* 25. Case-Insensitive Bounded Comparison Verification (c_utf8_strncasecmp) */ - // Test Case 1: Simple matching mixed-case strings - RUN_TEST(c_utf8_strncasecmp("Nlp大模型", "NLP大模型", 6) == 0, "c_utf8_strncasecmp matches mixed cases up to 6 characters"); - - // Test Case 2: Verification of prefix character restrictions bounding - RUN_TEST(c_utf8_strncasecmp("NLP大模型_v2", "nlp大模型_v3", 6) == 0, "c_utf8_strncasecmp returns 0 if differences fall past the character count limit"); - RUN_TEST(c_utf8_strncasecmp("NLP大模型_v2", "nlp大模型_v3", 9) != 0, "c_utf8_strncasecmp registers structural variance when character limits cover differences"); - - // Test Case 3: Mixed language case sorting behavior - RUN_TEST(c_utf8_strncasecmp("自然语言NLP", "自然语言nlp", 7) == 0, "c_utf8_strncasecmp handles matching trailing ASCII case differences after multi-byte blocks"); - - - /* ------------------------------------------------------------------------------------------------------------------ */ - /* */ - - /* 18. UTF-8 to Unicode Codepoint Decoding Verification */ - const char* utf8_src = "中!🚀"; // "中" (3 bytes), "!" (1 byte), "🚀" Emoji (4 bytes) - c_ucs4_t cp = 0; - c_size_t bytes_step = 0; - - // Decode first character ("中" -> Expected Codepoint: U+4E2D) - c_err_t err = c_utf8_to_unicode(utf8_src, &cp, &bytes_step); - RUN_TEST(err == C_ERR_OK && bytes_step == 3, "c_utf8_to_unicode processes 3-byte Chinese characters"); - RUN_TEST(cp == 0x4E2D, "Decoded codepoint matches U+4E2D ('中') accurately"); - - // Decode next sequence ("!" -> Expected Codepoint: U+0021) - err = c_utf8_to_unicode(utf8_src + bytes_step, &cp, &bytes_step); - RUN_TEST(err == C_ERR_OK && bytes_step == 1, "c_utf8_to_unicode processes 1-byte ASCII markers"); - RUN_TEST(cp == 0x0021, "Decoded codepoint matches U+0021 ('!')"); - - // Decode next sequence (Rocket Emoji "🚀" -> Expected Codepoint: U+1F680) - err = c_utf8_to_unicode(utf8_src + 4, &cp, &bytes_step); // Skip forward 4 bytes total - RUN_TEST(err == C_ERR_OK && bytes_step == 4, "c_utf8_to_unicode decodes 4-byte astral plane emojis"); - RUN_TEST(cp == 0x1F680, "Decoded codepoint matches U+1F680 ('🚀')"); - - /* 19. Unicode Codepoint to UTF-8 Encoding Verification */ - char encode_buf[8]; - c_size_t written_len = 0; - - // Encode U+4E2D back to UTF-8 - err = c_utf8_from_unicode(0x4E2D, encode_buf, &written_len); - RUN_TEST(err == C_ERR_OK && written_len == 3, "c_utf8_from_unicode encodes U+4E2D back into 3 bytes"); - RUN_TEST(strcmp(encode_buf, "中") == 0, "Encoded string content matches '中' flawlessly"); - - // Encode U+1F680 back to UTF-8 - err = c_utf8_from_unicode(0x1F680, encode_buf, &written_len); - RUN_TEST(err == C_ERR_OK && written_len == 4, "c_utf8_from_unicode encodes U+1F680 back into 4 bytes"); - - /* ------------------------------------------------------------------------------------------------------------------ */ - /* */ - - /* 20. UTF-8 String Stream <-> Unicode Array Conversions Verification */ - const char* mixed_sentence = "NLP大模型!🚀"; // Length: 3 ASCII, 3 Chinese (9B), 1 ASCII, 1 Emoji (4B) = 8 characters total - c_ucs4_t uni_array[16]; - c_size_t total_chars = 0; - - // Test Point 1: Decode stream into codepoint container array - err = c_utf8_to_unicode_array(mixed_sentence, uni_array, 16, &total_chars); - RUN_TEST(err == C_ERR_OK && total_chars == 8, "c_utf8_to_unicode_array maps complex string streams into separate integer points"); - RUN_TEST(uni_array[0] == 'N' && uni_array[3] == 0x5927 && uni_array[7] == 0x1F680, "Decoded array positions hold proper character points ('N', '大', '🚀')"); - - // Test Point 2: Trigger array capacity guard protection - c_ucs4_t tight_array[4]; - err = c_utf8_to_unicode_array(mixed_sentence, tight_array, 4, &total_chars); - RUN_TEST(err == C_ERR_PARAM && total_chars == 4, "c_utf8_to_unicode_array safely blocks operations and returns current progress on buffer limit hits"); - - // Test Point 3: Reverse operation - Encode codepoint array back into native UTF-8 string layout - char reconstructed_str[64]; - c_size_t written_bytes = 0; - err = c_utf8_from_unicode_array(uni_array, 8, reconstructed_str, sizeof(reconstructed_str), &written_bytes); - RUN_TEST(err == C_ERR_OK && written_bytes == 17, "c_utf8_from_unicode_array successfully packs codepoints back into 17 raw bytes"); - RUN_TEST(strcmp(reconstructed_str, mixed_sentence) == 0, "Reconstructed stream data matches original expression perfectly"); - - - /* ------------------------------------------------------------------------------------------------------------------ */ - /* */ - - /* 21. UTF-8 <-> UTF-16 Array Conversions Verification */ - const char* utf8_sentence = "NLP大模型!🚀"; // Contains ASCII, 3-byte Chinese, and a 4-byte Astral Plane Emoji - c_uint16_t utf16_array[32]; - c_size_t units_written = 0; - - // Test Point 1: Convert UTF-8 stream to UTF-16 code units - // "NLP" (3 units) + "大模型" (3 units) + "!" (1 unit) + "🚀" (Surrogate pair = 2 units) = 9 units total - err = c_utf8_to_utf16(utf8_sentence, utf16_array, 32, &units_written); - RUN_TEST(err == C_ERR_OK && units_written == 9, "c_utf8_to_utf16 successfully packs characters including astral planes"); - RUN_TEST(utf16_array[0] == 'N' && utf16_array[3] == 0x5927, "Verify standard BMP mapping inside UTF-16 array structure"); - // Verify high and low surrogate points for the Rocket Emoji 🚀 - RUN_TEST(utf16_array[7] == 0xD83D && utf16_array[8] == 0xDE80, "Verify surrogate pair matching (0xD83D 0xDE80) for U+1F680"); - - // Test Point 2: Convert UTF-16 array back to native UTF-8 string layout - char reconstructed_utf8[64]; - c_size_t bytes_written_utf8 = 0; - err = c_utf8_from_utf16(utf16_array, units_written, reconstructed_utf8, sizeof(reconstructed_utf8), &bytes_written_utf8); - RUN_TEST(err == C_ERR_OK && bytes_written_utf8 == 17, "c_utf8_from_utf16 unpacks units back into 17 raw bytes"); - RUN_TEST(strcmp(reconstructed_utf8, utf8_sentence) == 0, "Reconstructed UTF-8 matches the original string precisely"); - - // Test Point 3: Malformed Surrogate Pair Detection - c_uint16_t malformed_utf16[] = { 0xD83D, 'A' }; // High surrogate followed by a literal letter (invalid) - char error_buf[16]; - c_size_t err_bytes = 0; - err = c_utf8_from_utf16(malformed_utf16, 2, error_buf, sizeof(error_buf), &err_bytes); - RUN_TEST(err == C_ERR_PARAM, "c_utf8_from_utf16 successfully flags and rejects malformed/orphaned surrogate code units"); - - /* ------------------------------------------------------------------------------------------------------------------ */ - /* */ - - /* 22. UTF-16 Endianness Byte-Swapping Verification (c_utf16_swap_endian) */ - c_uint16_t sample_utf16[] = { 0xD83D, 0xDE80, 0x5927 }; // 🚀 and 大 in standard host endianness - c_size_t array_len = sizeof(sample_utf16) / sizeof(sample_utf16[0]); - - // Test Point 1: Guard against NULL parameters - RUN_TEST(c_utf16_swap_endian(NULL, array_len) == C_ERR_PARAM, "c_utf16_swap_endian safely rejects NULL pointer arrays"); - - // Test Point 2: Perform initial byte-swap transformation - err = c_utf16_swap_endian(sample_utf16, array_len); - RUN_TEST(err == C_ERR_OK, "c_utf16_swap_endian executes successfully"); - // 0xD83D -> 0x3DD8, 0xDE80 -> 0x80DE, 0x5927 -> 0x2759 - RUN_TEST(sample_utf16[0] == 0x3DD8, "First code unit correctly bit-swapped (0xD83D -> 0x3DD8)"); - RUN_TEST(sample_utf16[1] == 0x80DE, "Second code unit correctly bit-swapped (0xDE80 -> 0x80DE)"); - RUN_TEST(sample_utf16[2] == 0x2759, "Third code unit correctly bit-swapped (0x5927 -> 0x2759)"); - - // Test Point 3: Swap back to restore the original host endianness values - err = c_utf16_swap_endian(sample_utf16, array_len); - RUN_TEST(err == C_ERR_OK, "c_utf16_swap_endian reverts state back on secondary execution pass"); - RUN_TEST(sample_utf16[0] == 0xD83D && sample_utf16[1] == 0xDE80 && sample_utf16[2] == 0x5927, "Original internal value contexts perfectly preserved"); - - /* ------------------------------------------------------------------------------------------------------------------ */ - /* */ - - /* 23. UTF-16 Single-Char Unicode Conversions Verification */ - c_ucs4_t decoded_cp = 0; - c_size_t units_moved = 0; - - // Test Point 1: Decode Standard BMP Character ('大' -> U+5927) - c_uint16_t bmp_sample[] = { 0x5927 }; - err = c_utf16_to_unicode(bmp_sample, 1, &decoded_cp, &units_moved); - RUN_TEST(err == C_ERR_OK && units_moved == 1, "c_utf16_to_unicode processes BMP code units"); - RUN_TEST(decoded_cp == 0x5927, "Decoded BMP matches expected U+5927 successfully"); - - // Test Point 2: Decode Surrogate Pair Character (Rocket Emoji '🚀' -> High: 0xD83D, Low: 0xDE80) - c_uint16_t astral_sample[] = { 0xD83D, 0xDE80 }; - err = c_utf16_to_unicode(astral_sample, 2, &decoded_cp, &units_moved); - RUN_TEST(err == C_ERR_OK && units_moved == 2, "c_utf16_to_unicode correctly handles surrogate pairs"); - RUN_TEST(decoded_cp == 0x1F680, "Decoded Astral match returns U+1F680 ('🚀')"); - - // Test Point 3: Error validation protection against malformed surrogate chains - c_uint16_t isolated_high[] = { 0xD83D }; // Lacks matching trailing block - RUN_TEST(c_utf16_to_unicode(isolated_high, 1, &decoded_cp, &units_moved) == C_ERR_PARAM, "c_utf16_to_unicode rejects truncated surrogate sequences"); - - // Test Point 4: Encode Astral Plane back to UTF-16 code units - c_uint16_t encode_units[2]; - units_written = 0; - err = c_utf16_from_unicode(0x1F680, encode_units, 2, &units_written); - RUN_TEST(err == C_ERR_OK && units_written == 2, "c_utf16_from_unicode builds surrogate pairs for plane codepoints"); - RUN_TEST(encode_units[0] == 0xD83D && encode_units[1] == 0xDE80, "Generated high and low values match standard encoding targets"); - - - /* ------------------------------------------------------------------------------------------------------------------ */ - /* */ - - printf("==================================================\n"); - printf("\033[32mSUCCESS: ALL UTF-8 COMPATIBLE INTERFACES PASSED!\033[0m\n"); - printf("==================================================\n"); - return C_ERR_OK; -} - - -int main(int argc, char** argv){ - return c_Utf8String_UnitTest(); -} diff --git a/Foundation/c_utf8_file.c b/Foundation/c_utf8_file.c deleted file mode 100644 index dbe6328..0000000 --- a/Foundation/c_utf8_file.c +++ /dev/null @@ -1,208 +0,0 @@ -#include - -#include -#include - -c_err_t c_utf8_file_read(const char* filepath, c_StringBuffer_t* out_sb) { - if (!filepath || !out_sb || !out_sb->buffer) { - return C_ERR_PARAM; - } - - FILE* file = fopen(filepath, "rb"); // Open in binary mode to prevent Windows crlf translations - if (!file) { - return C_ERR_FAIL; - } - - // Step 1: Detect and handle the optional 3-byte UTF-8 BOM sequence - unsigned char bom[3]; - c_size_t bom_read = fread(bom, 1, 3, file); - c_bool_t has_bom = C_FALSE; - - if (bom_read == 3 && bom[0] == 0xEF && bom[1] == 0xBB && bom[2] == 0xBF) { - has_bom = C_TRUE; // BOM sequence matched; file pointer is positioned right past it - } else { - // No BOM found; rewind file pointer back to the absolute beginning of the stream - fseek(file, 0, SEEK_SET); - } - - // Step 2: Read data sequentially via stream chunking loops - char read_chunk[1024]; - c_size_t bytes_read = 0; - c_size_t partial_offset = 0; - - while ((bytes_read = fread(read_chunk + partial_offset, 1, sizeof(read_chunk) - partial_offset, file)) > 0) { - c_size_t total_available_bytes = bytes_read + partial_offset; - c_size_t valid_process_boundary = total_available_bytes; - - // Verify that the chunk boundary does not break a multi-byte character in half. - // Look back from the absolute end of the chunk to catch multi-byte headers. - if (read_chunk[total_available_bytes - 1] & 0x80) { - c_size_t lookback = 1; - // Scan backward up to 4 bytes to find the leading byte of the fractured character - while (lookback <= 4 && lookback <= total_available_bytes) { - unsigned char b = (unsigned char)read_chunk[total_available_bytes - lookback]; - if ((b & 0xC0) == 0xC0) { // Found a multi-byte lead byte - c_size_t expected_len = c_utf8_char_len((char)b); - if (lookback < expected_len) { - // Character is indeed fractured; shrink chunk boundary to omit it - valid_process_boundary = total_available_bytes - lookback; - } - break; - } - if ((b & 0x80) == 0) { // Standard ASCII character, boundary is clean - break; - } - lookback++; - } - } - - // Pipe valid, cohesive text fragments into your dynamic string buffer tracker - if (valid_process_boundary > 0) { - c_err_t err = c_StringBuffer_Append(out_sb, read_chunk, valid_process_boundary); - if (err != C_ERR_OK) { - fclose(file); - return err; - } - } - - // Move remaining fractured bytes to the front of the next chunk buffer iteration pass - partial_offset = total_available_bytes - valid_process_boundary; - if (partial_offset > 0) { - memmove(read_chunk, read_chunk + valid_process_boundary, partial_offset); - } - } - - // Process residual bytes if the file stream terminates abruptly with an incomplete character sequence - if (partial_offset > 0) { - c_StringBuffer_Append(out_sb, read_chunk, partial_offset); - } - - fclose(file); - return C_ERR_OK; -} - -c_err_t c_utf8_file_write(const char* filepath, c_StringBuffer_t* sb, c_bool_t write_bom) { - if (!filepath || !sb || !sb->buffer) { - return C_ERR_PARAM; - } - - FILE* file = fopen(filepath, "wb"); // Open in binary mode for precise byte preservation - if (!file) { - return C_ERR_FAIL; - } - - // Explicitly inject the UTF-8 BOM sequence if requested by the configuration parameter - if (write_bom) { - unsigned char bom[3] = {0xEF, 0xBB, 0xBF}; - if (fwrite(bom, 1, 3, file) != 3) { - fclose(file); - return C_ERR_FAIL; - } - } - - // Flush the string buffer's raw tracking payload into disk blocks - if (sb->size > 0) { - c_size_t written = fwrite(sb->buffer, 1, sb->size, file); - if (written != sb->size) { - fclose(file); - return C_ERR_FAIL; - } - } - - fclose(file); - return C_ERR_OK; -} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -c_err_t c_utf8_file_append(const char* filepath, c_StringBuffer_t* sb, c_bool_t write_bom) { - if (!filepath || !sb || !sb->buffer) { - return C_ERR_PARAM; - } - - // Check if the file already exists by attempting to open it in read mode - FILE* check_file = fopen(filepath, "rb"); - c_bool_t file_exists = (check_file != NULL); - if (file_exists) { - fclose(check_file); - } - - // Open the file in append-binary mode - FILE* file = fopen(filepath, "ab"); - if (!file) { - return C_ERR_FAIL; - } - - // Write the BOM only if requested AND the file is brand new - if (write_bom && !file_exists) { - unsigned char bom[3] = {0xEF, 0xBB, 0xBF}; - if (fwrite(bom, 1, 3, file) != 3) { - fclose(file); - return C_ERR_FAIL; - } - } - - // Append the string buffer's raw tracking payload - if (sb->size > 0) { - c_size_t written = fwrite(sb->buffer, 1, sb->size, file); - if (written != sb->size) { - fclose(file); - return C_ERR_FAIL; - } - } - - fclose(file); - return C_ERR_OK; -} - -c_err_t c_utf8_file_readline(FILE* file, c_StringBuffer_t* out_line) { - if (!file || !out_line || !out_line->buffer) { - return C_ERR_PARAM; - } - - // Clear previous string buffer trackers to prepare for fresh line ingestion - c_StringBuffer_Clear(out_line); - - char read_chunk[256]; - c_bool_t data_extracted = C_FALSE; - long line_start_pos = ftell(file); - - while (fgets(read_chunk, sizeof(read_chunk), file) != NULL) { - data_extracted = C_TRUE; - c_size_t chunk_len = strlen(read_chunk); - - // Check if the chunk contains a newline character - char* newline_ptr = strchr(read_chunk, '\n'); - if (newline_ptr != NULL) { - // Calculate exact copy length up to the newline boundary - c_size_t copy_len = newline_ptr - read_chunk; - - if (copy_len > 0) { - // Strip carriage returns '\r' for safe cross-platform matching - if (read_chunk[copy_len - 1] == '\r') { - copy_len--; - } - } - - if (copy_len > 0) { - c_err_t err = c_StringBuffer_Append(out_line, read_chunk, copy_len); - if (err != C_ERR_OK) return err; - } - - return C_ERR_OK; // Line read complete - } - - // If no newline is found, the line is longer than our chunk; append everything and keep reading - c_err_t err = c_StringBuffer_Append(out_line, read_chunk, chunk_len); - if (err != C_ERR_OK) return err; - } - - // Handle end-of-file (EOF) state - if (data_extracted) { - return C_ERR_OK; // Returned the final trailing line containing no newline char - } - - return C_ERR_FAIL; // Reached EOF without extracting any data bytes -} - diff --git a/Foundation/c_utf8_file.h b/Foundation/c_utf8_file.h deleted file mode 100644 index 6f44364..0000000 --- a/Foundation/c_utf8_file.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef INCLUDED_C_UTF8_FILE_H -#define INCLUDED_C_UTF8_FILE_H - -#ifndef INCLUDED_C_STRINGBUFFER_H -#include -#endif /*INCLUDED_C_STRINGBUFFER_H*/ - -#ifndef INCLUDED_C_UTF8_H -#include -#endif /*INCLUDED_C_UTF8_H*/ - -#ifndef INCLUDED_STDIO_H -#define INCLUDED_STDIO_H -#include -#endif /*INCLUDED_STDIO_H*/ - - - - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -/** - * @brief Reads the entire contents of a UTF-8 text file into a string buffer structure. - * Automatically handles, validates, and skips the UTF-8 BOM marker if present. - * @param filepath Path to the target source file on disk. - * @param out_sb Pointer to a pre-initialized c_StringBuffer_t container to collect file data. - * @return c_err_t C_ERR_OK on complete success, C_ERR_PARAM on invalid inputs, or C_ERR_FAIL if file access throws errors. - */ -c_err_t c_utf8_file_read(const char* filepath, c_StringBuffer_t* out_sb); - -/** - * @brief Writes data from a string buffer out to a disk file using a UTF-8 text layout stream. - * @param filepath Path to the destination file on disk. - * @param sb Pointer to the source string buffer containing data. - * @param write_bom If set to C_TRUE, explicitly prefixes the file layout with the 3-byte UTF-8 BOM marker. - * @return c_err_t C_ERR_OK on complete success, C_ERR_PARAM on invalid inputs, or C_ERR_FAIL on disk write errors. - */ -c_err_t c_utf8_file_write(const char* filepath, c_StringBuffer_t* sb, c_bool_t write_bom); - -/** - * @brief Appends text from a string buffer to a disk file. - * If the target file does not exist, it initializes it (with an optional BOM marker). - * @param filepath Path to the destination file on disk. - * @param sb Pointer to the source string buffer containing the append payload. - * @param write_bom If set to C_TRUE and the file is new, prefixes the stream with the 3-byte UTF-8 BOM. - * @return c_err_t C_ERR_OK on complete success, C_ERR_PARAM on invalid inputs, or C_ERR_FAIL on disk write errors. - */ -c_err_t c_utf8_file_append(const char* filepath, c_StringBuffer_t* sb, c_bool_t write_bom); - -/** - * @brief Reads a single line of text from an open file stream into a string buffer (Dynamic fgets). - * Automatically handles standard '\n' and '\r\n' line endings. - * @param file An active file stream pointer opened in binary read ("rb") mode. - * @param out_line Pointer to a pre-initialized c_StringBuffer_t container to collect the line string. - * @return c_err_t C_ERR_OK on successful line read, C_ERR_FAIL when reaching EOF with no data, or parameter errors. - */ -c_err_t c_utf8_file_readline(FILE* file, c_StringBuffer_t* out_line); - - -#endif /*INCLUDED_C_UTF8_FILE_H*/ diff --git a/Foundation/c_utf8_file.t.c b/Foundation/c_utf8_file.t.c deleted file mode 100644 index ffc7b62..0000000 --- a/Foundation/c_utf8_file.t.c +++ /dev/null @@ -1,116 +0,0 @@ -#include "c_utf8_file.h" -#include -#include - -#define RUN_TEST(test_case, name) \ - do { \ - printf("[RUN] %s... ", name); \ - if (test_case) { \ - printf("\033[32mPASSED\033[0m\n"); \ - } else { \ - printf("\033[31mFAILED\033[0m (%s:%d)\n", __FILE__, __LINE__); \ - return C_ERR_FAIL; \ - } \ - } while(0) - -static c_err_t c_utf8_file_test(void) { - printf("==================================================\n"); - printf(" STARTING C_UTF8_FILE UNIT TESTING \n"); - printf("==================================================\n"); - - /* 26. UTF-8 File I/O Operations Verification */ - c_StringBuffer_t write_sb; - c_StringBuffer_t read_sb; - const char* test_filename = "nlp_utf8_test.txt"; - const char* payload = "NLP大模型_2026_🚀"; - - c_StringBuffer_Init(&write_sb, 32); - c_StringBuffer_Init(&read_sb, 32); - c_StringBuffer_AppendStr(&write_sb, payload); - - // Test Point 1: Parameter checks protection - RUN_TEST(c_utf8_file_read(NULL, &read_sb) == C_ERR_PARAM, "File read handles NULL filepath strings"); - RUN_TEST(c_utf8_file_write(test_filename, NULL, C_FALSE) == C_ERR_PARAM, "File write handles NULL buffer contexts"); - - // Test Point 2: Write text payload with explicit BOM injection enabled - c_err_t err = c_utf8_file_write(test_filename, &write_sb, C_TRUE); - RUN_TEST(err == C_ERR_OK, "UTF-8 data written to disk with BOM successfully"); - - // Test Point 3: Read text payload back from disk space - err = c_utf8_file_read(test_filename, &read_sb); - RUN_TEST(err == C_ERR_OK, "UTF-8 data read from disk successfully"); - - // Verify that the BOM was skipped and data size matches exactly - RUN_TEST(read_sb.size == write_sb.size, "File reader successfully filtered out the 3 BOM byte footprints from data tracking metrics"); - RUN_TEST(strcmp(read_sb.buffer, payload) == 0, "Reconstructed disk text payload holds proper string characters perfectly"); - - // Cleanup resources and temporary test files - c_StringBuffer_Destroy(&write_sb); - c_StringBuffer_Destroy(&read_sb); - remove(test_filename); // Remove transient testing file assets from system layout - - /* ------------------------------------------------------------------------------------------------------------------ */ - /* */ - - /* 27. UTF-8 File Logging Append & Streaming Line Read Verification */ - c_StringBuffer_t io_sb; - c_StringBuffer_t line_sb; - const char* log_filename = "nlp_stream_test.txt"; - - c_StringBuffer_Init(&io_sb, 32); - c_StringBuffer_Init(&line_sb, 32); - - // Test Point 1: Consecutive appends to evaluate new file vs exist rules - c_StringBuffer_AppendStr(&io_sb, "First Line: 自然语言\n"); - err = c_utf8_file_append(log_filename, &io_sb, C_TRUE); // Creates file with BOM - RUN_TEST(err == C_ERR_OK, "Append created a new file with a BOM header successfully"); - - c_StringBuffer_Clear(&io_sb); - c_StringBuffer_AppendStr(&io_sb, "Second Line: 大模型🚀\n"); - err = c_utf8_file_append(log_filename, &io_sb, C_TRUE); // Appends to existing file (BOM skipped) - RUN_TEST(err == C_ERR_OK, "Append safely added data to the existing file without duplicate BOM injections"); - - // Test Point 2: Streaming Line Reads via c_utf8_file_readline - FILE* stream_in = fopen(log_filename, "rb"); - RUN_TEST(stream_in != NULL, "Opened log test file for stream reading"); - - // Handle initial optional BOM detection before streaming lines - unsigned char check_bom[3]; - if (fread(check_bom, 1, 3, stream_in) == 3 && check_bom[0] == 0xEF && check_bom[1] == 0xBB && check_bom[2] == 0xBF) { - // BOM detected and skipped successfully - } else { - fseek(stream_in, 0, SEEK_SET); - } - - // Read Line 1 - err = c_utf8_file_readline(stream_in, &line_sb); - RUN_TEST(err == C_ERR_OK, "Read the first text line via streaming readline API"); - RUN_TEST(strcmp(line_sb.buffer, "First Line: 自然语言") == 0, "Line 1 string matches, trailing newline stripped cleanly"); - - // Read Line 2 - err = c_utf8_file_readline(stream_in, &line_sb); - RUN_TEST(err == C_ERR_OK, "Read the second text line via streaming readline API"); - RUN_TEST(strcmp(line_sb.buffer, "Second Line: 大模型🚀") == 0, "Line 2 string matches multi-byte characters and Emojis perfectly"); - - // Read Line 3 (Expect EOF termination failure status) - err = c_utf8_file_readline(stream_in, &line_sb); - RUN_TEST(err == C_ERR_FAIL, "Readline returns C_ERR_FAIL cleanly when hitting EOF boundaries"); - - // Cleanup resources - fclose(stream_in); - c_StringBuffer_Destroy(&io_sb); - c_StringBuffer_Destroy(&line_sb); - remove(log_filename); // Purge volatile testing file asset - - /* ------------------------------------------------------------------------------------------------------------------ */ - /* */ - printf("==================================================\n"); - printf("\033[32mSUCCESS: ALL C_UTF8_FILE COMPATIBLE INTERFACES PASSED!\033[0m\n"); - printf("==================================================\n"); - return C_ERR_OK; -} - -int main(int argc, char** argv){ - - return c_utf8_file_test(); -} diff --git a/Memory/c_Allocator.c b/Memory/c_Allocator.c new file mode 100644 index 0000000..ecbf406 --- /dev/null +++ b/Memory/c_Allocator.c @@ -0,0 +1,51 @@ +#include +#include + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +C_STATIC_FORCE_INLINE +void* c_DefaultAllocator_Alloc(c_size_t nBytes, void* ud) { + C_UNUSED(ud); + return malloc(nBytes); +} + +C_STATIC_FORCE_INLINE +C_ALLOCATOR_REALLOC_FN(c_DefaultAllocator_Realloc) { + C_UNUSED(ud); + C_UNUSED(nOldSize); + return realloc(ptr, nNewSize); +} + +C_STATIC_FORCE_INLINE +void* c_DefaultAllocator_Calloc(c_size_t nCount, c_size_t nBytes, void* ud) { + C_UNUSED(ud); + return calloc(nCount, nBytes); +} +C_STATIC_FORCE_INLINE +void c_DefaultAllocator_Free(void* ptr, void* ud) { + C_UNUSED(ud); + if (ptr) { + free(ptr); + } +} + +C_STATIC_FORCE_INLINE +void c_DefaultAllocator_Dtor(void* ud) { + C_UNUSED(ud); +} + + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + + +c_Allocator_t c_DefaultAllocator=(c_Allocator_t){ + c_DefaultAllocator_Alloc, + c_DefaultAllocator_Realloc, + c_DefaultAllocator_Calloc, + c_DefaultAllocator_Free, + c_DefaultAllocator_Dtor, + 0 +}; + diff --git a/Memory/c_Allocator.h b/Memory/c_Allocator.h new file mode 100644 index 0000000..3404fe2 --- /dev/null +++ b/Memory/c_Allocator.h @@ -0,0 +1,96 @@ +#ifndef INCLUDED_C_ALLOCATOR_H +#define INCLUDED_C_ALLOCATOR_H + +#ifndef INCLUDED_C_TYPES_H +#include +#endif /*INCLUDED_C_TYPES_H*/ + +#ifndef INCLUDED_ASSERT_H +#define INCLUDED_ASSERT_H +#include +#endif /*INCLUDED_ASSERT_H*/ + + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +typedef void* (*c_Allocator_AllocFn_t)(c_size_t nBytes, void* ud); +typedef void* (*c_Allocator_ReallocFn_t)(void* ptr, c_size_t nOldSize, c_size_t nNewSize, void* ud); +typedef void* (*c_Allocator_CallocFn_t)(c_size_t nCount, c_size_t nBytes, void* ud); +typedef void (*c_Allocator_FreeFn_t)(void* ptr, void* ud); +typedef void (*c_Allocator_DtorFn_t)(void* ud); + +typedef struct c_Allocator_t{ + c_Allocator_AllocFn_t alloc; + c_Allocator_ReallocFn_t realloc; + c_Allocator_CallocFn_t calloc; + c_Allocator_FreeFn_t free; + c_Allocator_DtorFn_t dtor; + void* ud; +}c_Allocator_t; + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +#define C_ALLOCATOR_ALLOC_FN(name) void* name(c_size_t nBytes, void* ud) +#define C_ALLOCATOR_REALLOC_FN(name) void* name(void* ptr, c_size_t nOldSize, c_size_t nNewSize, void* ud) +#define C_ALLOCATOR_CALLOC_FN(name) void* name(c_size_t nCount, c_size_t nBytes, void* ud) +#define C_ALLOCATOR_FREE_FN(name) void name(void* ptr, void* ud) +#define C_ALLOCATOR_DTOR_FN(name) void name(void* ud) + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +extern c_Allocator_t c_DefaultAllocator; + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + + +C_STATIC_FORCE_INLINE +void c_Allocator_Init(c_Allocator_t* self, + const c_Allocator_AllocFn_t alloc_fn, + const c_Allocator_ReallocFn_t realloc_fn, + const c_Allocator_CallocFn_t calloc_fn, + const c_Allocator_FreeFn_t free_fn, + const c_Allocator_DtorFn_t dtor_fn, + void* ud) { + self->alloc = alloc_fn; + self->realloc = realloc_fn; + self->calloc = calloc_fn; + self->free = free_fn; + self->dtor = dtor_fn; + self->ud = ud; +} + +C_STATIC_FORCE_INLINE +void* c_Allocator_Alloc(c_Allocator_t* self, c_size_t nBytes) { + if (!self || nBytes==0 || self->alloc==NULL) return NULL; + return self->alloc(nBytes, self->ud); +} + +C_STATIC_FORCE_INLINE +void* c_Allocator_Realloc(c_Allocator_t* self, void* ptr, c_size_t nOldSize, c_size_t nNewSize) { + if (!self || !ptr || nNewSize==0 || !self->realloc) return NULL; + return self->realloc(ptr, nOldSize, nNewSize, self->ud); +} + +C_STATIC_FORCE_INLINE +void* c_Allocator_Calloc(c_Allocator_t* self, c_size_t count, c_size_t nBytes) { + if (!self || count==0 || nBytes==0 || !self->calloc) return NULL; + return self->calloc(count, nBytes, self->ud); +} + +C_STATIC_FORCE_INLINE +void c_Allocator_Free(c_Allocator_t* self, void* ptr) { + if (!self || !ptr || !self->free) return; + self->free(ptr, self->ud); +} + +C_STATIC_FORCE_INLINE +void c_Allocator_Destroy(c_Allocator_t* self) { + if (!self || !self->dtor) return; + self->dtor(self->ud); +} + +#endif /*INCLUDED_C_ALLOCATOR_H*/ diff --git a/Memory/c_BuddyAllocator.c b/Memory/c_BuddyAllocator.c new file mode 100644 index 0000000..0384d98 --- /dev/null +++ b/Memory/c_BuddyAllocator.c @@ -0,0 +1 @@ +#include diff --git a/Memory/c_BuddyAllocator.h b/Memory/c_BuddyAllocator.h new file mode 100644 index 0000000..8df2d16 --- /dev/null +++ b/Memory/c_BuddyAllocator.h @@ -0,0 +1,96 @@ +#ifndef INCLUDED_C_BUDDYALLOCATOR_H +#define INCLUDED_C_BUDDYALLOCATOR_H + +#ifndef INCLUDED_C_BUDDY_H +#include +#endif /*INCLUDED_C_BUDDY_H*/ + + +#ifndef INCLUDED_C_ALLOCATOR_H +#include +#endif /*INCLUDED_C_ALLOCATOR_H*/ + + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +typedef struct { + c_Buddy_t* buddy; +}c_BuddyAllocator_t; + +C_STATIC_FORCE_INLINE +void c_BuddyAllocator_Init(c_BuddyAllocator_t* allocator, c_Buddy_t* buddy) { + allocator->buddy = buddy; +} + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +C_STATIC_FORCE_INLINE +C_ALLOCATOR_ALLOC_FN(c_BuddyAllocator_Alloc) { + c_BuddyAllocator_t* self = (c_BuddyAllocator_t*)ud; + if (!self || !self->buddy) return NULL; + return c_Buddy_Alloc(self->buddy, (int)nBytes); +} + +C_STATIC_FORCE_INLINE +C_ALLOCATOR_FREE_FN(c_BuddyAllocator_Free) { + c_BuddyAllocator_t* self = (c_BuddyAllocator_t*)ud; + if (!self || !self->buddy) return; + c_Buddy_Free(self->buddy, ptr); +} + +C_STATIC_FORCE_INLINE +C_ALLOCATOR_REALLOC_FN(c_BuddyAllocator_Realloc) { + c_BuddyAllocator_t* self = (c_BuddyAllocator_t*)ud; + if (!self || !self->buddy) return NULL; + // 情况 1: 指针为空,直接分配新内存 + if (!ptr) { + return c_Buddy_Alloc(self->buddy, (int)nNewSize); + } + // 情况 2: 新大小为 0,直接释放内存 + if (nNewSize==0) { + c_Buddy_Free(self->buddy, ptr); + return NULL; + } + // 核心优化:利用 Header 逆向获取该块在底层伙伴系统中的真实物理大小 + const c_BuddyBlock_t *block = (c_BuddyBlock_t *) ((uint8_t *) ptr - self->buddy->alignment); + const int actual_block_size = block->size; + + // 【就地复用判定】:如果新申请的大小没有超过当前伙伴块的物理承载上限,并且新大小不至于小到需要缩容割裂 + // 直接返回原指针,零拷贝,零内存搬迁! + if ((int)nNewSize <= actual_block_size && (int)nNewSize > (actual_block_size / 2)) { + return ptr; + } + + // 情况 3: 伙伴块大小不匹配(需要升级或降级阶数),申请新块 + void* new_ptr = c_Buddy_Alloc(self->buddy, (int)nNewSize); + if (!new_ptr) return NULL; + + // 计算安全的拷贝长度 + const c_size_t copy_size = ((c_size_t)actual_block_size < nNewSize) ? (c_size_t)actual_block_size : nNewSize; + + // 数据迁移 + memcpy(new_ptr, ptr, copy_size); + + // 释放旧伙伴块 + c_Buddy_Free(self->buddy, ptr); + + return new_ptr; +} + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +C_STATIC_FORCE_INLINE +c_Allocator_t c_BuddyAllocator_Build(c_BuddyAllocator_t* self, c_Buddy_t* buddy) { + c_BuddyAllocator_Init(self, buddy); + c_Allocator_t allocator={0}; + allocator.ud = self; + allocator.alloc = c_BuddyAllocator_Alloc; + allocator.free = c_BuddyAllocator_Free; + allocator.realloc = c_BuddyAllocator_Realloc; + return allocator; +} + +#endif /*INCLUDED_C_BUDDYALLOCATOR_H*/ diff --git a/Memory/c_PoolAllocator.c b/Memory/c_PoolAllocator.c new file mode 100644 index 0000000..ab33013 --- /dev/null +++ b/Memory/c_PoolAllocator.c @@ -0,0 +1 @@ +#include diff --git a/Memory/c_PoolAllocator.h b/Memory/c_PoolAllocator.h new file mode 100644 index 0000000..bc37f3f --- /dev/null +++ b/Memory/c_PoolAllocator.h @@ -0,0 +1,86 @@ +#ifndef INCLUDED_C_POOLALLOCATOR_H +#define INCLUDED_C_POOLALLOCATOR_H + +#ifndef INCLUDED_C_ALLOCATOR_H +#include +#endif /*INCLUDED_C_ALLOCATOR_H*/ + +#ifndef INCLUDED_C_POOL_H +#include +#endif /*INCLUDED_C_POOL_H*/ + + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +typedef struct { + c_Pool_t* pool; +}c_PoolAllocator_t; + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +C_STATIC_FORCE_INLINE +void c_PoolAllocator_Init(c_PoolAllocator_t* self, c_Pool_t* pool) { + self->pool = pool; +} + +C_STATIC_FORCE_INLINE +void c_PoolAllocator_Destroy(c_PoolAllocator_t* self) { + c_Pool_Destroy(self->pool); +} + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + + +C_STATIC_FORCE_INLINE +C_ALLOCATOR_ALLOC_FN(c_PoolAllocator_Alloc) { + C_UNUSED(nBytes); + c_PoolAllocator_t* self = (c_PoolAllocator_t*)ud; + if (!self || !self->pool) return NULL; + return c_Pool_Alloc(self->pool); +} + +C_STATIC_FORCE_INLINE +C_ALLOCATOR_REALLOC_FN(c_PoolAllocator_Realloc) { + c_PoolAllocator_t* self = (c_PoolAllocator_t*)ud; + if (!self || !self->pool) return NULL; + assert(nNewSize==self->pool->objSize); + if (!ptr) { + return c_Pool_Alloc(self->pool); + } + return ptr; +} + +C_STATIC_FORCE_INLINE +C_ALLOCATOR_FREE_FN(c_PoolAllocator_Free) { + c_PoolAllocator_t* self = (c_PoolAllocator_t*)ud; + if (!self || !self->pool) return; + c_Pool_Free(self->pool, ptr); +} + +C_STATIC_FORCE_INLINE +C_ALLOCATOR_DTOR_FN(c_PoolAllocator_Dtor) { + c_PoolAllocator_t* self = (c_PoolAllocator_t*)ud; + if (!self || !self->pool) return; + c_Pool_Destroy(self->pool); +} + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +C_STATIC_FORCE_INLINE +c_Allocator_t c_PoolAllocator_Build(c_PoolAllocator_t* self, c_Pool_t* pool) { + c_Allocator_t allocator; + self->pool = pool; + allocator.ud = self; + allocator.alloc = c_PoolAllocator_Alloc; + allocator.realloc = c_PoolAllocator_Realloc; + allocator.free = c_PoolAllocator_Free; + allocator.calloc = 0; + allocator.dtor = c_PoolAllocator_Dtor; + return allocator; +} + +#endif /*INCLUDED_C_POOLALLOCATOR_H*/ diff --git a/Search/c_BST.c b/Search/c_BST.c deleted file mode 100644 index a16afad..0000000 --- a/Search/c_BST.c +++ /dev/null @@ -1,158 +0,0 @@ -#include -#include - -/** - * Helper accessors to safely locate key and value buffers within a generic node allocation block. - */ -C_STATIC_FORCE_INLINE void* c_BST_NodeKey(c_BSTNode_t* node) { - return (void*)((char*)node + sizeof(c_BSTNode_t)); -} - -C_STATIC_FORCE_INLINE void* c_BST_NodeVal(c_BSTNode_t* node, c_size_t key_size) { - return (void*)((char*)node + sizeof(c_BSTNode_t) + key_size); -} - -/** - * Creates and initializes a standalone tree node layout. - */ -C_STATIC_FORCE_INLINE -c_BSTNode_t* c_BST_CreateNode(const void* key, const void* val, c_size_t ks, c_size_t vs) { - c_BSTNode_t* node = (c_BSTNode_t*)C_ALLOC(sizeof(c_BSTNode_t) + ks + vs); - if (node == NULL) return NULL; - - node->left = NULL; - node->right = NULL; - memcpy(c_BST_NodeKey(node), key, ks); - memcpy(c_BST_NodeVal(node, ks), val, vs); - return node; -} - -/** - * Internal recursive post-order destructor helper. - */ -static void c_BST_DestroyNodes(c_BSTNode_t* node) { - if (node == NULL) return; - c_BST_DestroyNodes(node->left); - c_BST_DestroyNodes(node->right); - C_FREE(node); -} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -c_err_t c_BST_Init(c_BST_t* tree, c_size_t key_size, c_size_t val_size, int (*compar)(const void*, const void*)) { - if (tree == NULL || key_size == 0 || val_size == 0 || compar == NULL) return C_ERR_PARAM; - tree->root = NULL; - tree->key_size = key_size; - tree->val_size = val_size; - tree->size = 0; - tree->compar = compar; - return C_ERR_OK; -} - -void c_BST_Destroy(c_BST_t* tree) { - if (tree) { - c_BST_DestroyNodes(tree->root); - tree->root = NULL; - tree->size = 0; - } -} - -c_err_t c_BST_Clear(c_BST_t* tree) { - if (tree == NULL) return C_ERR_PARAM; - c_BST_DestroyNodes(tree->root); - tree->root = NULL; - tree->size = 0; - return C_ERR_OK; -} - -c_bool_t c_BST_Contains(const c_BST_t* tree, const void* key) { - if (tree == NULL || key == NULL) return C_FALSE; - c_BSTNode_t* curr = tree->root; - while (curr != NULL) { - int cmp = tree->compar(key, c_BST_NodeKey(curr)); - if (cmp == 0) return C_TRUE; - curr = (cmp < 0) ? curr->left : curr->right; - } - return C_FALSE; -} - -c_err_t c_BST_Put(c_BST_t* tree, const void* key, const void* val) { - if (tree == NULL || key == NULL || val == NULL) return C_ERR_PARAM; - - c_BSTNode_t** link = &tree->root; - c_BSTNode_t* curr = tree->root; - - while (curr != NULL) { - int cmp = tree->compar(key, c_BST_NodeKey(curr)); - if (cmp == 0) { - // Overwrite existing value for matching symbol key - memcpy(c_BST_NodeVal(curr, tree->key_size), val, tree->val_size); - return C_ERR_OK; - } - link = (cmp < 0) ? &curr->left : &curr->right; - curr = *link; - } - - // Key is unique, construct a new node configuration structure - c_BSTNode_t* new_node = c_BST_CreateNode(key, val, tree->key_size, tree->val_size); - if (new_node == NULL) return C_ERR_NOMEM; - - *link = new_node; - tree->size++; - return C_ERR_OK; -} - -void* c_BST_Get(const c_BST_t* tree, const void* key) { - if (tree == NULL || key == NULL) return NULL; - c_BSTNode_t* curr = tree->root; - while (curr != NULL) { - int cmp = tree->compar(key, c_BST_NodeKey(curr)); - if (cmp == 0) return c_BST_NodeVal(curr, tree->key_size); - curr = (cmp < 0) ? curr->left : curr->right; - } - return NULL; -} - -c_err_t c_BST_Delete(c_BST_t* tree, const void* key) { - if (tree == NULL || key == NULL) return C_ERR_PARAM; - - c_BSTNode_t** link = &tree->root; - c_BSTNode_t* curr = tree->root; - - while (curr != NULL) { - int cmp = tree->compar(key, c_BST_NodeKey(curr)); - if (cmp == 0) break; - link = (cmp < 0) ? &curr->left : &curr->right; - curr = *link; - } - - if (curr == NULL) return C_ERR_NOTFOUND; - - // Standard Hibbard deletion implementation sequence matching tree boundaries - if (curr->left == NULL) { - *link = curr->right; - } else if (curr->right == NULL) { - *link = curr->left; - } else { - // Node has two children; locate the successor node (smallest node in the right sub-tree) - c_BSTNode_t** succ_link = &curr->right; - c_BSTNode_t* succ = curr->right; - while (succ->left != NULL) { - succ_link = &succ->left; - succ = succ->left; - } - - // Delink the successor node from its previous position - *succ_link = succ->right; - - // Route child structures of the node being deleted into the successor - succ->left = curr->left; - succ->right = curr->right; - *link = succ; - } - - C_FREE(curr); - tree->size--; - return C_ERR_OK; -} diff --git a/Search/c_BST.h b/Search/c_BST.h deleted file mode 100644 index b9cab47..0000000 --- a/Search/c_BST.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef INCLUDED_C_BST_H -#define INCLUDED_C_BST_H - -#ifndef INCLUDED_C_TYPES_H -#include -#endif /*INCLUDED_C_TYPES_H*/ - - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -// Forward declaration of internal node structure -typedef struct c_BSTNode { - struct c_BSTNode* left; // Pointer to left child - struct c_BSTNode* right; // Pointer to right child - // Node payload layout: key block followed immediately by the value block in memory -} c_BSTNode_t; - -// Binary Search Tree Context Structure -typedef struct { - c_BSTNode_t* root; // Root node pointer - c_size_t key_size; // Size of each key in bytes - c_size_t val_size; // Size of each value in bytes - c_size_t size; // Total number of nodes in the tree - int (*compar)(const void*, const void*); // Key comparison rule pointer -} c_BST_t; - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -c_err_t c_BST_Init(c_BST_t* tree, c_size_t key_size, c_size_t val_size, int (*compar)(const void*, const void*)) ; -void c_BST_Destroy(c_BST_t* tree); - -c_err_t c_BST_Clear(c_BST_t* tree); -c_bool_t c_BST_Contains(const c_BST_t* tree, const void* key); -c_err_t c_BST_Put(c_BST_t* tree, const void* key, const void* val); -void* c_BST_Get(const c_BST_t* tree, const void* key); -c_err_t c_BST_Delete(c_BST_t* tree, const void* key) ; - -#endif /*INCLUDED_C_BST_H*/ diff --git a/Search/c_BinarySearch.c b/Search/c_BinarySearch.c deleted file mode 100644 index b3c7a34..0000000 --- a/Search/c_BinarySearch.c +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/Search/c_BinarySearch.h b/Search/c_BinarySearch.h deleted file mode 100644 index 3379f9e..0000000 --- a/Search/c_BinarySearch.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef INCLUDED_C_BINARYSEARCH_H -#define INCLUDED_C_BINARYSEARCH_H - -#ifndef INCLUDED_C_TYPES_H -#include -#endif /*INCLUDED_C_TYPES_H*/ - - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -/** - * 通用二分查找函数 - * @param key 指向要查找的目标元素的指针 - * @param base 指向待查找数组首元素的指针 - * @param num 数组中元素的个数 - * @param size 每个元素的大小(以字节为单位,使用 sizeof 获取) - * @param compar 指向比较函数的指针(由用户提供比较逻辑) - * @return 找到则返回指向该元素的指针,未找到则返回 NULL - */ -C_STATIC_FORCE_INLINE -void* c_BinarySearch(const void* key, const void* base, c_size_t num, c_size_t size, - int (*compar)(const void*, const void*)) { - c_size_t left = 0; - c_size_t right = num; // 使用左闭右开区间 [left, right) 逻辑更清晰 - - while (left < right) { - c_size_t mid = left + (right - left) / 2; - - // 计算 mid 元素的内存地址:首地址 + 索引 * 每个元素的字节大小 - // 先强转为 char* 是为了按单字节进行指针偏移 - const void* midElem = (const char*)base + (mid * size); - - // 调用用户自定义的比较函数 - int cmp = compar(key, midElem); - - if (cmp == 0) { - return (void*)midElem; // 找到目标,返回其在数组中的地址 - } else if (cmp > 0) { - left = mid + 1; // key 大于 midElem,往右半部分找 - } else { - right = mid; // key 小于 midElem,往左半部分找 - } - } - - return NULL; // 未找到 -} - -#endif /*INCLUDED_C_BINARYSEARCH_H*/ diff --git a/Search/c_BinarySearchST.c b/Search/c_BinarySearchST.c deleted file mode 100644 index 3cab316..0000000 --- a/Search/c_BinarySearchST.c +++ /dev/null @@ -1,168 +0,0 @@ -#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_NOTFOUND; - - 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; -} diff --git a/Search/c_BinarySearchST.h b/Search/c_BinarySearchST.h deleted file mode 100644 index 8ef2593..0000000 --- a/Search/c_BinarySearchST.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef INCLUDED_C_BINARYSEARCHST_H -#define INCLUDED_C_BINARYSEARCHST_H - -#ifndef INCLUDED_C_TYPES_H -#include -#endif /*INCLUDED_C_TYPES_H*/ - - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -typedef struct { - void* keys; // Flat parallel array block storing keys - void* vals; // Flat parallel array block storing values - c_size_t key_size; // Size of each key in bytes (sizeof(Key)) - c_size_t val_size; // Size of each value in bytes (sizeof(Value)) - c_size_t capacity; // Maximum allocated element capacity - c_size_t size; // Current active entry count - int (*compar)(const void*, const void*); // Key comparison rule pointer -} c_BinarySearchST_t; - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ -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*)); -void c_BinarySearchST_Destroy(c_BinarySearchST_t* st); - -c_err_t c_BinarySearchST_Clear(c_BinarySearchST_t* st); -c_bool_t c_BinarySearchST_Contains(const c_BinarySearchST_t* st, const void* key); -c_err_t c_BinarySearchST_Put(c_BinarySearchST_t* st, const void* key, const void* val); -void* c_BinarySearchST_Get(const c_BinarySearchST_t* st, const void* key); -c_err_t c_BinarySearchST_Delete(c_BinarySearchST_t* st, const void* key); - -#endif /*INCLUDED_C_BINARYSEARCHST_H*/ diff --git a/Search/c_HashMap.c b/Search/c_HashMap.c deleted file mode 100644 index 49b16e5..0000000 --- a/Search/c_HashMap.c +++ /dev/null @@ -1,269 +0,0 @@ -#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 自動留在了下一個節點上,不需額外處理 -} - diff --git a/Search/c_HashMap.h b/Search/c_HashMap.h deleted file mode 100644 index 2f68949..0000000 --- a/Search/c_HashMap.h +++ /dev/null @@ -1,59 +0,0 @@ -#ifndef INCLUDED_C_HASHMAP_H -#define INCLUDED_C_HASHMAP_H - -#ifndef INCLUDED_C_TYPES_H -#include -#endif /*INCLUDED_C_TYPES_H*/ - - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -typedef struct c_HashMapEntry_t { - void* key; - void* value; - struct c_HashMapEntry_t* next; -} c_HashMapEntry_t; - -typedef uint32_t (*c_HashMap_Hash_f)(const void* key, int key_size); -typedef int (*c_HashMap_Compare_f)(const void* key1, const void* key2, int key_size); - -typedef struct { - c_HashMapEntry_t** buckets; // Array of entry linked list head pointers - c_size_t capacity; // Number of buckets allocated - c_size_t size; // Number of active key-value pairs stored - int key_size; // Byte footprint of the key type - int value_size; // Byte footprint of the value type - c_HashMap_Hash_f hash; // User hash calculation function - c_HashMap_Compare_f compare;// User key comparison function -} c_HashMap_t; - -typedef struct { - c_HashMap_t* map; // 繫結的雜湊表 - c_size_t bucket_index; // 當前走訪的桶子索引 (Bucket Index) - c_HashMapEntry_t** entry; // 指向當前節點指標的指標,用於 O(1) 安全刪除 -} c_HashMapKeyIter_t; - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - - -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); -void c_HashMap_Destroy(c_HashMap_t* self); - -c_err_t c_HashMap_Put(c_HashMap_t* self, const void* key, const void* value); -c_err_t c_HashMap_Get(c_HashMap_t* self, const void* key, void* out_value); -c_err_t c_HashMap_Remove(c_HashMap_t* self, const void* key); -c_bool_t c_HashMap_Contains(c_HashMap_t* self, const void* key); - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -void c_HashMapKeyIter_Init(c_HashMapKeyIter_t* self, c_HashMap_t* map); -c_bool_t c_HashMapKeyIter_HasNext(c_HashMapKeyIter_t* self); -void* c_HashMapKeyIter_Next(c_HashMapKeyIter_t* self); -void* c_HashMapKeyIter_Get(c_HashMapKeyIter_t* self); -void c_HashMapKeyIter_Remove(c_HashMapKeyIter_t* self); - -#endif /*INCLUDED_C_HASHMAP_H*/ diff --git a/Search/c_HashSet.c b/Search/c_HashSet.c deleted file mode 100644 index 5ad349e..0000000 --- a/Search/c_HashSet.c +++ /dev/null @@ -1,45 +0,0 @@ -#include - -// 虛擬佔位常數,所有集合元素在底層對應同一個 Dummy 值的地址 -static const int dummy_value = 1; - -c_err_t c_HashSet_Init(c_HashSet_t* self, int obj_size, c_size_t initial_capacity, - c_HashMap_Hash_f hash, c_HashMap_Compare_f compare) { - if (!self) return C_ERR_PARAM; - - // 初始化底層對映的雜湊表,value_size 固定設為常數大小 - return c_HashMap_Init(&self->map, obj_size, sizeof(int), initial_capacity, hash, compare); -} - -void c_HashSet_Destroy(c_HashSet_t* self) { - if (!self) return; - c_HashMap_Destroy(&self->map); -} - -// 推入元素:若元素已存在則攔截並報錯,確保唯一性 -c_err_t c_HashSet_Add(c_HashSet_t* self, const void* obj) { - if (!self || !obj) return C_ERR_PARAM; - - // 先檢查是否已經存在此元素 - if (c_HashMap_Contains(&self->map, obj)) { - return C_ERR_ALREADY_EXISTS; - } - - // 將物件當作 Key 寫入,Value 塞入 Dummy 常數 - return c_HashMap_Put(&self->map, obj, &dummy_value); -} - -c_err_t c_HashSet_Remove(c_HashSet_t* self, const void* obj) { - if (!self || !obj) return C_ERR_PARAM; - return c_HashMap_Remove(&self->map, obj); -} - -c_bool_t c_HashSet_Contains(c_HashSet_t* self, const void* obj) { - if (!self || !obj) return C_FALSE; - return c_HashMap_Contains(&self->map, obj); -} - -c_size_t c_HashSet_GetSize(const c_HashSet_t* self) { - if (!self) return 0; - return self->map.size; -} \ No newline at end of file diff --git a/Search/c_HashSet.h b/Search/c_HashSet.h deleted file mode 100644 index e83d57e..0000000 --- a/Search/c_HashSet.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef INCLUDED_C_HASHSET_H -#define INCLUDED_C_HASHSET_H - -#ifndef INCLUDED_C_HASHMAP_H -#include -#endif /*INCLUDED_C_HASHMAP_H*/ - - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -typedef struct { - c_HashMap_t map; // 底層由 HashMap 驅動 -} c_HashSet_t; - -// 集合迭代器(直接重定向至您的 HashMapKeyIter) -typedef c_HashMapKeyIter_t c_HashSetIter_t; - -// 核心函數宣告 -c_err_t c_HashSet_Init(c_HashSet_t* self, int obj_size, c_size_t initial_capacity, - c_HashMap_Hash_f hash, c_HashMap_Compare_f compare); -void c_HashSet_Destroy(c_HashSet_t* self); - -c_err_t c_HashSet_Add(c_HashSet_t* self, const void* obj); -c_err_t c_HashSet_Remove(c_HashSet_t* self, const void* obj); -c_bool_t c_HashSet_Contains(c_HashSet_t* self, const void* obj); -c_size_t c_HashSet_GetSize(const c_HashSet_t* self); - -// 集合迭代器巨集/函數重定向(完美保持一致性) -#define c_HashSetIter_Init(self, set) c_HashMapKeyIter_Init(self, &(set)->map) -#define c_HashSetIter_HasNext(self) c_HashMapKeyIter_HasNext(self) -#define c_HashSetIter_Get(self) c_HashMapKeyIter_Get(self) -#define c_HashSetIter_Next(self) c_HashMapKeyIter_Next(self) -#define c_HashSetIter_Remove(self) c_HashMapKeyIter_Remove(self) - -#endif /*INCLUDED_C_HASHSET_H*/ diff --git a/Search/c_LinearProbingHashST.c b/Search/c_LinearProbingHashST.c deleted file mode 100644 index 5e83a09..0000000 --- a/Search/c_LinearProbingHashST.c +++ /dev/null @@ -1,196 +0,0 @@ -#include -#include - -/** - * FNV-1a baseline string/scalar data hash scrambling algorithm. - */ -C_STATIC_FORCE_INLINE -uint32_t c_LPHash_DefaultHash(const void* key, c_size_t key_size) { - const uint8_t* data = (const uint8_t*)key; - uint32_t hash = 0x811C9DC5; - for (c_size_t i = 0; i < key_size; i++) { - hash ^= data[i]; - hash *= 0x01000193; - } - return hash; -} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -c_err_t c_LinearProbingHashST_Init(c_LinearProbingHashST_t* st, c_size_t initial_capacity, - c_size_t key_size, c_size_t val_size, - uint32_t (*hash_fn)(const void*, c_size_t), - int (*key_compar)(const void*, const void*)) { - if (st == NULL || initial_capacity == 0 || key_size == 0 || val_size == 0 || key_compar == NULL) { - return C_ERR_PARAM; - } - - st->M = initial_capacity; - st->N = 0; - st->key_size = key_size; - st->val_size = val_size; - st->hash_fn = (hash_fn != NULL) ? hash_fn : c_LPHash_DefaultHash; - st->key_compar = key_compar; - - st->keys = C_ALLOC(st->M * key_size); - st->vals = C_ALLOC(st->M * val_size); - st->occupied = (c_bool_t*)C_ALLOC(st->M * sizeof(c_bool_t)); - - if (st->keys == NULL || st->vals == NULL || st->occupied == NULL) { - C_FREE(st->keys); C_FREE(st->vals); C_FREE(st->occupied); - st->keys = NULL; st->vals = NULL; st->occupied = NULL; - return C_ERR_NOMEM; - } - - memset(st->occupied, C_FALSE, st->M * sizeof(c_bool_t)); - return C_ERR_OK; -} - -void c_LinearProbingHashST_Destroy(c_LinearProbingHashST_t* st) { - if (st) { - C_FREE(st->keys); st->keys = NULL; - C_FREE(st->vals); st->vals = NULL; - C_FREE(st->occupied); st->occupied = NULL; - st->M = 0; - st->N = 0; - } -} - -/** - * Explicit internal resizing routing handler. - * Essential for keeping the Load Factor (alpha) under 0.5 to prevent clustering. - */ -static c_err_t c_LinearProbingHashST_Resize(c_LinearProbingHashST_t* st, c_size_t capacity) { - c_LinearProbingHashST_t temp_st; - c_err_t err = c_LinearProbingHashST_Init(&temp_st, capacity, st->key_size, st->val_size, st->hash_fn, st->key_compar); - if (err != C_ERR_OK) return err; - - 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; - - // Rehash and insert all existing active items into the new, expanded table footprint - for (c_size_t i = 0; i < st->M; i++) { - if (st->occupied[i]) { - extern c_err_t c_LinearProbingHashST_Put(c_LinearProbingHashST_t*, const void*, const void*); - err = c_LinearProbingHashST_Put(&temp_st, keys_base + (i * ks), vals_base + (i * vs)); - if (err != C_ERR_OK) { - c_LinearProbingHashST_Destroy(&temp_st); - return err; - } - } - } - - // Swap parameters to apply the newly rehashed table context - C_FREE(st->keys); C_FREE(st->vals); C_FREE(st->occupied); - st->keys = temp_st.keys; - st->vals = temp_st.vals; - st->occupied = temp_st.occupied; - st->M = temp_st.M; - return C_ERR_OK; -} - -c_err_t c_LinearProbingHashST_Put(c_LinearProbingHashST_t* st, const void* key, const void* val) { - if (st == NULL || key == NULL || val == NULL) return C_ERR_PARAM; - - // Enforce an upper bound load factor limit of 50% to mitigate clustering degradation - if (st->N >= st->M / 2) { - c_err_t err = c_LinearProbingHashST_Resize(st, st->M * 2); - if (err != C_ERR_OK) return err; - } - - 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; - - c_size_t i; - for (i = st->hash_fn(key, ks) % st->M; st->occupied[i]; i = (i + 1) % st->M) { - if (st->key_compar(keys_base + (i * ks), key) == 0) { - // Found existing key match: update values block payload in place - memcpy(vals_base + (i * vs), val, vs); - return C_ERR_OK; - } - } - - // Insert new item into the available open slot found by probing - memcpy(keys_base + (i * ks), key, ks); - memcpy(vals_base + (i * vs), val, vs); - st->occupied[i] = C_TRUE; - st->N++; - - return C_ERR_OK; -} - -void* c_LinearProbingHashST_Get(const c_LinearProbingHashST_t* st, const void* key) { - if (st == NULL || st->keys == NULL || key == NULL) return NULL; - - char* keys_base = (char*)st->keys; - c_size_t ks = st->key_size; - - for (c_size_t i = st->hash_fn(key, ks) % st->M; st->occupied[i]; i = (i + 1) % st->M) { - if (st->key_compar(keys_base + (i * ks), key) == 0) { - return (char*)st->vals + (i * st->val_size); - } - } - return NULL; -} - -c_bool_t c_LinearProbingHashST_Contains(const c_LinearProbingHashST_t* st, const void* key) { - return c_LinearProbingHashST_Get(st, key) != NULL; -} - -c_err_t c_LinearProbingHashST_Delete(c_LinearProbingHashST_t* st, const void* key) { - if (st == NULL || key == NULL) return C_ERR_PARAM; - - char* keys_base = (char*)st->keys; - c_size_t ks = st->key_size; - c_size_t vs = st->val_size; - - c_size_t i = st->hash_fn(key, ks) % st->M; - while (st->occupied[i]) { - if (st->key_compar(keys_base + (i * ks), key) == 0) { - break; - } - i = (i + 1) % st->M; - } - - // Key to delete was not found in the hash table - if (!st->occupied[i]) return C_ERR_NOTFOUND; - - // Hard delete: Free the targeted slot index flag - st->occupied[i] = C_FALSE; - st->N--; - - // CRITICAL REQUIREMENT: Rehash all subsequent cluster elements - // to bridge the open slot gap caused by deletion, preventing future search short-circuits. - i = (i + 1) % st->M; - while (st->occupied[i]) { - // Capture old keys/values payload allocations locally - void* key_to_rehash = C_ALLOC(ks); - void* val_to_rehash = C_ALLOC(vs); - memcpy(key_to_rehash, keys_base + (i * ks), ks); - memcpy(val_to_rehash, (char*)st->vals + (i * vs), vs); - - // Explicitly clear the current cluster entry tracking variables - st->occupied[i] = C_FALSE; - st->N--; - - // Re-insert the captured element into the table using standard routing rules - c_LinearProbingHashST_Put(st, key_to_rehash, val_to_rehash); - - C_FREE(key_to_rehash); - C_FREE(val_to_rehash); - - i = (i + 1) % st->M; - } - - // Shrink the table capacity automatically if utilization drops below 12.5% - if (st->N > 0 && st->N <= st->M / 8) { - c_LinearProbingHashST_Resize(st, st->M / 2); - } - - return C_ERR_OK; -} diff --git a/Search/c_LinearProbingHashST.h b/Search/c_LinearProbingHashST.h deleted file mode 100644 index 5ab390f..0000000 --- a/Search/c_LinearProbingHashST.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef INCLUDED_C_LINEARPROBINGHASHST_H -#define INCLUDED_C_LINEARPROBINGHASHST_H - -#ifndef INCLUDED_C_TYPES_H -#include -#endif /*INCLUDED_C_TYPES_H*/ - - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -// Linear Probing Hash Symbol Table Instance Layout -typedef struct { - void* keys; // Flat parallel array block storing keys - void* vals; // Flat parallel array block storing values - c_bool_t* occupied; // Flag array tracking whether a specific slot is filled - - c_size_t M; // Linear probing table capacity (array size) - c_size_t N; // Current active element count - c_size_t key_size; // Size of each key in bytes - c_size_t val_size; // Size of each value in bytes - - uint32_t (*hash_fn)(const void* key, c_size_t key_size); // Hash function - int (*key_compar)(const void*, const void*); // Key comparison rule pointer -} c_LinearProbingHashST_t; - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -c_err_t c_LinearProbingHashST_Init(c_LinearProbingHashST_t* st, c_size_t initial_capacity, - c_size_t key_size, c_size_t val_size, - uint32_t (*hash_fn)(const void*, c_size_t), - int (*key_compar)(const void*, const void*)); -void c_LinearProbingHashST_Destroy(c_LinearProbingHashST_t* st); -c_err_t c_LinearProbingHashST_Put(c_LinearProbingHashST_t* st, const void* key, const void* val); -void* c_LinearProbingHashST_Get(const c_LinearProbingHashST_t* st, const void* key); -c_bool_t c_LinearProbingHashST_Contains(const c_LinearProbingHashST_t* st, const void* key); -c_err_t c_LinearProbingHashST_Delete(c_LinearProbingHashST_t* st, const void* key); - -#endif /*INCLUDED_C_LINEARPROBINGHASHST_H*/ diff --git a/Search/c_RedBlackBST.c b/Search/c_RedBlackBST.c deleted file mode 100644 index 18e715e..0000000 --- a/Search/c_RedBlackBST.c +++ /dev/null @@ -1,154 +0,0 @@ -#include -#include - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - - -// --- Structural Balancing Primitives --- - -C_STATIC_FORCE_INLINE -c_RBNode_t* c_RBBST_RotateLeft(c_RBNode_t* h) { - c_RBNode_t* x = h->right; - h->right = x->left; - x->left = h; - x->color = h->color; - h->color = C_RB_RED; - return x; -} - -C_STATIC_FORCE_INLINE -c_RBNode_t* c_RBBST_RotateRight(c_RBNode_t* h) { - c_RBNode_t* x = h->left; - h->left = x->right; - x->right = h; - x->color = h->color; - h->color = C_RB_RED; - return x; -} - -C_STATIC_FORCE_INLINE -void c_RBBST_FlipColors(c_RBNode_t* h) { - h->color = !h->color; - if (h->left) h->left->color = !h->left->color; - if (h->right) h->right->color = !h->right->color; -} - -/** - * Creates and initializes a standalone tree node. - */ -C_STATIC_FORCE_INLINE -c_RBNode_t* c_RBBST_CreateNode(const void* key, const void* val, c_size_t ks, c_size_t vs) { - c_RBNode_t* node = (c_RBNode_t*)C_ALLOC(sizeof(c_RBNode_t) + ks + vs); - if (node == NULL) return NULL; - - node->left = NULL; - node->right = NULL; - node->color = C_RB_RED; // New nodes are always inserted as RED links - memcpy(c_RBBST_NodeKey(node), key, ks); - memcpy(c_RBBST_NodeVal(node, ks), val, vs); - return node; -} - -static void c_RBBST_DestroyNodes(c_RBNode_t* node) { - if (node == NULL) return; - c_RBBST_DestroyNodes(node->left); - c_RBBST_DestroyNodes(node->right); - C_FREE(node); -} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -c_err_t c_RedBlackBST_Init(c_RedBlackBST_t* tree, c_size_t key_size, c_size_t val_size, - int (*compar)(const void*, const void*)) { - if (tree == NULL || key_size == 0 || val_size == 0 || compar == NULL) return C_ERR_PARAM; - tree->root = NULL; - tree->key_size = key_size; - tree->val_size = val_size; - tree->size = 0; - tree->compar = compar; - return C_ERR_OK; -} - -void c_RedBlackBST_Destroy(c_RedBlackBST_t* tree) { - if (tree) { - c_RBBST_DestroyNodes(tree->root); - tree->root = NULL; - tree->size = 0; - } -} - -c_bool_t c_RedBlackBST_Contains(const c_RedBlackBST_t* tree, const void* key) { - if (tree == NULL || key == NULL) return C_FALSE; - c_RBNode_t* curr = tree->root; - while (curr != NULL) { - int cmp = tree->compar(key, c_RBBST_NodeKey(curr)); - if (cmp == 0) return C_TRUE; - curr = (cmp < 0) ? curr->left : curr->right; - } - return C_FALSE; -} - -void* c_RedBlackBST_Get(const c_RedBlackBST_t* tree, const void* key) { - if (tree == NULL || key == NULL) return NULL; - c_RBNode_t* curr = tree->root; - while (curr != NULL) { - int cmp = tree->compar(key, c_RBBST_NodeKey(curr)); - if (cmp == 0) return c_RBBST_NodeVal(curr, tree->key_size); - curr = (cmp < 0) ? curr->left : curr->right; - } - return NULL; -} - -/** - * Recursive insertion core worker. - */ -static c_RBNode_t* c_RBBST_PutInternal(c_RedBlackBST_t* tree, c_RBNode_t* h, - const void* key, const void* val, c_err_t* err) { - if (h == NULL) { - c_RBNode_t* node = c_RBBST_CreateNode(key, val, tree->key_size, tree->val_size); - if (node == NULL) *err = C_ERR_NOMEM; - else tree->size++; - return node; - } - - int cmp = tree->compar(key, c_RBBST_NodeKey(h)); - if (cmp < 0) { - h->left = c_RBBST_PutInternal(tree, h->left, key, val, err); - } else if (cmp > 0) { - h->right = c_RBBST_PutInternal(tree, h->right, key, val, err); - } else { - // Enforce update if key matches existing tracking cell - memcpy(c_RBBST_NodeVal(h, tree->key_size), val, tree->val_size); - } - - // --- Left-Leaning Red-Black Balancing Pipeline Validation Steps --- - // Condition 1: Right child is red, left child is black -> Rotate Left - if (c_RBBST_IsRed(h->right) && !c_RBBST_IsRed(h->left)) { - h = c_RBBST_RotateLeft(h); - } - // Condition 2: Left child and left grandchild are both red -> Rotate Right - if (c_RBBST_IsRed(h->left) && c_RBBST_IsRed(h->left->left)) { - h = c_RBBST_RotateRight(h); - } - // Condition 3: Both children are red -> Color Split Flip - if (c_RBBST_IsRed(h->left) && c_RBBST_IsRed(h->right)) { - c_RBBST_FlipColors(h); - } - - return h; -} - -c_err_t c_RedBlackBST_Put(c_RedBlackBST_t* tree, const void* key, const void* val) { - if (tree == NULL || key == NULL || val == NULL) return C_ERR_PARAM; - - c_err_t err = C_ERR_OK; - tree->root = c_RBBST_PutInternal(tree, tree->root, key, val, &err); - - if (tree->root != NULL) { - tree->root->color = C_RB_BLACK; // Root link must consistently point black - } - - return err; -} diff --git a/Search/c_RedBlackBST.h b/Search/c_RedBlackBST.h deleted file mode 100644 index 5ae6859..0000000 --- a/Search/c_RedBlackBST.h +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef INCLUDED_C_REDBLACKBST_H -#define INCLUDED_C_REDBLACKBST_H - -#ifndef INCLUDED_C_TYPES_H -#include -#endif /*INCLUDED_C_TYPES_H*/ - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -// Link Color Definitions -typedef enum { - C_RB_BLACK = 0, - C_RB_RED = 1 -} c_RBColor_t; - -// Node Structure Layout -typedef struct c_RBNode { - struct c_RBNode* left; - struct c_RBNode* right; - c_RBColor_t color; - // Payload layout: key block followed immediately by the value block in memory -} c_RBNode_t; - -// Red-Black BST Context Structure -typedef struct { - c_RBNode_t* root; - c_size_t key_size; - c_size_t val_size; - c_size_t size; - int (*compar)(const void*, const void*); -} c_RedBlackBST_t; - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - - -// --- Internal Helper Accessors --- -C_STATIC_FORCE_INLINE -void* c_RBBST_NodeKey(c_RBNode_t* node) { - return (void*)((char*)node + sizeof(c_RBNode_t)); -} - -C_STATIC_FORCE_INLINE -void* c_RBBST_NodeVal(c_RBNode_t* node, c_size_t key_size) { - return (void*)((char*)node + sizeof(c_RBNode_t) + key_size); -} - -C_STATIC_FORCE_INLINE -c_bool_t c_RBBST_IsRed(c_RBNode_t* node) { - if (node == NULL) return C_FALSE; - return node->color == C_RB_RED; -} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -c_err_t c_RedBlackBST_Init(c_RedBlackBST_t* tree, c_size_t key_size, c_size_t val_size, - int (*compar)(const void*, const void*)); -void c_RedBlackBST_Destroy(c_RedBlackBST_t* tree); - -c_bool_t c_RedBlackBST_Contains(const c_RedBlackBST_t* tree, const void* key); -c_err_t c_RedBlackBST_Put(c_RedBlackBST_t* tree, const void* key, const void* val); -void* c_RedBlackBST_Get(const c_RedBlackBST_t* tree, const void* key); - -#endif /*INCLUDED_C_REDBLACKBST_H*/ diff --git a/Search/c_SeparateChainingHashST.c b/Search/c_SeparateChainingHashST.c deleted file mode 100644 index f245af2..0000000 --- a/Search/c_SeparateChainingHashST.c +++ /dev/null @@ -1,308 +0,0 @@ -#include -#include - -/** - * Default MurmurHash3 (32-bit) implementation for basic scalar and string keys. - * Maximizes distribution and avalanche property to minimize bucket collisions. - */ -C_STATIC_FORCE_INLINE -uint32_t c_SCHash_DefaultHash(const void* key, c_size_t key_size) { - const uint8_t* data = (const uint8_t*)key; - uint32_t hash = 0x811C9DC5; // FNV-1a baseline for quick scrambling if needed, but using a robust mix - for (c_size_t i = 0; i < key_size; i++) { - hash ^= data[i]; - hash *= 0x01000193; - } - return hash; -} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -c_err_t c_SeparateChainingHashST_Init(c_SeparateChainingHashST_t* st, c_size_t num_buckets, - c_size_t key_size, c_size_t val_size, - uint32_t (*hash_fn)(const void*, c_size_t), - int (*key_compar)(const void*, const void*)) { - if (st == NULL || num_buckets == 0 || key_size == 0 || val_size == 0 || key_compar == NULL) { - return C_ERR_PARAM; - } - - st->num_buckets = num_buckets; - st->key_size = key_size; - st->val_size = val_size; - st->size = 0; - st->hash_fn = (hash_fn != NULL) ? hash_fn : c_SCHash_DefaultHash; - st->key_compar = key_compar; - - // Allocate array of bucket head pointers - st->buckets = (c_SCHashNode_t**)C_ALLOC(num_buckets * sizeof(c_SCHashNode_t*)); - if (st->buckets == NULL) return C_ERR_NOMEM; - - // Clear bucket heads cleanly - memset(st->buckets, 0, num_buckets * sizeof(c_SCHashNode_t*)); - - return C_ERR_OK; -} - -void c_SeparateChainingHashST_Destroy(c_SeparateChainingHashST_t* st) { - if (st && st->buckets) { - for (c_size_t i = 0; i < st->num_buckets; i++) { - c_SCHashNode_t* curr = st->buckets[i]; - while (curr != NULL) { - c_SCHashNode_t* next = curr->next; - C_FREE(curr); - curr = next; - } - } - C_FREE(st->buckets); - st->size = 0; - st->num_buckets = 0; - } -} - -c_bool_t c_SeparateChainingHashST_Contains(const c_SeparateChainingHashST_t* st, const void* key) { - if (st == NULL || st->buckets == NULL || key == NULL) return C_FALSE; - - uint32_t hash = st->hash_fn(key, st->key_size); - c_size_t bucket_idx = hash % st->num_buckets; - - c_SCHashNode_t* curr = st->buckets[bucket_idx]; - while (curr != NULL) { - if (st->key_compar(key, c_SCHash_NodeKey(curr)) == 0) { - return C_TRUE; - } - curr = curr->next; - } - return C_FALSE; -} - -c_err_t c_SeparateChainingHashST_Put(c_SeparateChainingHashST_t* st, const void* key, const void* val) { - if (st == NULL || st->buckets == NULL || key == NULL || val == NULL) return C_ERR_PARAM; - - uint32_t hash = st->hash_fn(key, st->key_size); - c_size_t bucket_idx = hash % st->num_buckets; - - c_SCHashNode_t* curr = st->buckets[bucket_idx]; - while (curr != NULL) { - if (st->key_compar(key, c_SCHash_NodeKey(curr)) == 0) { - // Key match: Overwrite value in place - memcpy(c_SCHash_NodeVal(curr, st->key_size), val, st->val_size); - return C_ERR_OK; - } - curr = curr->next; - } - - // Key not found: Construct a unified packed node - c_SCHashNode_t* new_node = (c_SCHashNode_t*)C_ALLOC(sizeof(c_SCHashNode_t) + st->key_size + st->val_size); - if (new_node == NULL) return C_ERR_NOMEM; - - memcpy(c_SCHash_NodeKey(new_node), key, st->key_size); - memcpy(c_SCHash_NodeVal(new_node, st->key_size), val, st->val_size); - - // Insert at head of the bucket chain (O(1) insertion) - new_node->next = st->buckets[bucket_idx]; - st->buckets[bucket_idx] = new_node; - st->size++; - - return C_ERR_OK; -} - -void* c_SeparateChainingHashST_Get(const c_SeparateChainingHashST_t* st, const void* key) { - if (st == NULL || st->buckets == NULL || key == NULL) return NULL; - - uint32_t hash = st->hash_fn(key, st->key_size); - c_size_t bucket_idx = hash % st->num_buckets; - - c_SCHashNode_t* curr = st->buckets[bucket_idx]; - while (curr != NULL) { - if (st->key_compar(key, c_SCHash_NodeKey(curr)) == 0) { - return c_SCHash_NodeVal(curr, st->key_size); - } - curr = curr->next; - } - return NULL; -} - -c_err_t c_SeparateChainingHashST_Delete(c_SeparateChainingHashST_t* st, const void* key) { - if (st == NULL || st->buckets == NULL || key == NULL) return C_ERR_PARAM; - - uint32_t hash = st->hash_fn(key, st->key_size); - c_size_t bucket_idx = hash % st->num_buckets; - - c_SCHashNode_t** link = &st->buckets[bucket_idx]; - c_SCHashNode_t* curr = st->buckets[bucket_idx]; - - while (curr != NULL) { - if (st->key_compar(key, c_SCHash_NodeKey(curr)) == 0) { - // Unlink node cleanly using double pointer redirection - *link = curr->next; - C_FREE(curr); - st->size--; - return C_ERR_OK; - } - link = &curr->next; - curr = curr->next; - } - - return C_ERR_NOTFOUND; -} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ -/** - * Steps the cursor forward to the next occupied bucket slot. - */ -C_STATIC_FORCE_INLINE -void c_SCHashIter_AdvanceToNextValid(c_SeparateChainingHashSTKeyIter_t* iter) { - iter->curr_node = NULL; - iter->curr_bucket++; - - while (iter->curr_bucket < iter->st->num_buckets) { - if (iter->st->buckets[iter->curr_bucket] != NULL) { - iter->curr_node = iter->st->buckets[iter->curr_bucket]; - break; - } - iter->curr_bucket++; - } -} - -/** - * Initialize the Separate Chaining Hash Symbol Table Key Iterator. - * Traverses forward to latch onto the very first active key node element across bucket slots. - * - * Time Complexity: O(M) worst-case to locate first entry where M is bucket count | Space Complexity: O(1) - */ -c_err_t c_SeparateChainingHashSTKeyIter_Init(c_SeparateChainingHashSTKeyIter_t* iter, - const c_SeparateChainingHashST_t* st) { - if (iter == NULL || st == NULL) return C_ERR_PARAM; - - // Cast away constness to bind to the non-const structural field required for Remove() - iter->st = (c_SeparateChainingHashST_t*)st; - iter->curr_bucket = 0; - iter->curr_node = NULL; - iter->last_returned = NULL; - - // Advance forward to locate the first populated bucket slot index context - while (iter->curr_bucket < st->num_buckets) { - if (st->buckets[iter->curr_bucket] != NULL) { - iter->curr_node = st->buckets[iter->curr_bucket]; - break; - } - iter->curr_bucket++; - } - - return C_ERR_OK; -} - -/** - * Clean up allocations within the context wrapper safely. - */ -void c_SeparateChainingHashSTKeyIter_Destroy(c_SeparateChainingHashSTKeyIter_t* iter) { - if (iter) { - iter->st = NULL; - iter->curr_bucket = 0; - iter->curr_node = NULL; - iter->last_returned = NULL; - } -} - -/** - * Evaluates whether any keys remain unread inside the look-ahead pipeline. - */ -c_bool_t c_SeparateChainingHashSTKeyIter_HasNext(const c_SeparateChainingHashSTKeyIter_t* iter) { - if (iter == NULL) return C_FALSE; - return iter->curr_node != NULL; -} - -/** - * Retrieve a reference pointer to the key most recently extracted by Next(). - * - * Time Complexity: O(1) constant runtime overhead - */ -void* c_SeparateChainingHashSTKeyIter_Get(c_SeparateChainingHashSTKeyIter_t* iter) { - if (iter == NULL || iter->curr_node == NULL) return NULL; - - // 直接回傳當前指標停靠節點的 Key - iter->last_returned = c_SCHash_NodeKey(iter->curr_node); - return iter->last_returned; -} - -/** - * Extracts a pointer to the next consecutive key element. - * Updates internal path registers to step along table slots. - * - * Time Complexity: O(M) worst case to skip empty buckets, O(1) amortized - */ -void* c_SeparateChainingHashSTKeyIter_Next(c_SeparateChainingHashSTKeyIter_t* iter) { - if (iter == NULL || iter->curr_node == NULL) return NULL; - - c_SCHashNode_t* node = iter->curr_node; - void* current_key = c_SCHash_NodeKey(node); - - // Track history for the Remove state machine - iter->last_returned = current_key; - - // Advance forward natively - if (node->next != NULL) { - iter->curr_node = node->next; - } else { - c_SCHashIter_AdvanceToNextValid(iter); - } - - return current_key; -} - - - -/** - * Stateful Removal Engine for the Hash table chain structure layout. - * Safely handles unlinking modifications and heals traversal registers in O(1) amortized time. - */ -c_err_t c_SeparateChainingHashSTKeyIter_Remove(c_SeparateChainingHashSTKeyIter_t* iter) { - if (iter == NULL || iter->st == NULL) return C_ERR_PARAM; - if (iter->last_returned == NULL) return C_ERR_NOTFOUND; - - // Find the targeted bucket index for the key we are deleting - uint32_t hash = iter->st->hash_fn(iter->last_returned, iter->st->key_size); - c_size_t target_bucket = hash % iter->st->num_buckets; - - // Use a double pointer to locate and delete the node from the backing list chain - c_SCHashNode_t** link = &iter->st->buckets[target_bucket]; - c_SCHashNode_t* curr = iter->st->buckets[target_bucket]; - c_SCHashNode_t* next_valid_node = NULL; - - while (curr != NULL) { - if (iter->st->key_compar(iter->last_returned, c_SCHash_NodeKey(curr)) == 0) { - // Capture the next element pointer in the link chain before unlinking - next_valid_node = curr->next; - - // Perform the structural delete - *link = curr->next; - C_FREE(curr); - iter->st->size--; - break; - } - link = &curr->next; - curr = curr->next; - } - - // Reset the state machine tracking register to prevent double deletion - iter->last_returned = NULL; - - // --- EXPLICIT FORWARD SYNCHRONIZATION --- - // Update the iterator's position to point to the correct next element - if (next_valid_node != NULL) { - iter->curr_node = next_valid_node; - iter->curr_bucket = target_bucket; - } else { - // If the deletion emptied out the remainder of this bucket chain, - // search forward through subsequent buckets to find the next valid node. - iter->curr_bucket = target_bucket; - c_SCHashIter_AdvanceToNextValid(iter); - } - - return C_ERR_OK; -} - - - diff --git a/Search/c_SeparateChainingHashST.h b/Search/c_SeparateChainingHashST.h deleted file mode 100644 index bd39ba0..0000000 --- a/Search/c_SeparateChainingHashST.h +++ /dev/null @@ -1,78 +0,0 @@ -#ifndef INCLUDED_C_SEPARATECHAININGHASHST_H -#define INCLUDED_C_SEPARATECHAININGHASHST_H - -#ifndef INCLUDED_C_TYPES_H -#include -#endif /*INCLUDED_C_TYPES_H*/ - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -// Forward declaration of internal node structure -typedef struct c_SCHashNode { - struct c_SCHashNode* next; // Pointer to next node in the chain - // Payload layout: key block followed immediately by the value block in memory -} c_SCHashNode_t; - -// Separate Chaining Hash ST Context Structure -typedef struct { - c_SCHashNode_t** buckets; // Array of linked list head pointers - c_size_t num_buckets; // Total number of buckets (M) - c_size_t key_size; // Size of each key in bytes - c_size_t val_size; // Size of each value in bytes - c_size_t size; // Total number of key-value pairs (N) - - uint32_t (*hash_fn)(const void* key, c_size_t key_size); // Custom hash function - int (*key_compar)(const void*, const void*); // Key comparison rule pointer -} c_SeparateChainingHashST_t; - -typedef struct { - c_SeparateChainingHashST_t* st; // Reference link to backing hash table container - c_size_t curr_bucket; // Active index tracking variable inside the flat array - c_SCHashNode_t* curr_node; // Head cursor tracking elements inside linked list buckets - void* last_returned; // Pointer caching the key payload returned by Next() -} c_SeparateChainingHashSTKeyIter_t; - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -// --- Internal Helper Accessors --- -C_STATIC_FORCE_INLINE -void* c_SCHash_NodeKey(c_SCHashNode_t* node) { - if (node == NULL) return NULL; - return (void*)((char*)node + sizeof(c_SCHashNode_t)); -} - -C_STATIC_FORCE_INLINE -void* c_SCHash_NodeVal(c_SCHashNode_t* node, c_size_t key_size) { - if (!node) return NULL; - return (void*)((char*)node + sizeof(c_SCHashNode_t) + key_size); -} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -c_err_t c_SeparateChainingHashST_Init(c_SeparateChainingHashST_t* st, c_size_t num_buckets, - c_size_t key_size, c_size_t val_size, - uint32_t (*hash_fn)(const void*, c_size_t), - int (*key_compar)(const void*, const void*)); - -void c_SeparateChainingHashST_Destroy(c_SeparateChainingHashST_t* st); - -c_bool_t c_SeparateChainingHashST_Contains(const c_SeparateChainingHashST_t* st, const void* key); -c_err_t c_SeparateChainingHashST_Put(c_SeparateChainingHashST_t* st, const void* key, const void* val); -void* c_SeparateChainingHashST_Get(const c_SeparateChainingHashST_t* st, const void* key); -c_err_t c_SeparateChainingHashST_Delete(c_SeparateChainingHashST_t* st, const void* key); - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -c_err_t c_SeparateChainingHashSTKeyIter_Init(c_SeparateChainingHashSTKeyIter_t* iter, - const c_SeparateChainingHashST_t* st); -void c_SeparateChainingHashSTKeyIter_Destroy(c_SeparateChainingHashSTKeyIter_t* iter); -c_bool_t c_SeparateChainingHashSTKeyIter_HasNext(const c_SeparateChainingHashSTKeyIter_t* iter); -void* c_SeparateChainingHashSTKeyIter_Get(c_SeparateChainingHashSTKeyIter_t* iter); -void* c_SeparateChainingHashSTKeyIter_Next(c_SeparateChainingHashSTKeyIter_t* iter); -c_err_t c_SeparateChainingHashSTKeyIter_Remove(c_SeparateChainingHashSTKeyIter_t* iter) ; - -#endif /*INCLUDED_C_SEPARATECHAININGHASHST_H*/ diff --git a/Search/c_TST.c b/Search/c_TST.c deleted file mode 100644 index 09c9609..0000000 --- a/Search/c_TST.c +++ /dev/null @@ -1,312 +0,0 @@ -#include -#include -#include -#include - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - - -/* Internal constructor helper to build an isolated TST node capsule */ -static c_TSTNode_t* c_TSTNode_Create(char c) { - c_TSTNode_t* node = (c_TSTNode_t*)C_CALLOC(1, sizeof(c_TSTNode_t)); - if (node) { - node->c = c; - } - return node; -} - -/* Internal destructor helper to clear TST nodes non-recursively using an explicit heap stack */ -static void c_TSTNode_DestroyRecursive(c_TSTNode_t* root) { - if (!root) return; - - c_ArrayStack_t node_stack; - c_ArrayStack_Init(&node_stack, sizeof(c_TSTNode_t*), 256); - c_ArrayStack_Push(&node_stack, &root); - - while (!c_ArrayStack_IsEmpty(&node_stack)) { - c_TSTNode_t* curr = 0; - c_ArrayStack_Pop(&node_stack, &curr); - c_bool_t advanced = C_FALSE; - - // Push children onto the cleanup stack frame and clear links to avoid cycles - if (curr->left) { - c_ArrayStack_Push(&node_stack, &curr->left); - curr->left = NULL; - advanced = C_TRUE; - } else if (curr->mid) { - c_ArrayStack_Push(&node_stack, &curr->mid); - curr->mid = NULL; - advanced = C_TRUE; - } else if (curr->right) { - c_ArrayStack_Push(&node_stack, &curr->right); - curr->right = NULL; - advanced = C_TRUE; - } - - if (advanced == C_FALSE) { - C_FREE(curr); - } - } - - c_ArrayStack_Destroy(&node_stack); -} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - - -c_err_t c_TST_Init(c_TST_t* self) { - if (!self) return C_ERR_PARAM; - self->root = NULL; - self->size = 0; - return C_ERR_OK; -} - -void c_TST_Destroy(c_TST_t* self) { - if (!self) return; - c_TSTNode_DestroyRecursive(self->root); - self->root = NULL; - self->size = 0; -} - -/* Internal recursive worker to support clean TST node creation and value insertions */ -static c_TSTNode_t* c_TST_PutWorker(c_TSTNode_t* x, const char* key, c_size_t d, void* value, c_bool_t* is_new, c_err_t* err) { - char c = key[d]; - if (!x) { - x = c_TSTNode_Create(c); - if (!x) { - *err = C_ERR_NOMEM; - return NULL; - } - } - - if (c < x->c) { - x->left = c_TST_PutWorker(x->left, key, d, value, is_new, err); - } else if (c > x->c) { - x->right = c_TST_PutWorker(x->right, key, d, value, is_new, err); - } else if (d < strlen(key) - 1) { - x->mid = c_TST_PutWorker(x->mid, key, d + 1, value, is_new, err); - } else { - if (x->value == NULL) { - *is_new = C_TRUE; - } - x->value = value; - } - return x; -} - -c_err_t c_TST_Put(c_TST_t* self, const char* key, void* value) { - if (!self || !key || strlen(key) == 0 || !value) return C_ERR_PARAM; - - c_bool_t is_new = C_FALSE; - c_err_t err = C_ERR_OK; - self->root = c_TST_PutWorker(self->root, key, 0, value, &is_new, &err); - - if (err == C_ERR_OK && is_new == C_TRUE) { - self->size++; - } - return err; -} - -void* c_TST_Get(c_TST_t* self, const char* key) { - if (!self || !key || strlen(key) == 0 || !self->root) return NULL; - - c_TSTNode_t* curr = self->root; - c_size_t d = 0; - c_size_t len = strlen(key); - - while (curr) { - char c = key[d]; - if (c < curr->c) { - curr = curr->left; - } else if (c > curr->c) { - curr = curr->right; - } else if (d < len - 1) { - curr = curr->mid; - d++; - } else { - return curr->value; - } - } - return NULL; -} - -c_bool_t c_TST_Contains(c_TST_t* self, const char* key) { - return (c_TST_Get(self, key) != NULL) ? C_TRUE : C_FALSE; -} - -/* Internal prefix traversal worker */ -static void c_TST_CollectWorker(c_TSTNode_t* x, c_StringBuffer_t* sb, c_size_t depth, c_StringList* result) { - if (!x) return; - - // Explore smaller alphabetical character trees leftward (keeps current string prefix length unchanged) - c_TST_CollectWorker(x->left, sb, depth, result); - - // Append the matching node character token directly to the string builder - c_StringBuffer_Append(sb, &(x->c), 1); - if (x->value != NULL) { - c_StringList_Append(result, sb->buffer); - } - - // Continue crawling down matching children on the middle branch - c_TST_CollectWorker(x->mid, sb, depth + 1, result); - - // Backtrack step: restore parent character layout configuration length boundaries - c_StringBuffer_SetLength(sb, depth); - - // Explore larger alphabetical character trees rightward - c_TST_CollectWorker(x->right, sb, depth, result); -} - -c_err_t c_TST_KeysWithPrefix(c_TST_t* self, const char* prefix, c_StringList* result) { - if (!self || !prefix || !result || !self->root) return C_ERR_PARAM; - - c_TSTNode_t* curr = self->root; - c_size_t d = 0; - c_size_t len = strlen(prefix); - - // Navigate to the end node matching the prefix string character rules - while (curr) { - char c = prefix[d]; - if (c < curr->c) { - curr = curr->left; - } else if (c > curr->c) { - curr = curr->right; - } else if (d < len - 1) { - curr = curr->mid; - d++; - } else { - break; // Prefix matched up to curr node boundaries - } - } - - if (!curr) return C_ERR_OK; // Prefix not found safely yields 0 matches - - c_StringBuffer_t sb; - if (c_StringBuffer_Init(&sb, 256) != C_ERR_OK) return C_ERR_NOMEM; - - // Seed our builder with the matching prefix handle string tokens - c_StringBuffer_Append(&sb, prefix, len); - - // If the prefix node boundary itself holds an active value, record it first - if (curr->value != NULL) { - c_StringList_Append(result, prefix); - } - - // Crawl down the middle branch to extract all matching multi-character children variations - c_TST_CollectWorker(curr->mid, &sb, len, result); - - c_StringBuffer_Destroy(&sb); - return C_ERR_OK; -} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -/* Internal recursive wildcard collector worker */ -static void c_TST_MatchWorker(c_TSTNode_t* x, c_StringBuffer_t* sb, const char* pattern, c_size_t d, c_StringList* result) { - if (!x) return; - - char c = pattern[d]; - c_size_t len = strlen(pattern); - - // Explore smaller characters leftward if the pattern permits or if it's a wildcard - if (c == '.' || c < x->c) { - c_TST_MatchWorker(x->left, sb, pattern, d, result); - } - - // Process current node character matching boundaries - if (c == '.' || c == x->c) { - // Append the current split character token onto your string buffer builder stack - c_StringBuffer_Append(sb, &(x->c), 1); - - // Terminal case: If we have reached the final character index of the pattern layout string - if (d == len - 1) { - if (x->value != NULL) { - c_StringList_Append(result, sb->buffer); - } - } else { - // Advance deeper down the middle branch to explore matching multi-character continuations - c_TST_MatchWorker(x->mid, sb, pattern, d + 1, result); - } - - // Backtracking unwinding step: reset logical buffer length configuration framework - c_StringBuffer_SetLength(sb, d); - } - - // Explore larger characters rightward if the pattern permits or if it's a wildcard - if (c == '.' || c > x->c) { - c_TST_MatchWorker(x->right, sb, pattern, d, result); - } -} - -/** - * Gather all keys currently matching a specific wildcard pattern string inside the TST - */ -c_err_t c_TST_KeysThatMatch(c_TST_t* self, const char* pattern, c_StringList* result) { - if (!self || !pattern || strlen(pattern) == 0 || !result || !self->root) { - return C_ERR_PARAM; - } - - c_StringBuffer_t sb; - if (c_StringBuffer_Init(&sb, 256) != C_ERR_OK) { - return C_ERR_NOMEM; - } - - // Start crawling the ternary search tree using our shared string buffer accumulator - c_TST_MatchWorker(self->root, &sb, pattern, 0, result); - - c_StringBuffer_Destroy(&sb); - return C_ERR_OK; -} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -char* c_TST_LongestPrefixOf(c_TST_t* self, const char* query) { - if (!self || !query || !self->root) { - return NULL; - } - - c_TSTNode_t* curr = self->root; - c_size_t query_len = strlen(query); - c_size_t longest_match_len = 0; - c_bool_t match_found = C_FALSE; - c_size_t d = 0; - - // Run an iterative O(L) scan across TST split character tokens - while (curr && d < query_len) { - char c = query[d]; - - if (c < curr->c) { - curr = curr->left; // Step left: current character is smaller - } else if (c > curr->c) { - curr = curr->right; // Step right: current character is larger - } else { - // Character matches curr->c exactly! Check if this marks a complete key - if (curr->value != NULL) { - longest_match_len = d + 1; - match_found = C_TRUE; - } - curr = curr->mid; // Advance down the middle branch - d++; // Advance to next character in query string - } - } - - // Allocate an isolated heap buffer to hold the output string copy - c_size_t output_bytes = match_found ? (longest_match_len + 1) : 1; - char* result_str = (char*)C_ALLOC(output_bytes); - if (!result_str) { - return NULL; - } - - if (match_found == C_TRUE) { - memcpy(result_str, query, longest_match_len); - result_str[longest_match_len] = '\0'; - } else { - result_str[0] = '\0'; // Return a clean empty string if no prefix matches - } - - return result_str; -} \ No newline at end of file diff --git a/Search/c_TST.h b/Search/c_TST.h deleted file mode 100644 index 8b2e707..0000000 --- a/Search/c_TST.h +++ /dev/null @@ -1,77 +0,0 @@ -#ifndef INCLUDED_C_TST_H -#define INCLUDED_C_TST_H - -#ifndef INCLUDED_C_TYPES_H -#include -#endif /*INCLUDED_C_TYPES_H*/ - -#ifndef INCLUDED_C_STRINGLIST_H -#include -#endif /*INCLUDED_C_STRINGLIST_H*/ - - - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -typedef struct c_TSTNode { - char c; // The single character split character token for this node - void* value; // Generic client value pointer associated with a complete key string - struct c_TSTNode* left; // Left branch pointer: character is smaller (<) - struct c_TSTNode* mid; // Middle branch pointer: character matches (==) - struct c_TSTNode* right; // Right branch pointer: character is larger (>) -} c_TSTNode_t; - -typedef struct { - c_TSTNode_t* root; // Reference root pointer of the TST structure capsule - c_size_t size; // Total count of distinct key-value pairs stored inside the TST -} c_TST_t; - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -c_err_t c_TST_Init(c_TST_t* self); -void c_TST_Destroy(c_TST_t* self); - -/** - * Insert or update a string key mapped to a generic value pointer inside the table - */ -c_err_t c_TST_Put(c_TST_t* self, const char* key, void* value); - -/** - * Retrieve the generic client value pointer mapped to a string key - * @return The stored value address, or NULL if the key does not exist - */ -void* c_TST_Get(c_TST_t* self, const char* key); - -/** - * Check if the TST contains a matching entry for a specific string key - */ -c_bool_t c_TST_Contains(c_TST_t* self, const char* key); - -/** - * Gather all keys currently matching a specific character prefix layout string - * @param result An initialized c_StringList container to append the extracted string records - */ -c_err_t c_TST_KeysWithPrefix(c_TST_t* self, const char* prefix, c_StringList* result); - -/** - * Gather all keys currently matching a specific wildcard pattern string (where '.' matches any character) - * @param pattern String pattern containing characters and '.' wildcards - * @param result An initialized c_StringList container to append the extracted string records - */ -c_err_t c_TST_KeysThatMatch(c_TST_t* self, const char* pattern, c_StringList* result); - -/** - * Find the longest key registered in the TST that is a prefix of the query string. - * For example, if "a", "app", and "apple" are in the TST, LongestPrefixOf("applepie") returns "apple". - * - * @param query The source text string to analyze - * @return - * - A dynamically allocated copy of the longest matching prefix string (managed via C_ALLOC, caller frees) - * - An empty string copy "" if no prefix is matched - * - NULL if system parameters are invalid - */ -char* c_TST_LongestPrefixOf(c_TST_t* self, const char* query); - -#endif /*INCLUDED_C_TST_H*/ diff --git a/Search/c_TreeMap.c b/Search/c_TreeMap.c deleted file mode 100644 index fc3e8b6..0000000 --- a/Search/c_TreeMap.c +++ /dev/null @@ -1,365 +0,0 @@ -#include -#include - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -// --- Structural Balancing Primitives --- - -C_STATIC_FORCE_INLINE -c_TMNode_t* c_TreeMap_RotateLeft(c_TMNode_t* h) { - c_TMNode_t* x = h->right; - h->right = x->left; - x->left = h; - x->color = h->color; - h->color = C_TM_RED; - return x; -} - -C_STATIC_FORCE_INLINE -c_TMNode_t* c_TreeMap_RotateRight(c_TMNode_t* h) { - c_TMNode_t* x = h->left; - h->left = x->right; - x->right = h; - x->color = h->color; - h->color = C_TM_RED; - return x; -} - -C_STATIC_FORCE_INLINE -void c_TreeMap_FlipColors(c_TMNode_t* h) { - h->color = !h->color; - if (h->left) h->left->color = !h->left->color; - if (h->right) h->right->color = !h->right->color; -} - -C_STATIC_FORCE_INLINE -c_TMNode_t* c_TreeMap_MoveRedLeft(c_TMNode_t* h) { - c_TreeMap_FlipColors(h); - if (c_TreeMap_IsRed(h->right->left)) { - h->right = c_TreeMap_RotateRight(h->right); - h = c_TreeMap_RotateLeft(h); - c_TreeMap_FlipColors(h); - } - return h; -} - -C_STATIC_FORCE_INLINE -c_TMNode_t* c_TreeMap_MoveRedRight(c_TMNode_t* h) { - c_TreeMap_FlipColors(h); - if (c_TreeMap_IsRed(h->left->left)) { - h = c_TreeMap_RotateRight(h); - c_TreeMap_FlipColors(h); - } - return h; -} - -C_STATIC_FORCE_INLINE -c_TMNode_t* c_TreeMap_Balance(c_TMNode_t* h) { - if (c_TreeMap_IsRed(h->right) && !c_TreeMap_IsRed(h->left)) h = c_TreeMap_RotateLeft(h); - if (c_TreeMap_IsRed(h->left) && c_TreeMap_IsRed(h->left->left)) h = c_TreeMap_RotateRight(h); - if (c_TreeMap_IsRed(h->left) && c_TreeMap_IsRed(h->right)) c_TreeMap_FlipColors(h); - return h; -} - -C_STATIC_FORCE_INLINE -c_TMNode_t* c_TreeMap_CreateNode(const void* key, const void* val, c_size_t ks, c_size_t vs) { - c_TMNode_t* node = (c_TMNode_t*)C_ALLOC(sizeof(c_TMNode_t) + ks + vs); - if (node == NULL) return NULL; - node->left = NULL; - node->right = NULL; - node->color = C_TM_RED; - memcpy(c_TreeMap_NodeKey(node), key, ks); - memcpy(c_TreeMap_NodeVal(node, ks), val, vs); - return node; -} - -static void c_TreeMap_DestroyNodes(c_TMNode_t* node) { - if (node == NULL) return; - c_TreeMap_DestroyNodes(node->left); - c_TreeMap_DestroyNodes(node->right); - C_FREE(node); -} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -c_err_t c_TreeMap_Init(c_TreeMap_t* map, c_size_t key_size, c_size_t val_size, - int (*compar)(const void*, const void*)) { - if (map == NULL || key_size == 0 || val_size == 0 || compar == NULL) return C_ERR_PARAM; - map->root = NULL; - map->key_size = key_size; - map->val_size = val_size; - map->size = 0; - map->compar = compar; - return C_ERR_OK; -} - -void c_TreeMap_Destroy(c_TreeMap_t* map) { - if (map) { - c_TreeMap_DestroyNodes(map->root); - map->root = NULL; - map->size = 0; - } -} - -c_bool_t c_TreeMap_Contains(const c_TreeMap_t* map, const void* key) { - if (map == NULL || key == NULL) return C_FALSE; - c_TMNode_t* curr = map->root; - while (curr != NULL) { - int cmp = map->compar(key, c_TreeMap_NodeKey(curr)); - if (cmp == 0) return C_TRUE; - curr = (cmp < 0) ? curr->left : curr->right; - } - return C_FALSE; -} - -void* c_TreeMap_Get(const c_TreeMap_t* map, const void* key) { - if (map == NULL || key == NULL) return NULL; - c_TMNode_t* curr = map->root; - while (curr != NULL) { - int cmp = map->compar(key, c_TreeMap_NodeKey(curr)); - if (cmp == 0) return c_TreeMap_NodeVal(curr, map->key_size); - curr = (cmp < 0) ? curr->left : curr->right; - } - return NULL; -} - -static c_TMNode_t* c_TreeMap_PutInternal(c_TreeMap_t* map, c_TMNode_t* h, - const void* key, const void* val, c_err_t* err) { - if (h == NULL) { - c_TMNode_t* node = c_TreeMap_CreateNode(key, val, map->key_size, map->val_size); - if (node == NULL) *err = C_ERR_NOMEM; - else map->size++; - return node; - } - - int cmp = map->compar(key, c_TreeMap_NodeKey(h)); - if (cmp < 0) h->left = c_TreeMap_PutInternal(map, h->left, key, val, err); - else if (cmp > 0) h->right = c_TreeMap_PutInternal(map, h->right, key, val, err); - else memcpy(c_TreeMap_NodeVal(h, map->key_size), val, map->val_size); - - return c_TreeMap_Balance(h); -} - -c_err_t c_TreeMap_Put(c_TreeMap_t* map, const void* key, const void* val) { - if (map == NULL || key == NULL || val == NULL) return C_ERR_PARAM; - c_err_t err = C_ERR_OK; - map->root = c_TreeMap_PutInternal(map, map->root, key, val, &err); - if (map->root) map->root->color = C_TM_BLACK; - return err; -} - -static c_TMNode_t* c_TreeMap_DeleteMin(c_TreeMap_t* map, c_TMNode_t* h, c_TMNode_t** out_min) { - if (h->left == NULL) { - *out_min = h; - return NULL; - } - if (!c_TreeMap_IsRed(h->left) && !c_TreeMap_IsRed(h->left->left)) { - h = c_TreeMap_MoveRedLeft(h); - } - h->left = c_TreeMap_DeleteMin(map, h->left, out_min); - return c_TreeMap_Balance(h); -} - -static c_TMNode_t* c_TreeMap_RemoveInternal(c_TreeMap_t* map, c_TMNode_t* h, const void* key, c_err_t* err) { - if (map->compar(key, c_TreeMap_NodeKey(h)) < 0) { - if (h->left == NULL) { *err = C_ERR_FAIL; return h; } - if (!c_TreeMap_IsRed(h->left) && !c_TreeMap_IsRed(h->left->left)) { - h = c_TreeMap_MoveRedLeft(h); - } - h->left = c_TreeMap_RemoveInternal(map, h->left, key, err); - } else { - if (c_TreeMap_IsRed(h->left)) { - h = c_TreeMap_RotateRight(h); - } - if (map->compar(key, c_TreeMap_NodeKey(h)) == 0 && (h->right == NULL)) { - map->size--; - C_FREE(h); - return NULL; - } - if (h->right == NULL) { *err = C_ERR_FAIL; return h; } - if (!c_TreeMap_IsRed(h->right) && !c_TreeMap_IsRed(h->right->left)) { - h = c_TreeMap_MoveRedRight(h); - } - if (map->compar(key, c_TreeMap_NodeKey(h)) == 0) { - c_TMNode_t* successor = NULL; - h->right = c_TreeMap_DeleteMin(map, h->right, &successor); - - successor->left = h->left; - successor->right = h->right; - successor->color = h->color; - - C_FREE(h); - map->size--; - h = successor; - } else { - h->right = c_TreeMap_RemoveInternal(map, h->right, key, err); - } - } - return c_TreeMap_Balance(h); -} - -c_err_t c_TreeMap_Remove(c_TreeMap_t* map, const void* key) { - if (map == NULL || key == NULL) return C_ERR_PARAM; - if (map->root == NULL) return C_ERR_NOTFOUND; - - c_err_t err = C_ERR_OK; - if (!c_TreeMap_IsRed(map->root->left) && !c_TreeMap_IsRed(map->root->right)) { - map->root->color = C_TM_RED; - } - - map->root = c_TreeMap_RemoveInternal(map, map->root, key, &err); - if (map->root) map->root->color = C_TM_BLACK; - return err; -} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -/** - * Initialize the TreeMap Key Iterator. - * Performs dynamic heap stack initialization and loads the initial minimum path context. - * - * Time Complexity: O(log n) | Space Complexity: O(log n) heap initialization - */ -c_err_t c_TreeMapKeyIter_Init(c_TreeMapKeyIter_t* iter, const c_TreeMap_t* map) { - if (iter == NULL || map == NULL) return C_ERR_PARAM; - - // Cast away constness to bind to the non-const structural field required for Remove() - iter->map = (c_TreeMap_t*)map; - iter->stack_top = -1; - iter->last_returned = NULL; - - // Safety depth boundary limit (Handles worst-case height for massive LLRB trees) - iter->max_depth = 64; - iter->stack = (c_TMNode_t**)C_ALLOC(iter->max_depth * sizeof(c_TMNode_t*)); - if (iter->stack == NULL) return C_ERR_NOMEM; - - // Load initial lookup vector matching the minimum starting key node context - c_TMNode_t* curr = map->root; - while (curr != NULL && iter->stack_top < (long long)iter->max_depth - 1) { - iter->stack[++iter->stack_top] = curr; - curr = curr->left; - } - - return C_ERR_OK; -} - -/** - * Clean up allocations within the context wrapper safely. - * Resets tracking registers to guard against dangling usage. - */ -void c_TreeMapKeyIter_Destroy(c_TreeMapKeyIter_t* iter) { - if (iter) { - C_FREE(iter->stack); - iter->stack_top = -1; - iter->max_depth = 0; - iter->last_returned = NULL; - iter->map = NULL; - } -} - -/** - * Evaluates whether any keys remain unread inside the look-ahead pipeline. - */ -c_bool_t c_TreeMapKeyIter_HasNext(const c_TreeMapKeyIter_t* iter) { - if (iter == NULL || iter->stack == NULL) return C_FALSE; - return iter->stack_top >= 0; -} - -/** - * Retrieve a reference pointer to the key most recently extracted by Next(). - * - * Time Complexity: O(1) constant runtime overhead - */ -void* c_TreeMapKeyIter_Get(c_TreeMapKeyIter_t* iter) { - if (iter == NULL || iter->stack==NULL || iter->stack_top<0) return NULL; - c_TMNode_t* node = iter->stack[iter->stack_top]; - iter->last_returned = c_TreeMap_NodeKey(node); - return iter->last_returned; -} - -/** - * Extracts a pointer to the next consecutive key in sorted order. - * Updates internal path registers to step along the sequence. - */ -void* c_TreeMapKeyIter_Next(c_TreeMapKeyIter_t* iter) { - if (iter == NULL || iter->stack_top < 0 || iter->stack == NULL) return NULL; - - // Pop the current minimal node out of the active stack frame - c_TMNode_t* node = iter->stack[iter->stack_top--]; - iter->last_returned = c_TreeMap_NodeKey(node); - - // If a right subtree exists, loop down its left-most branches - c_TMNode_t* curr = node->right; - while (curr != NULL && iter->stack_top < (long long)iter->max_depth - 1) { - iter->stack[++iter->stack_top] = curr; - curr = curr->left; - } - - return iter->last_returned; -} - -/** - * High-performance companion helper to reconstruct dynamic stack positions - * back down to a specified target key without memory leaks. - */ -static void c_TreeMapKeyIter_RebuildDynamicStack(c_TreeMapKeyIter_t* iter, c_TMNode_t* node, const void* target_key) { - while (node != NULL && iter->stack_top < (long long)iter->max_depth - 1) { - int cmp = iter->map->compar(target_key, c_TreeMap_NodeKey(node)); - if (cmp < 0) { - iter->stack[++iter->stack_top] = node; - node = node->left; - } else if (cmp > 0) { - node = node->right; - } else { - iter->stack[++iter->stack_top] = node; - break; - } - } -} - -/** - * Stateful Removal Execution Engine. - * Safely handles LLRB tree balancing modifications and heals stack tracking frames in O(log n). - */ -c_err_t c_TreeMapKeyIter_Remove(c_TreeMapKeyIter_t* iter) { - if (iter == NULL || iter->map == NULL || iter->stack == NULL) return C_ERR_PARAM; - if (iter->last_returned == NULL) return C_ERR_FAIL; // Guard against double-deletion/unstarted cursor - - c_bool_t has_next = (iter->stack_top >= 0) ? C_TRUE : C_FALSE; - c_size_t ks = iter->map->key_size; - - // Use a stack-allocated cache buffer to avoid dynamic allocation penalties during deletion hotpaths - #define TRANS_LIMIT 64 - char backup_buffer[TRANS_LIMIT]; - void* next_key_backup = NULL; - - if (has_next) { - next_key_backup = (ks <= TRANS_LIMIT) ? (void*)backup_buffer : C_ALLOC(ks); - if (next_key_backup == NULL) return C_ERR_NOMEM; - memcpy(next_key_backup, c_TreeMap_NodeKey(iter->stack[iter->stack_top]), ks); - } - - // Perform the actual LLRB tree element removal balancing routine - c_err_t err = c_TreeMap_Remove(iter->map, iter->last_returned); - if (err != C_ERR_OK) { - if (has_next && ks > TRANS_LIMIT) C_FREE(next_key_backup); - return err; - } - - iter->last_returned = NULL; // Clear tracking state to prevent invalid double-delete calls - iter->stack_top = -1; // Flush old stack frames corrupted by tree rotations - - // Rebuild the path map using the new root context down to our tracked lookahead key - if (has_next && iter->map->root != NULL) { - c_TreeMapKeyIter_RebuildDynamicStack(iter, iter->map->root, next_key_backup); - if (ks > TRANS_LIMIT) C_FREE(next_key_backup); - } - - #undef TRANS_LIMIT - return C_ERR_OK; -} - - diff --git a/Search/c_TreeMap.h b/Search/c_TreeMap.h deleted file mode 100644 index 0dbf7d3..0000000 --- a/Search/c_TreeMap.h +++ /dev/null @@ -1,82 +0,0 @@ -#ifndef INCLUDED_C_TREEMAP_H -#define INCLUDED_C_TREEMAP_H - -#ifndef INCLUDED_C_TYPES_H -#include -#endif /*INCLUDED_C_TYPES_H*/ - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -// Link Color Definitions -typedef enum { - C_TM_BLACK = 0, - C_TM_RED = 1 -} c_TMColor_t; - -// TreeMap Inlined Node Layout Configuration -typedef struct c_TMNode { - struct c_TMNode* left; - struct c_TMNode* right; - c_TMColor_t color; - // Payload layout: key block followed immediately by the value block in memory -} c_TMNode_t; - -// TreeMap Context Structure -typedef struct { - c_TMNode_t* root; - c_size_t key_size; - c_size_t val_size; - c_size_t size; - int (*compar)(const void*, const void*); -} c_TreeMap_t; - -typedef struct { - c_TreeMap_t* map; // Non-const to allow operations on the backing collection - c_TMNode_t** stack; // Dynamic lookup-vector tracking block - long long stack_top; // Explicit tracking index pointer limits - c_size_t max_depth; // Safety boundary memory cushion - void* last_returned; // Pointer tracking the key returned by the most recent Next() call -} c_TreeMapKeyIter_t; - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -// --- Internal Helper Accessors --- -C_STATIC_FORCE_INLINE void* c_TreeMap_NodeKey(c_TMNode_t* node) { - return (void*)((char*)node + sizeof(c_TMNode_t)); -} - -C_STATIC_FORCE_INLINE void* c_TreeMap_NodeVal(c_TMNode_t* node, c_size_t key_size) { - return (void*)((char*)node + sizeof(c_TMNode_t) + key_size); -} - -C_STATIC_FORCE_INLINE c_bool_t c_TreeMap_IsRed(c_TMNode_t* node) { - if (node == NULL) return C_FALSE; - return node->color == C_TM_RED; -} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -c_err_t c_TreeMap_Init(c_TreeMap_t* map, c_size_t key_size, c_size_t val_size, - int (*compar)(const void*, const void*)); -void c_TreeMap_Destroy(c_TreeMap_t* map); - -c_bool_t c_TreeMap_Contains(const c_TreeMap_t* map, const void* key); -void* c_TreeMap_Get(const c_TreeMap_t* map, const void* key); -c_err_t c_TreeMap_Put(c_TreeMap_t* map, const void* key, const void* val); -c_err_t c_TreeMap_Remove(c_TreeMap_t* map, const void* key); - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -c_err_t c_TreeMapKeyIter_Init(c_TreeMapKeyIter_t* iter, const c_TreeMap_t* map); -void c_TreeMapKeyIter_Destroy(c_TreeMapKeyIter_t* iter); -c_bool_t c_TreeMapKeyIter_HasNext(const c_TreeMapKeyIter_t* iter); -void* c_TreeMapKeyIter_Get(c_TreeMapKeyIter_t* iter); -void* c_TreeMapKeyIter_Next(c_TreeMapKeyIter_t* iter); -c_err_t c_TreeMapKeyIter_Remove(c_TreeMapKeyIter_t* iter); - - -#endif /*INCLUDED_C_TREEMAP_H*/ diff --git a/Search/c_TreeSet.c b/Search/c_TreeSet.c deleted file mode 100644 index 767384f..0000000 --- a/Search/c_TreeSet.c +++ /dev/null @@ -1,347 +0,0 @@ -#include -#include - -// --- Structural Balancing Primitives --- - -C_STATIC_FORCE_INLINE -c_TSNode_t* c_TreeSet_RotateLeft(c_TSNode_t* h) { - c_TSNode_t* x = h->right; - h->right = x->left; - x->left = h; - x->color = h->color; - h->color = C_TS_RED; - return x; -} - -C_STATIC_FORCE_INLINE -c_TSNode_t* c_TreeSet_RotateRight(c_TSNode_t* h) { - c_TSNode_t* x = h->left; - h->left = x->right; - x->right = h; - x->color = h->color; - h->color = C_TS_RED; - return x; -} - -C_STATIC_FORCE_INLINE -void c_TreeSet_FlipColors(c_TSNode_t* h) { - h->color = !h->color; - if (h->left) h->left->color = !h->left->color; - if (h->right) h->right->color = !h->right->color; -} - -C_STATIC_FORCE_INLINE -c_TSNode_t* c_TreeSet_MoveRedLeft(c_TSNode_t* h) { - c_TreeSet_FlipColors(h); - if (c_TreeSet_IsRed(h->right->left)) { - h->right = c_TreeSet_RotateRight(h->right); - h = c_TreeSet_RotateLeft(h); - c_TreeSet_FlipColors(h); - } - return h; -} - -C_STATIC_FORCE_INLINE -c_TSNode_t* c_TreeSet_MoveRedRight(c_TSNode_t* h) { - c_TreeSet_FlipColors(h); - if (c_TreeSet_IsRed(h->left->left)) { - h = c_TreeSet_RotateRight(h); - c_TreeSet_FlipColors(h); - } - return h; -} - -C_STATIC_FORCE_INLINE -c_TSNode_t* c_TreeSet_Balance(c_TSNode_t* h) { - if (c_TreeSet_IsRed(h->right) && !c_TreeSet_IsRed(h->left)) h = c_TreeSet_RotateLeft(h); - if (c_TreeSet_IsRed(h->left) && c_TreeSet_IsRed(h->left->left)) h = c_TreeSet_RotateRight(h); - if (c_TreeSet_IsRed(h->left) && c_TreeSet_IsRed(h->right)) c_TreeSet_FlipColors(h); - return h; -} - -C_STATIC_FORCE_INLINE -c_TSNode_t* c_TreeSet_CreateNode(const void* element, c_size_t es) { - c_TSNode_t* node = (c_TSNode_t*)C_ALLOC(sizeof(c_TSNode_t) + es); - if (node == NULL) return NULL; - node->left = NULL; - node->right = NULL; - node->color = C_TS_RED; - memcpy(c_TreeSet_NodeKey(node), element, es); - return node; -} - -static void c_TreeSet_DestroyNodes(c_TSNode_t* node) { - if (node == NULL) return; - c_TreeSet_DestroyNodes(node->left); - c_TreeSet_DestroyNodes(node->right); - C_FREE(node); -} - - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -c_err_t c_TreeSet_Init(c_TreeSet_t* set, c_size_t element_size, int (*compar)(const void*, const void*)) { - if (set == NULL || element_size == 0 || compar == NULL) return C_ERR_PARAM; - set->root = NULL; - set->element_size = element_size; - set->size = 0; - set->compar = compar; - - return C_ERR_OK; -} - -void c_TreeSet_Destroy(c_TreeSet_t* set) { - if (set) { - c_TreeSet_DestroyNodes(set->root); - set->root = NULL; - set->size = 0; - } -} - -c_bool_t c_TreeSet_Contains(const c_TreeSet_t* set, const void* element) { - if (set == NULL || element == NULL) return C_FALSE; - c_TSNode_t* curr = set->root; - while (curr != NULL) { - int cmp = set->compar(element, c_TreeSet_NodeKey(curr)); - if (cmp == 0) return C_TRUE; - curr = (cmp < 0) ? curr->left : curr->right; - } - return C_FALSE; -} - -static c_TSNode_t* c_TreeSet_AddInternal(c_TreeSet_t* set, c_TSNode_t* h, const void* element, c_err_t* err) { - if (h == NULL) { - c_TSNode_t* node = c_TreeSet_CreateNode(element, set->element_size); - if (node == NULL) *err = C_ERR_NOMEM; - else set->size++; - return node; - } - - int cmp = set->compar(element, c_TreeSet_NodeKey(h)); - if (cmp < 0) h->left = c_TreeSet_AddInternal(set, h->left, element, err); - else if (cmp > 0) h->right = c_TreeSet_AddInternal(set, h->right, element, err); - else *err = C_ERR_ALREADY_EXISTS; // Set constraint violation: duplicates forbidden - - return c_TreeSet_Balance(h); -} - -c_err_t c_TreeSet_Add(c_TreeSet_t* set, const void* element) { - if (set == NULL || element == NULL) return C_ERR_PARAM; - c_err_t err = C_ERR_OK; - set->root = c_TreeSet_AddInternal(set, set->root, element, &err); - if (set->root) set->root->color = C_TS_BLACK; - return err; -} - -static c_TSNode_t* c_TreeSet_DeleteMin(c_TreeSet_t* set, c_TSNode_t* h, c_TSNode_t** out_min) { - if (h->left == NULL) { - *out_min = h; - return NULL; - } - if (!c_TreeSet_IsRed(h->left) && !c_TreeSet_IsRed(h->left->left)) { - h = c_TreeSet_MoveRedLeft(h); - } - h->left = c_TreeSet_DeleteMin(set, h->left, out_min); - return c_TreeSet_Balance(h); -} - -static c_TSNode_t* c_TreeSet_RemoveInternal(c_TreeSet_t* set, c_TSNode_t* h, const void* element, c_err_t* err) { - if (set->compar(element, c_TreeSet_NodeKey(h)) < 0) { - if (h->left == NULL) { *err = C_ERR_FAIL; return h; } - if (!c_TreeSet_IsRed(h->left) && !c_TreeSet_IsRed(h->left->left)) { - h = c_TreeSet_MoveRedLeft(h); - } - h->left = c_TreeSet_RemoveInternal(set, h->left, element, err); - } else { - if (c_TreeSet_IsRed(h->left)) { - h = c_TreeSet_RotateRight(h); - } - if (set->compar(element, c_TreeSet_NodeKey(h)) == 0 && (h->right == NULL)) { - set->size--; - C_FREE(h); - return NULL; - } - if (h->right == NULL) { *err = C_ERR_FAIL; return h; } - if (!c_TreeSet_IsRed(h->right) && !c_TreeSet_IsRed(h->right->left)) { - h = c_TreeSet_MoveRedRight(h); - } - if (set->compar(element, c_TreeSet_NodeKey(h)) == 0) { - c_TSNode_t* successor = NULL; - h->right = c_TreeSet_DeleteMin(set, h->right, &successor); - - successor->left = h->left; - successor->right = h->right; - successor->color = h->color; - - C_FREE(h); - set->size--; - h = successor; - } else { - h->right = c_TreeSet_RemoveInternal(set, h->right, element, err); - } - } - return c_TreeSet_Balance(h); -} - -c_err_t c_TreeSet_Remove(c_TreeSet_t* set, const void* element) { - if (set == NULL || element == NULL) return C_ERR_PARAM; - if (set->root == NULL) return C_ERR_FAIL; - - c_err_t err = C_ERR_OK; - if (!c_TreeSet_IsRed(set->root->left) && !c_TreeSet_IsRed(set->root->right)) { - set->root->color = C_TS_RED; - } - - set->root = c_TreeSet_RemoveInternal(set, set->root, element, &err); - if (set->root) set->root->color = C_TS_BLACK; - return err; -} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ -/** - * High-performance helper to reconstruct dynamic stack positions - * back down to a specified target key without memory leaks. - */ -C_STATIC_FORCE_INLINE -void c_TreeSetIter_RebuildDynamicStack(c_TreeSetIter_t* iter, c_TSNode_t* node, const void* target_key) { - while (node != NULL && iter->stack_top < (long long)iter->max_depth - 1) { - int cmp = iter->set->compar(target_key, c_TreeSet_NodeKey(node)); - if (cmp < 0) { - iter->stack[++iter->stack_top] = node; - node = node->left; - } else if (cmp > 0) { - node = node->right; - } else { - iter->stack[++iter->stack_top] = node; - break; - } - } -} - - -/** - * Initialize the dynamic lookup-vector tracking iterator context. - * Computes initial left-most branching bounds down to the minimal key node. - * - * Time Complexity: O(log n) | Space Complexity: O(log n) heap initialization - */ -c_err_t c_TreeSetIter_Init(c_TreeSetIter_t* iter, const c_TreeSet_t* set) { - if (iter == NULL || set == NULL) return C_ERR_PARAM; - - // Cast away constness to bind to the non-const structural field required for Remove() - iter->set = (c_TreeSet_t*)set; - iter->stack_top = -1; - iter->last_returned = NULL; - - // Safety depth boundary limit (Handles worst-case height for massive LLRB trees) - iter->max_depth = 64; - iter->stack = (c_TSNode_t**)C_ALLOC(iter->max_depth * sizeof(c_TSNode_t*)); - if (iter->stack == NULL) return C_ERR_NOMEM; - - // Load initial lookup vector matching the minimum starting key node context - c_TSNode_t* curr = set->root; - while (curr != NULL && iter->stack_top < (long long)iter->max_depth - 1) { - iter->stack[++iter->stack_top] = curr; - curr = curr->left; - } - - return C_ERR_OK; -} - -/** - * Lifecycle Management: Free allocated structural tracking path arrays. - */ -void c_TreeSetIter_Destroy(c_TreeSetIter_t* iter) { - if (iter) { - C_FREE(iter->stack); - iter->stack_top = -1; - iter->max_depth = 0; - iter->last_returned = NULL; - iter->set = NULL; - } -} - -/** - * Evaluates whether any element remains unread inside the look-ahead pipeline. - */ -c_bool_t c_TreeSetIter_HasNext(const c_TreeSetIter_t* iter) { - if (iter == NULL || iter->stack == NULL) return C_FALSE; - return iter->stack_top >= 0; -} - -/** - * Extracts a pointer to the next consecutive element in sorted order. - * Updates internal path registers to step along the sequence. - * @return void* pointer to the key payload region, or NULL if empty/exhausted. - */ -void* c_TreeSetIter_Next(c_TreeSetIter_t* iter) { - if (iter == NULL || iter->stack_top < 0 || iter->stack == NULL) return NULL; - - // Pop the current minimal node out of the active stack frame - c_TSNode_t* node = iter->stack[iter->stack_top--]; - iter->last_returned = c_TreeSet_NodeKey(node); - - // If a right subtree exists, it holds the next sequence elements. - // Shift tracking focus down over that node's leftmost boundary path. - c_TSNode_t* curr = node->right; - while (curr != NULL && iter->stack_top < (long long)iter->max_depth - 1) { - iter->stack[++iter->stack_top] = curr; - curr = curr->left; - } - - return iter->last_returned; -} - -/** - * Safely removes the element most recently returned by c_TreeSetIter_Next(). - * Re-synchronizes structural lookup maps dynamically post-balance rotation shifts. - * - * Time Complexity: O(log n) | Call Stack: O(1) in-place - * @return C_ERR_OK if successful, or C_ERR_INVALID if invalid iterator state sequence. - */ -c_err_t c_TreeSetIter_Remove(c_TreeSetIter_t* iter) { - if (iter == NULL || iter->set == NULL || iter->stack == NULL) return C_ERR_PARAM; - if (iter->last_returned == NULL) return C_ERR_FAIL; // Guard against double-deletion/unstarted cursor - - c_bool_t has_next = (iter->stack_top >= 0) ? C_TRUE : C_FALSE; - c_size_t es = iter->set->element_size; - - // Use a stack-allocated cache buffer to avoid dynamic allocation penalties during deletion hotpaths -#define TRANS_LIMIT 64 - char backup_buffer[TRANS_LIMIT]; - void* next_key_backup = NULL; - - if (has_next) { - next_key_backup = (es <= TRANS_LIMIT) ? (void*)backup_buffer : C_ALLOC(es); - if (next_key_backup == NULL) return C_ERR_NOMEM; - memcpy(next_key_backup, c_TreeSet_NodeKey(iter->stack[iter->stack_top]), es); - } - - // Perform the actual LLRB tree element removal balancing routine - c_err_t err = c_TreeSet_Remove(iter->set, iter->last_returned); - if (err != C_ERR_OK) { - if (has_next && es > TRANS_LIMIT) C_FREE(next_key_backup); - return err; - } - - iter->last_returned = NULL; // Clear tracking state to prevent invalid double-delete calls - iter->stack_top = -1; // Flush old stack frames corrupted by tree rotations - - // Rebuild the path map using the new root context down to our tracked lookahead key - if (has_next && iter->set->root != NULL) { - c_TreeSetIter_RebuildDynamicStack(iter, iter->set->root, next_key_backup); - if (es > TRANS_LIMIT) C_FREE(next_key_backup); - } - -#undef TRANS_LIMIT - return C_ERR_OK; -} - -void* c_TreeSetIter_Get(c_TreeSetIter_t* iter) { - if (iter == NULL || iter->stack==NULL || iter->stack_top<0) return NULL; - c_TSNode_t* node = iter->stack[iter->stack_top]; - iter->last_returned = c_TreeSet_NodeKey(node); - return iter->last_returned; -} diff --git a/Search/c_TreeSet.h b/Search/c_TreeSet.h deleted file mode 100644 index 4929edd..0000000 --- a/Search/c_TreeSet.h +++ /dev/null @@ -1,80 +0,0 @@ -#ifndef INCLUDED_C_TREESET_H -#define INCLUDED_C_TREESET_H - -#ifndef INCLUDED_C_TYPES_H -#include -#endif /*INCLUDED_C_TYPES_H*/ - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -// Link Color Definitions -typedef enum { - C_TS_BLACK = 0, - C_TS_RED = 1 -} c_TSColor_t; - -// TreeSet Inlined Node Layout Configuration -typedef struct c_TSNode { - struct c_TSNode* left; - struct c_TSNode* right; - c_TSColor_t color; - // Payload layout: element block resides immediately after this structure in memory -} c_TSNode_t; - -// TreeSet Context Structure -typedef struct { - c_TSNode_t* root; - c_size_t element_size; // Size of each unified unique element in bytes - c_size_t size; // Total number of unique nodes inside the set - int (*compar)(const void*, const void*); // Key comparison rule pointer -} c_TreeSet_t; - -typedef struct { - c_TreeSet_t* set; // Modified to non-const to allow operations on the set - c_TSNode_t** stack; - long long stack_top; - c_size_t max_depth; - void* last_returned; // Pointer tracking the key returned by the most recent Next() call -} c_TreeSetIter_t; - - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -// --- Internal Helper Accessors --- -C_STATIC_FORCE_INLINE -void* c_TreeSet_NodeKey(c_TSNode_t* node) { - if (node == NULL) return NULL; - return (void*)((char*)node + sizeof(c_TSNode_t)); -} - -C_STATIC_FORCE_INLINE -c_bool_t c_TreeSet_IsRed(c_TSNode_t* node) { - if (node == NULL) return C_FALSE; - return node->color == C_TS_RED; -} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -c_err_t c_TreeSet_Init(c_TreeSet_t* set, c_size_t element_size, int (*compar)(const void*, const void*)); -void c_TreeSet_Destroy(c_TreeSet_t* set); - -c_bool_t c_TreeSet_Contains(const c_TreeSet_t* set, const void* element); -c_err_t c_TreeSet_Add(c_TreeSet_t* set, const void* element); -c_err_t c_TreeSet_Remove(c_TreeSet_t* set, const void* element); - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -c_err_t c_TreeSetIter_Init(c_TreeSetIter_t* iter, const c_TreeSet_t* set); -void c_TreeSetIter_Destroy(c_TreeSetIter_t* iter); -c_bool_t c_TreeSetIter_HasNext(const c_TreeSetIter_t* iter); -void* c_TreeSetIter_Next(c_TreeSetIter_t* iter); -void* c_TreeSetIter_Get(c_TreeSetIter_t* iter); -c_err_t c_TreeSetIter_Remove(c_TreeSetIter_t* iter); - - - -#endif /*INCLUDED_C_TREESET_H*/ diff --git a/Search/c_Trie.c b/Search/c_Trie.c deleted file mode 100644 index f3ebfe4..0000000 --- a/Search/c_Trie.c +++ /dev/null @@ -1,320 +0,0 @@ -#include -#include -#include -#include "c_StringBuffer.h" - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - - -/* Internal constructor helper to build an isolated trie node capsule */ -C_STATIC_FORCE_INLINE -c_TrieNode_t* c_TrieNode_Create(void) { - c_TrieNode_t* node = (c_TrieNode_t*)C_CALLOC(1, sizeof(c_TrieNode_t)); - return node; // C_CALLOC initializes all children nodes inside next[] to NULL -} - -/* Internal destructor helper to clear trie nodes post-order non-recursively using an explicit stack */ -static void c_TrieNode_DestroyRecursive(c_TrieNode_t* root) { - if (!root) return; - - // Explicit tree-cleanup stack configuration limits space constraints safely - c_ArrayStack_t node_stack; - c_ArrayStack_Init(&node_stack, sizeof(c_TrieNode_t*), 4); - c_ArrayStack_Push(&node_stack, &root); - - while (!c_ArrayStack_IsEmpty(&node_stack)) { - c_TrieNode_t* curr = 0; - c_err_t err = c_ArrayStack_Pop(&node_stack, &curr); - c_bool_t has_children = C_FALSE; - - for (int i = 0; i < C_TRIE_R; i++) { - if (curr->next[i]) { - c_ArrayStack_Push(&node_stack, &curr->next[i]); - curr->next[i] = NULL; // Break loop linkage to track post-order cleanup processing - has_children = C_TRUE; - break; - } - } - - if (has_children == C_FALSE) { - C_FREE(curr); - } - } - c_ArrayStack_Destroy(&node_stack); -} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - - -c_err_t c_Trie_Init(c_Trie_t* self) { - if (!self) return C_ERR_PARAM; - self->root = c_TrieNode_Create(); - self->size = 0; - return self->root ? C_ERR_OK : C_ERR_NOMEM; -} - -void c_Trie_Destroy(c_Trie_t* self) { - if (!self) return; - c_TrieNode_DestroyRecursive(self->root); - self->root = NULL; - self->size = 0; -} - -c_err_t c_Trie_Put(c_Trie_t* self, const char* key, void* value) { - if (!self || !key) return C_ERR_PARAM; - if (!self->root) { - self->root = c_TrieNode_Create(); - if (!self->root) return C_ERR_NOMEM; - } - - c_TrieNode_t* curr = self->root; - c_size_t len = strlen(key); - - for (c_size_t i = 0; i < len; i++) { - unsigned char c = (unsigned char)key[i]; - if (!curr->next[c]) { - curr->next[c] = c_TrieNode_Create(); - if (!curr->next[c]) return C_ERR_NOMEM; - } - curr = curr->next[c]; - } - - if (curr->value == NULL && value != NULL) { - self->size++; - } else if (curr->value != NULL && value == NULL) { - self->size--; - } - - curr->value = value; - return C_ERR_OK; -} - -void* c_Trie_Get(c_Trie_t* self, const char* key) { - if (!self || !key || !self->root) return NULL; - - c_TrieNode_t* curr = self->root; - c_size_t len = strlen(key); - - for (c_size_t i = 0; i < len; i++) { - unsigned char c = (unsigned char)key[i]; - curr = curr->next[c]; - if (!curr) return NULL; - } - return curr->value; -} - -c_bool_t c_Trie_Contains(c_Trie_t* self, const char* key) { - return (c_Trie_Get(self, key) != NULL) ? C_TRUE : C_FALSE; -} - -/* Internal recursive worker to support automated character branch purging on node deletions */ -static c_TrieNode_t* c_Trie_DeleteWorker(c_TrieNode_t* x, const char* key, c_size_t d, c_bool_t* out_deleted, c_size_t* size_ref) { - if (!x) return NULL; - - if (d == strlen(key)) { - if (x->value != NULL) { - x->value = NULL; - (*size_ref)--; - *out_deleted = C_TRUE; - } - } else { - unsigned char c = (unsigned char)key[d]; - x->next[c] = c_Trie_DeleteWorker(x->next[c], key, d + 1, out_deleted, size_ref); - } - - // Clean up empty nodes dynamically: if this node holds a value or has other sub-branches, preserve it - if (x->value != NULL) return x; - for (int c = 0; c < C_TRIE_R; c++) { - if (x->next[c] != NULL) return x; - } - - // Completely orphaned branch slot achieved; purge memory to prevent layout leaks - C_FREE(x); - return NULL; -} - -c_err_t c_Trie_Delete(c_Trie_t* self, const char* key) { - if (!self || !key || !self->root) return C_ERR_PARAM; - c_bool_t deleted = C_FALSE; - self->root = c_Trie_DeleteWorker(self->root, key, 0, &deleted, &(self->size)); - return deleted ? C_ERR_OK : C_ERR_PARAM; -} - - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -static void c_Trie_CollectWorker(c_TrieNode_t* x, c_StringBuffer_t* sb, c_size_t depth, c_StringList* result) { - if (!x) return; - - // 1. If an active data payload value exists, export a snapshot copy directly to your StringList - if (x->value != NULL) { - // Retrieve the current continuous null-terminated string handle from the buffer wrapper - // const char* completed_string = c_StringBuffer_CStr(sb); - c_StringList_Append(result, sb->buffer); - } - - // 2. Iterate sequentially through all possible child alphabet pathways - for (int c = 0; c < C_TRIE_R; c++) { - if (x->next[c]) { - // Append the edge character representation directly onto your builder stack frame - char character_token = (char)c; - c_StringBuffer_Append(sb, &character_token, 1); - - // Descend recursively down to explore child nodes - c_Trie_CollectWorker(x->next[c], sb, depth + 1, result); - - /* - * 🛡️ BACKTRACKING STRING INVARIANT: - * When winding back up a call frame stack, we must pop/truncate the last character - * from your string buffer to restore the parent prefix context state cleanly. - */ - c_StringBuffer_SetLength(sb, depth); - } - } -} - -c_err_t c_Trie_KeysWithPrefix(c_Trie_t* self, const char* prefix, c_StringList* result) { - if (!self || !prefix || !result) return C_ERR_PARAM; - - c_TrieNode_t* curr = self->root; - c_size_t len = strlen(prefix); - for (c_size_t i = 0; i < len; i++) { - unsigned char c = (unsigned char)prefix[i]; - curr = curr->next[c]; - if (!curr) return C_ERR_OK; - } - - c_StringBuffer_t sb; - if (c_StringBuffer_Init(&sb, len+256) != C_ERR_OK) { - return C_ERR_NOMEM; - } - - c_StringBuffer_Append(&sb, (const char*)prefix, len); - - c_Trie_CollectWorker(curr, &sb, len, result); - - c_StringBuffer_Destroy(&sb); - - return C_ERR_OK; -} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -/* Internal recursive matching collector worker */ -static void c_Trie_MatchWorker(c_TrieNode_t* x, c_StringBuffer_t* sb, const char* pattern, c_size_t depth, c_StringList* result) { - if (!x) return; - - c_size_t pattern_len = strlen(pattern); - - // Invariant Guard: If we have reached the pattern length, check for an active terminal value payload - if (depth == pattern_len) { - if (x->value != NULL) { - c_StringList_Append(result, sb->buffer); - } - return; - } - - unsigned char c = (unsigned char)pattern[depth]; - - // Case A: The active cursor encounters the dot wildcard character ('.') - if (c == '.') { - for (int next_char = 0; next_char < C_TRIE_R; next_char++) { - if (x->next[next_char]) { - char token = (char)next_char; - c_StringBuffer_Append(sb, &token, 1); - - c_Trie_MatchWorker(x->next[next_char], sb, pattern, depth + 1, result); - - // Backtracking unwinding step: reset logical buffer length context - c_StringBuffer_SetLength(sb, depth); - } - } - } - // Case B: Explicit character absolute matching step - else { - if (x->next[c]) { - char token = (char)c; - c_StringBuffer_Append(sb, &token, 1); - - c_Trie_MatchWorker(x->next[c], sb, pattern, depth + 1, result); - - // Backtracking unwinding step: reset logical buffer length context - c_StringBuffer_SetLength(sb, depth); - } - } -} - -/** - * Gather all keys currently matching a specific wildcard pattern string - */ -c_err_t c_Trie_KeysThatMatch(c_Trie_t* self, const char* pattern, c_StringList* result) { - if (!self || !pattern || !result || !self->root) { - return C_ERR_PARAM; - } - - c_StringBuffer_t sb; - if (c_StringBuffer_Init(&sb, 256) != C_ERR_OK) { - return C_ERR_NOMEM; - } - - // Start crawling the trie from root utilizing our string buffer builder - c_Trie_MatchWorker(self->root, &sb, pattern, 0, result); - - c_StringBuffer_Destroy(&sb); - return C_ERR_OK; -} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - - -/** - * Find the longest key registered in the Trie that is a prefix of the query string. - */ -char* c_Trie_LongestPrefixOf(c_Trie_t* self, const char* query) { - if (!self || !query || !self->root) { - return NULL; - } - - c_TrieNode_t* curr = self->root; - c_size_t query_len = strlen(query); - c_size_t longest_match_len = 0; - c_bool_t match_found = C_FALSE; - - // Iterate through characters of the query string sequentially - for (c_size_t i = 0; i < query_len; i++) { - unsigned char c = (unsigned char)query[i]; - curr = curr->next[c]; - - // If the path breaks, stop the search - if (!curr) { - break; - } - - // If this intermediate node marks a complete registered key, record its length - if (curr->value != NULL) { - longest_match_len = i + 1; - match_found = C_TRUE; - } - } - - // Allocate an isolated heap buffer to hold the output copy string - c_size_t output_bytes = match_found ? (longest_match_len + 1) : 1; - char* result_str = (char*)C_ALLOC(output_bytes); - if (!result_str) { - return NULL; - } - - if (match_found == C_TRUE) { - memcpy(result_str, query, longest_match_len); - result_str[longest_match_len] = '\0'; - } else { - result_str[0] = '\0'; // Return a clean empty string if no prefix matches - } - - return result_str; -} diff --git a/Search/c_Trie.h b/Search/c_Trie.h deleted file mode 100644 index 6c14365..0000000 --- a/Search/c_Trie.h +++ /dev/null @@ -1,82 +0,0 @@ -#ifndef INCLUDED_C_TRIE_H -#define INCLUDED_C_TRIE_H - -#ifndef INCLUDED_C_TYPES_H -#include -#endif /*INCLUDED_C_TYPES_H*/ - -#ifndef INCLUDED_C_STRINGLIST_H -#include -#endif /*INCLUDED_C_STRINGLIST_H*/ - - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -#define C_TRIE_R 256 - - -typedef struct c_TrieNode { - void* value; // Generic client value pointer associated with a complete key string - struct c_TrieNode* next[C_TRIE_R]; // Flat array of child node pointers mapping to character offsets -} c_TrieNode_t; - -typedef struct { - c_TrieNode_t* root; // Reference root pointer of the trie structure capsule - c_size_t size; // Total count of distinct key-value pairs stored inside the trie -} c_Trie_t; - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -c_err_t c_Trie_Init(c_Trie_t* self); - -void c_Trie_Destroy(c_Trie_t* self); - -/** - * Insert or update a string key mapped to a generic value pointer inside the table - */ -c_err_t c_Trie_Put(c_Trie_t* self, const char* key, void* value); - -/** - * Retrieve the generic client value pointer mapped to a string key - * @return The stored value address, or NULL if the key does not exist - */ -void* c_Trie_Get(c_Trie_t* self, const char* key); - -/** - * Check if the trie contains a matching entry for a specific string key - */ -c_bool_t c_Trie_Contains(c_Trie_t* self, const char* key); - -/** - * Remove a key-value mapping from the trie table. Cleans up orphaned down-stream nodes automatically. - */ -c_err_t c_Trie_Delete(c_Trie_t* self, const char* key); - -/** - * Gather all keys currently matching a specific character prefix layout string - * @param result An initialized c_StringList container to append the extracted string records - */ -c_err_t c_Trie_KeysWithPrefix(c_Trie_t* self, const char* prefix, c_StringList* result); - -/** - * Gather all keys currently matching a specific wildcard pattern string (where '.' matches any character) - * @param pattern String pattern containing characters and '.' wildcards - * @param result An initialized c_StringList container to append the extracted string records - */ -c_err_t c_Trie_KeysThatMatch(c_Trie_t* self, const char* pattern, c_StringList* result); - -/** - * Find the longest key registered in the Trie that is a prefix of the query string. - * For example, if "a", "app", and "apple" are in the Trie, LongestPrefixOf("applepie") returns "apple". - * - * @param query The source text string to analyze - * @return - * - A dynamically allocated copy of the longest matching prefix string (managed via C_ALLOC, caller frees) - * - An empty string copy "" if no prefix is matched - * - NULL if system parameters are invalid - */ -char* c_Trie_LongestPrefixOf(c_Trie_t* self, const char* query); - -#endif /*INCLUDED_C_TRIE_H*/ diff --git a/Sort/c_BinaryInsertionSort.c b/Sort/c_BinaryInsertionSort.c deleted file mode 100644 index 209282d..0000000 --- a/Sort/c_BinaryInsertionSort.c +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/Sort/c_BinaryInsertionSort.h b/Sort/c_BinaryInsertionSort.h deleted file mode 100644 index e67e4fb..0000000 --- a/Sort/c_BinaryInsertionSort.h +++ /dev/null @@ -1,79 +0,0 @@ -#ifndef INCLUDED_C_BINARYINSERTIONSORT_H -#define INCLUDED_C_BINARYINSERTIONSORT_H - -#ifndef INCLUDED_C_TYPES_H -#include -#endif /*INCLUDED_C_TYPES_H*/ - -#ifndef INCLUDED_C_MEMORY_H -#include -#endif /*INCLUDED_C_MEMORY_H*/ - - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - - -/** - * 通用折半插入排序函数 - * @param base 指向待排序数组首元素的指针 - * @param num 数组中元素的个数 - * @param size 每个元素的大小(字节数) - * @param compar 指向比较函数的指针 - */ -C_STATIC_FORCE_INLINE -void c_BinaryInsertionSort(void* base, c_size_t num, c_size_t size, - int (*compar)(const void*, const void*)) { - char* arr = (char*)base; // 强转为 char* 以便按单字节进行指针偏移 - - // 分配一块临时内存,用于存放当前要插入的“哨兵”元素(temp) -#define STACK_LIMIT 128 - char stack_buf[STACK_LIMIT]; - void* temp = NULL; - - if (size <= STACK_LIMIT) { - temp = stack_buf; - } else { - temp = C_ALLOC(size); - if (temp == NULL) return; - } - - for (c_size_t i = 1; i < num; i++) { - // temp = arr[i]:备份当前要插入的元素 - memcpy(temp, arr + (i * size), size); - - // 1. 使用二分查找决定插入位置 [left, right] - long long left = 0; - long long right = i - 1; - - while (left <= right) { - long long mid = left + (right - left) / 2; - - // 为了保证排序的稳定性(Stability), - // 当 mid 元素等于 temp 时,应当继续向右区间查找,把 temp 放到相同元素的后面 - if (compar(arr + (mid * size), temp) <= 0) { - left = mid + 1; // 目标位置在右边 - } else { - right = mid - 1; // 目标位置在左边 - } - } - // 循环结束时,left 就是元素应该插入的目标索引位置 - - // 2. 将 [left, i-1] 区间的元素全部向后移动一个位置 - for (long long j = i - 1; j >= left; j--) { - memcpy(arr + ((j + 1) * size), arr + (j * size), size); - } - - // 3. 将 temp 插入到腾出来的 left 位置 - memcpy(arr + (left * size), temp, size); - } - - // Only trigger free if it was actually allocated from the heap - if (size > STACK_LIMIT) { - C_FREE(temp); - } -#undef STACK_LIMIT -} - - -#endif /*INCLUDED_C_BINARYINSERTIONSORT_H*/ diff --git a/Sort/c_HeapSort.c b/Sort/c_HeapSort.c deleted file mode 100644 index c4aba39..0000000 --- a/Sort/c_HeapSort.c +++ /dev/null @@ -1,2 +0,0 @@ -#include -#include diff --git a/Sort/c_HeapSort.h b/Sort/c_HeapSort.h deleted file mode 100644 index 98441a7..0000000 --- a/Sort/c_HeapSort.h +++ /dev/null @@ -1,103 +0,0 @@ -#ifndef INCLUDED_C_HEAPSORT_H -#define INCLUDED_C_HEAPSORT_H - -#ifndef INCLUDED_C_TYPES_H -#include -#endif /*INCLUDED_C_TYPES_H*/ - -#ifndef INCLUDED_C_MEMORY_H -#include -#endif /*INCLUDED_C_MEMORY_H*/ - - - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - - -/** - * Internal macro helper to swap two arbitrary blocks of memory of given size. - */ -C_STATIC_FORCE_INLINE -void c_SwapInternal(char* a, char* b, c_size_t size, void* temp) { - if (a == b) return; - memcpy(temp, a, size); - memcpy(a, b, size); - memcpy(b, temp, size); -} - -/** - * Standard Sift-Down structural loop modified to build/maintain a Max-Heap. - */ -C_STATIC_FORCE_INLINE -void c_Heapify(char* arr, c_size_t num, c_size_t root, c_size_t size, - void* temp, int (*compar)(const void*, const void*)) { - c_int_t current = root; - - while (1) { - c_int_t left_child = (2 * current) + 1; - c_int_t right_child = (2 * current) + 2; - c_int_t largest = current; - - if (left_child < num && - compar(arr + (left_child * size), arr + (largest * size)) > 0) { - largest = left_child; - } - - if (right_child < num && - compar(arr + (right_child * size), arr + (largest * size)) > 0) { - largest = right_child; - } - - if (largest == current) { - break; - } - - c_SwapInternal(arr + (current * size), arr + (largest * size), size, temp); - current = largest; - } -} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -/** - * Top-Level Framework Entry Point for Heapsort. - * Time Complexity: O(n log n) | Space Complexity: O(1) in-place | Stable: No - */ -C_STATIC_FORCE_INLINE -void c_HeapSort(void* base, c_size_t num, c_size_t size, - int (*compar)(const void*, const void*)) { - if (base == NULL || num < 2 || size == 0) return; - - char* arr = (char*)base; - -#define HEAP_STACK_LIMIT 128 - char stack_buf[HEAP_STACK_LIMIT]; - void* temp = (size <= HEAP_STACK_LIMIT) ? stack_buf : C_ALLOC(size); - if (temp == NULL) return; - - // Safely cast size parameters to signed c_int_t variables before starting the algorithm loops - c_int_t total_items = (c_int_t)num; - - // Phase 1: Build the Max-Heap from the bottom up (Floyd's heap construction) - for (c_int_t i = (total_items / 2) - 1; i >= 0; i--) { - c_Heapify(arr, total_items, i, size, temp, compar); - } - - // Phase 2: In-place sorted array extraction - for (c_int_t k = total_items - 1; k > 0; k--) { - // Swap root max element to current end positions - c_SwapInternal(arr, arr + (k * size), size, temp); - - // Re-heapify the remaining sub-heap structure - c_Heapify(arr, k, 0, size, temp, compar); - } - - if (size > HEAP_STACK_LIMIT) { - C_FREE(temp); - } -#undef HEAP_STACK_LIMIT -} - -#endif /*INCLUDED_C_HEAPSORT_H*/ diff --git a/Sort/c_InPlaceMSDRadixSort.c b/Sort/c_InPlaceMSDRadixSort.c deleted file mode 100644 index f12af74..0000000 --- a/Sort/c_InPlaceMSDRadixSort.c +++ /dev/null @@ -1,105 +0,0 @@ -#include -#include - -/** - * Inline helper to safely extract a character at string offset d. - * Automatically maps a string's null terminator to a sentinel value of -1. - */ -C_STATIC_FORCE_INLINE -int c_InPlaceMSDRadixSort_CharAt(const char* str, c_size_t d) { - if (str == NULL) return -1; - c_size_t i = 0; - while (i < d && str[i] != '\0') { - i++; - } - if (str[i] == '\0' || i < d) return -1; - return (unsigned char)str[i]; -} - -/** - * Core Private Recursive Sub-partition In-place Sorting Subroutine. - * Employs a localized head/tail lookup permutation ring to operate directly within array slices. - */ -static void c_InPlaceMSDRadixSort_Recursive(char** arr, long long lo, long long hi, c_size_t d, - c_size_t R, c_size_t* count_buf, long long* heads, long long* tails) { - if (hi <= lo) return; - - // Elements are shifted forward by +2 slots to absorb the -1 string end sentinel gracefully - c_size_t total_buckets = R + 2; - memset(count_buf, 0, total_buckets * sizeof(c_size_t)); - - // Pass A: Compute frequency counts for the current digit slice - for (long long i = lo; i <= hi; i++) { - int c = c_InPlaceMSDRadixSort_CharAt(arr[i], d); - count_buf[c + 2]++; - } - - // Pass B: Transform frequencies into absolute head and tail cursor index maps - heads[0] = lo; - tails[0] = lo + (long long)count_buf[0]; - for (c_size_t r = 1; r < total_buckets; r++) { - heads[r] = tails[r - 1]; - tails[r] = heads[r] + (long long)count_buf[r]; - } - - // Pass C: Cyclic Permutation Swap Element Loop (In-Place Distribution) - for (c_size_t r = 0; r < total_buckets; r++) { - while (heads[r] < tails[r]) { - long long curr_idx = heads[r]; - int c = c_InPlaceMSDRadixSort_CharAt(arr[curr_idx], d); - c_size_t bucket = (c_size_t)(c + 2); - - if (bucket == r) { - heads[r]++; // Element is already in its correct bucket, step forward - } else { - // Evict the element to its correct destination bucket via data swap - long long dest_idx = heads[bucket]; - char* temp = arr[curr_idx]; - arr[curr_idx] = arr[dest_idx]; - arr[dest_idx] = temp; - - heads[bucket]++; // Increment the destination bucket's cursor - } - } - } - - // Pass D: Recursively process sub-arrays for each character bucket - // Shorter strings that terminated (sentinel character index 0) do not need deeper processing - long long current_lo = lo + (long long)count_buf[0]; - for (c_size_t r = 1; r < total_buckets; r++) { - long long current_hi = current_lo + (long long)count_buf[r] - 1; - - if (current_hi > current_lo) { - c_InPlaceMSDRadixSort_Recursive(arr, current_lo, current_hi, d + 1, R, count_buf, heads, tails); - } - current_lo = current_hi + 1; - } -} - -/** - * Sorts an array of variable-length strings completely in-place. - * Space Complexity: O(1) Auxiliary Heap memory footprint (Excluding recursive tracking arrays bound to R) - */ -c_err_t c_InPlaceMSDRadixSort_Sort(const c_InPlaceMSDRadixSort_t* sort, char** arr, c_size_t n) { - if (sort == NULL || arr == NULL || sort->R == 0) return C_ERR_PARAM; - if (n <= 1) return C_ERR_OK; - - // Radix-bound tracking buffers are allocated once upfront to eliminate heap overhead in hot loops - c_size_t total_buckets = sort->R + 2; - c_size_t* count_buf = (c_size_t*)C_ALLOC(total_buckets * sizeof(c_size_t)); - long long* heads = (long long*)C_ALLOC(total_buckets * sizeof(long long)); - long long* tails = (long long*)C_ALLOC(total_buckets * sizeof(long long)); - - if (count_buf == NULL || heads == NULL || tails == NULL) { - C_FREE(count_buf); C_FREE(heads); C_FREE(tails); - return C_ERR_NOMEM; - } - - // Launch the in-place cyclic permutation partition tree - c_InPlaceMSDRadixSort_Recursive(arr, 0, (long long)n - 1, 0, sort->R, count_buf, heads, tails); - - C_FREE(count_buf); - C_FREE(heads); - C_FREE(tails); - return C_ERR_OK; -} diff --git a/Sort/c_InPlaceMSDRadixSort.h b/Sort/c_InPlaceMSDRadixSort.h deleted file mode 100644 index 9c5311f..0000000 --- a/Sort/c_InPlaceMSDRadixSort.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef INCLUDED_C_INPLACEMSDRADIXSORT_H -#define INCLUDED_C_INPLACEMSDRADIXSORT_H - -#ifndef INCLUDED_C_TYPES_H -#include -#endif /*INCLUDED_C_TYPES_H*/ - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -typedef struct { - c_size_t R; // Alphabet size / Radix constraints (e.g., 256 for standard byte arrays) -} c_InPlaceMSDRadixSort_t; - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -c_err_t c_InPlaceMSDRadixSort_Sort(const c_InPlaceMSDRadixSort_t* sort, char** arr, c_size_t n); - -#endif /*INCLUDED_C_INPLACEMSDRADIXSORT_H*/ diff --git a/Sort/c_IndexMaxPQ.c b/Sort/c_IndexMaxPQ.c deleted file mode 100644 index 7c606b2..0000000 --- a/Sort/c_IndexMaxPQ.c +++ /dev/null @@ -1,184 +0,0 @@ -#include - -#include -#include - -/** - * Internal helper to swap two positions inside the heap structures. - * Keeps the inverted index (qp) tightly synchronized. - */ -C_STATIC_FORCE_INLINE -void c_IndexMaxPQ_Swap(c_IndexMaxPQ_t* pq_inst, c_size_t i, c_size_t j) { - long long temp_pq = pq_inst->pq[i]; - pq_inst->pq[i] = pq_inst->pq[j]; - pq_inst->pq[j] = temp_pq; - - pq_inst->qp[pq_inst->pq[i]] = (long long)i; - pq_inst->qp[pq_inst->pq[j]] = (long long)j; -} - -/** - * Sift-Up Operational Core for Max-Heap - */ -C_STATIC_FORCE_INLINE -void c_IndexMaxPQ_SiftUp(c_IndexMaxPQ_t* pq_inst, c_size_t current) { - char* keys_arr = (char*)pq_inst->keys; - c_size_t es = pq_inst->element_size; - - while (current > 0) { - c_size_t parent = (current - 1) / 2; - - const void* current_key = keys_arr + (pq_inst->pq[current] * es); - const void* parent_key = keys_arr + (pq_inst->pq[parent] * es); - - // Max-Heap condition: Break if current element is less than or equal to its parent - if (pq_inst->compar(current_key, parent_key) <= 0) { - break; - } - c_IndexMaxPQ_Swap(pq_inst, current, parent); - current = parent; - } -} - -/** - * Sift-Down Operational Core for Max-Heap - */ -C_STATIC_FORCE_INLINE -void c_IndexMaxPQ_SiftDown(c_IndexMaxPQ_t* pq_inst, c_size_t current) { - char* keys_arr = (char*)pq_inst->keys; - c_size_t es = pq_inst->element_size; - - while (1) { - c_size_t left_child = (2 * current) + 1; - c_size_t right_child = (2 * current) + 2; - c_size_t largest = current; - - // Max-Heap condition: Target the larger of the two children to sift down - if (left_child < pq_inst->size) { - if (pq_inst->compar(keys_arr + (pq_inst->pq[left_child] * es), keys_arr + (pq_inst->pq[largest] * es)) > 0) { - largest = left_child; - } - } - if (right_child < pq_inst->size) { - if (pq_inst->compar(keys_arr + (pq_inst->pq[right_child] * es), keys_arr + (pq_inst->pq[largest] * es)) > 0) { - largest = right_child; - } - } - - if (largest == current) { - break; - } - c_IndexMaxPQ_Swap(pq_inst, current, largest); - current = largest; - } -} - -/* ------------------------------------------------------------------------------------------------------------------ */ - -c_err_t c_IndexMaxPQ_Init(c_IndexMaxPQ_t* pq_inst, c_size_t max_items, c_size_t element_size, - int (*compar)(const void*, const void*)) { - if (pq_inst == NULL || max_items == 0 || element_size == 0 || compar == NULL) return C_ERR_PARAM; - - pq_inst->max_items = max_items; - pq_inst->element_size = element_size; - pq_inst->size = 0; - pq_inst->compar = compar; - - pq_inst->keys = C_ALLOC(max_items * element_size); - pq_inst->pq = (long long*)C_ALLOC(max_items * sizeof(long long)); - pq_inst->qp = (long long*)C_ALLOC(max_items * sizeof(long long)); - - if (pq_inst->keys == NULL || pq_inst->pq == NULL || pq_inst->qp == NULL) { - C_FREE(pq_inst->keys); C_FREE(pq_inst->pq); C_FREE(pq_inst->qp); - return C_ERR_NOMEM; - } - - for (c_size_t i = 0; i < max_items; i++) { - pq_inst->qp[i] = -1; - } - - return C_ERR_OK; -} - -void c_IndexMaxPQ_Destroy(c_IndexMaxPQ_t* pq_inst) { - if (pq_inst) { - C_FREE(pq_inst->keys); pq_inst->keys = NULL; - C_FREE(pq_inst->pq); pq_inst->pq = NULL; - C_FREE(pq_inst->qp); pq_inst->qp = NULL; - pq_inst->size = 0; - pq_inst->max_items = 0; - } -} - -c_bool_t c_IndexMaxPQ_Contains(c_IndexMaxPQ_t* pq_inst, c_size_t ext_id) { - if (pq_inst == NULL || ext_id >= pq_inst->max_items) return C_FALSE; - return pq_inst->qp[ext_id] != -1; -} - -c_err_t c_IndexMaxPQ_Push(c_IndexMaxPQ_t* pq_inst, c_size_t ext_id, const void* element) { - if (pq_inst == NULL || ext_id >= pq_inst->max_items || element == NULL) return C_ERR_PARAM; - if (c_IndexMaxPQ_Contains(pq_inst, ext_id)) return C_ERR_ALREADY_EXISTS; - - char* keys_arr = (char*)pq_inst->keys; - memcpy(keys_arr + (ext_id * pq_inst->element_size), element, pq_inst->element_size); - - c_size_t current = pq_inst->size; - pq_inst->pq[current] = (long long)ext_id; - pq_inst->qp[ext_id] = (long long)current; - - pq_inst->size++; - - c_IndexMaxPQ_SiftUp(pq_inst, current); - - return C_ERR_OK; -} - -c_err_t c_IndexMaxPQ_Pop(c_IndexMaxPQ_t* pq_inst, c_size_t* out_ext_id, void* out_element_buffer) { - if (pq_inst == NULL) return C_ERR_PARAM; - if (pq_inst->size == 0) return C_ERR_EMPTY; - - long long max_ext_id = pq_inst->pq[0]; - if (out_ext_id) *out_ext_id = (c_size_t)max_ext_id; - - if (out_element_buffer) { - char* keys_arr = (char*)pq_inst->keys; - memcpy(out_element_buffer, keys_arr + (max_ext_id * pq_inst->element_size), pq_inst->element_size); - } - - c_IndexMaxPQ_Swap(pq_inst, 0, pq_inst->size - 1); - - pq_inst->qp[max_ext_id] = -1; - pq_inst->size--; - - if (pq_inst->size > 0) { - c_IndexMaxPQ_SiftDown(pq_inst, 0); - } - - return C_ERR_OK; -} - -c_err_t c_IndexMaxPQ_ChangeKey(c_IndexMaxPQ_t* pq_inst, c_size_t ext_id, const void* new_element) { - if (pq_inst == NULL || ext_id >= pq_inst->max_items || new_element == NULL) return C_ERR_PARAM; - if (!c_IndexMaxPQ_Contains(pq_inst, ext_id)) return C_ERR_NOTFOUND; - - char* keys_arr = (char*)pq_inst->keys; - c_size_t es = pq_inst->element_size; - - memcpy(keys_arr + (ext_id * es), new_element, es); - - c_size_t heap_pos = (c_size_t)pq_inst->qp[ext_id]; - - c_IndexMaxPQ_SiftUp(pq_inst, heap_pos); - c_IndexMaxPQ_SiftDown(pq_inst, heap_pos); - - return C_ERR_OK; -} - -void* c_IndexMaxPQ_Peek(c_IndexMaxPQ_t* pq_inst, c_size_t* out_ext_id) { - if (pq_inst == NULL || pq_inst->size == 0) return NULL; - if (out_ext_id) *out_ext_id = (c_size_t)pq_inst->pq[0]; - - char* keys_arr = (char*)pq_inst->keys; - return keys_arr + (pq_inst->pq[0] * pq_inst->element_size); -} - diff --git a/Sort/c_IndexMaxPQ.h b/Sort/c_IndexMaxPQ.h deleted file mode 100644 index e3d5271..0000000 --- a/Sort/c_IndexMaxPQ.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef INCLUDED_C_INDEXMAXPQ_H -#define INCLUDED_C_INDEXMAXPQ_H - -#ifndef INCLUDED_C_TYPES_H -#include -#endif /*INCLUDED_C_TYPES_H*/ - - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -typedef struct { - void* keys; - c_size_t element_size; - c_size_t max_items; - c_size_t size; - long long* pq; - long long* qp; - int (*compar)(const void*, const void*); -} c_IndexMaxPQ_t; - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -c_err_t c_IndexMaxPQ_Init(c_IndexMaxPQ_t* pq_inst, c_size_t max_items, c_size_t element_size, - int (*compar)(const void*, const void*)); - -void c_IndexMaxPQ_Destroy(c_IndexMaxPQ_t* pq_inst); - -c_bool_t c_IndexMaxPQ_Contains(c_IndexMaxPQ_t* pq_inst, c_size_t ext_id); - -c_err_t c_IndexMaxPQ_Push(c_IndexMaxPQ_t* pq_inst, c_size_t ext_id, const void* element); - -c_err_t c_IndexMaxPQ_Pop(c_IndexMaxPQ_t* pq_inst, c_size_t* out_ext_id, void* out_element_buffer); - -c_err_t c_IndexMaxPQ_ChangeKey(c_IndexMaxPQ_t* pq_inst, c_size_t ext_id, const void* new_element); - -void* c_IndexMaxPQ_Peek(c_IndexMaxPQ_t* pq_inst, c_size_t* out_ext_id); - - -#endif /*INCLUDED_C_INDEXMAXPQ_H*/ diff --git a/Sort/c_IndexMinPQ.c b/Sort/c_IndexMinPQ.c deleted file mode 100644 index 8ecd6d0..0000000 --- a/Sort/c_IndexMinPQ.c +++ /dev/null @@ -1,192 +0,0 @@ -#include -#include - -/** - * Internal helper to swap two positions inside the heap structures. - * Also keeps the inverted index (qp) tightly synchronized. - */ -C_STATIC_FORCE_INLINE -void c_IndexMinPQ_Swap(c_IndexMinPQ_t* pq_inst, c_size_t i, c_size_t j) { - long long temp_pq = pq_inst->pq[i]; - pq_inst->pq[i] = pq_inst->pq[j]; - pq_inst->pq[j] = temp_pq; - - pq_inst->qp[pq_inst->pq[i]] = (long long)i; - pq_inst->qp[pq_inst->pq[j]] = (long long)j; -} - -/** - * Sift-Up Operational Core - */ -C_STATIC_FORCE_INLINE -void c_IndexMinPQ_SiftUp(c_IndexMinPQ_t* pq_inst, c_size_t current) { - char* keys_arr = (char*)pq_inst->keys; - c_size_t es = pq_inst->element_size; - - while (current > 0) { - c_size_t parent = (current - 1) / 2; - - const void* current_key = keys_arr + (pq_inst->pq[current] * es); - const void* parent_key = keys_arr + (pq_inst->pq[parent] * es); - - if (pq_inst->compar(current_key, parent_key) >= 0) { - break; - } - c_IndexMinPQ_Swap(pq_inst, current, parent); - current = parent; - } -} - -/** - * Sift-Down Operational Core - */ -C_STATIC_FORCE_INLINE -void c_IndexMinPQ_SiftDown(c_IndexMinPQ_t* pq_inst, c_size_t current) { - char* keys_arr = (char*)pq_inst->keys; - c_size_t es = pq_inst->element_size; - - while (1) { - c_size_t left_child = (2 * current) + 1; - c_size_t right_child = (2 * current) + 2; - c_size_t smallest = current; - - if (left_child < pq_inst->size) { - if (pq_inst->compar(keys_arr + (pq_inst->pq[left_child] * es), keys_arr + (pq_inst->pq[smallest] * es)) < 0) { - smallest = left_child; - } - } - if (right_child < pq_inst->size) { - if (pq_inst->compar(keys_arr + (pq_inst->pq[right_child] * es), keys_arr + (pq_inst->pq[smallest] * es)) < 0) { - smallest = right_child; - } - } - - if (smallest == current) { - break; - } - c_IndexMinPQ_Swap(pq_inst, current, smallest); - current = smallest; - } -} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -c_err_t c_IndexMinPQ_Init(c_IndexMinPQ_t* pq_inst, c_size_t max_items, c_size_t element_size, - int (*compar)(const void*, const void*)) { - if (pq_inst == NULL || max_items == 0 || element_size == 0 || compar == NULL) return C_ERR_PARAM; - - pq_inst->max_items = max_items; - pq_inst->element_size = element_size; - pq_inst->size = 0; - pq_inst->compar = compar; - - pq_inst->keys = C_ALLOC(max_items * element_size); - pq_inst->pq = (long long*)C_ALLOC(max_items * sizeof(long long)); - pq_inst->qp = (long long*)C_ALLOC(max_items * sizeof(long long)); - - if (pq_inst->keys == NULL || pq_inst->pq == NULL || pq_inst->qp == NULL) { - // Safe cleanup if any allocation segment drops offline - C_FREE(pq_inst->keys); C_FREE(pq_inst->pq); C_FREE(pq_inst->qp); - return C_ERR_NOMEM; - } - - // Initialize inverted tracking array cells to -1 (indicating absent from heap) - for (c_size_t i = 0; i < max_items; i++) { - pq_inst->qp[i] = -1; - } - - return C_ERR_OK; -} - -void c_IndexMinPQ_Destroy(c_IndexMinPQ_t* pq_inst) { - if (pq_inst) { - C_FREE(pq_inst->keys); pq_inst->keys = NULL; - C_FREE(pq_inst->pq); pq_inst->pq = NULL; - C_FREE(pq_inst->qp); pq_inst->qp = NULL; - pq_inst->size = 0; - pq_inst->max_items = 0; - } -} - -c_bool_t c_IndexMinPQ_Contains(c_IndexMinPQ_t* pq_inst, c_size_t ext_id) { - if (pq_inst == NULL || ext_id >= pq_inst->max_items) return C_FALSE; - return pq_inst->qp[ext_id] != -1; -} - -c_err_t c_IndexMinPQ_Push(c_IndexMinPQ_t* pq_inst, c_size_t ext_id, const void* element) { - if (pq_inst == NULL || ext_id >= pq_inst->max_items || element == NULL) return C_ERR_PARAM; - if (c_IndexMinPQ_Contains(pq_inst, ext_id)) return C_ERR_ALREADY_EXISTS; // Must use Change Key API if already existing - - char* keys_arr = (char*)pq_inst->keys; - - // Store key inside the primary index table slot - memcpy(keys_arr + (ext_id * pq_inst->element_size), element, pq_inst->element_size); - - // Append to bottom leaf array trackers - c_size_t current = pq_inst->size; - pq_inst->pq[current] = (long long)ext_id; - pq_inst->qp[ext_id] = (long long)current; - - pq_inst->size++; - - // Sift upward to re-stabilize the min-heap property - c_IndexMinPQ_SiftUp(pq_inst, current); - - return C_ERR_OK; -} - -c_err_t c_IndexMinPQ_Pop(c_IndexMinPQ_t* pq_inst, c_size_t* out_ext_id, void* out_element_buffer) { - if (pq_inst == NULL) return C_ERR_PARAM; - if (pq_inst->size == 0) return C_ERR_EMPTY; - - long long min_ext_id = pq_inst->pq[0]; - if (out_ext_id) *out_ext_id = (c_size_t)min_ext_id; - - if (out_element_buffer) { - char* keys_arr = (char*)pq_inst->keys; - memcpy(out_element_buffer, keys_arr + (min_ext_id * pq_inst->element_size), pq_inst->element_size); - } - - // Swap top root with the trailing active leaf node - c_IndexMinPQ_Swap(pq_inst, 0, pq_inst->size - 1); - - // Clean up tracking registers for extracted ID - pq_inst->qp[min_ext_id] = -1; - pq_inst->size--; - - // Sift down from the root to re-balance the tree bounds - if (pq_inst->size > 0) { - c_IndexMinPQ_SiftDown(pq_inst, 0); - } - - return C_ERR_OK; -} - -c_err_t c_IndexMinPQ_ChangeKey(c_IndexMinPQ_t* pq_inst, c_size_t ext_id, const void* new_element) { - if (pq_inst == NULL || ext_id >= pq_inst->max_items || new_element == NULL) return C_ERR_PARAM; - if (!c_IndexMinPQ_Contains(pq_inst, ext_id)) return C_ERR_NOTFOUND; - - char* keys_arr = (char*)pq_inst->keys; - c_size_t es = pq_inst->element_size; - - // Update raw payload data in-place - memcpy(keys_arr + (ext_id * es), new_element, es); - - // Leverage the inverted index (qp) to instantly locate the item's position inside the heap tree - c_size_t heap_pos = (c_size_t)pq_inst->qp[ext_id]; - - // Trigger localized sifting in both directions. Only one will execute depending on whether the key grew or shrank. - c_IndexMinPQ_SiftUp(pq_inst, heap_pos); - c_IndexMinPQ_SiftDown(pq_inst, heap_pos); - - return C_ERR_OK; -} - -void* c_IndexMinPQ_Peek(c_IndexMinPQ_t* pq_inst, c_size_t* out_ext_id) { - if (pq_inst == NULL || pq_inst->size == 0) return NULL; - if (out_ext_id) *out_ext_id = (c_size_t)pq_inst->pq[0]; - - char* keys_arr = (char*)pq_inst->keys; - return keys_arr + (pq_inst->pq[0] * pq_inst->element_size); -} \ No newline at end of file diff --git a/Sort/c_IndexMinPQ.h b/Sort/c_IndexMinPQ.h deleted file mode 100644 index de0dcd8..0000000 --- a/Sort/c_IndexMinPQ.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef INCLUDED_C_INDEXMINPQ_H -#define INCLUDED_C_INDEXMINPQ_H - -#ifndef INCLUDED_C_TYPES_H -#include -#endif /*INCLUDED_C_TYPES_H*/ - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - - -typedef struct { - void* keys; // Flat array storing user's complex items (indexed by external ID) - c_size_t element_size; // Size of each element in bytes - c_size_t max_items; // Maximum external ID capacity (0 to max_items - 1) - c_size_t size; // Current active element count inside the heap - - long long* pq; // Heap array: map heap position -> external ID - long long* qp; // Inverted index array: map external ID -> heap position (-1 if not in heap) - - int (*compar)(const void*, const void*); // Custom comparison rule pointer -} c_IndexMinPQ_t; - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -c_err_t c_IndexMinPQ_Init(c_IndexMinPQ_t* pq_inst, c_size_t max_items, c_size_t element_size, - int (*compar)(const void*, const void*)); - -void c_IndexMinPQ_Destroy(c_IndexMinPQ_t* pq_inst); - -c_bool_t c_IndexMinPQ_Contains(c_IndexMinPQ_t* pq_inst, c_size_t ext_id); - -c_err_t c_IndexMinPQ_Push(c_IndexMinPQ_t* pq_inst, c_size_t ext_id, const void* element); - -c_err_t c_IndexMinPQ_Pop(c_IndexMinPQ_t* pq_inst, c_size_t* out_ext_id, void* out_element_buffer) ; - -c_err_t c_IndexMinPQ_ChangeKey(c_IndexMinPQ_t* pq_inst, c_size_t ext_id, const void* new_element); - -void* c_IndexMinPQ_Peek(c_IndexMinPQ_t* pq_inst, c_size_t* out_ext_id); - -#endif /*INCLUDED_C_INDEXMINPQ_H*/ diff --git a/Sort/c_InsertionSort.c b/Sort/c_InsertionSort.c deleted file mode 100644 index 4ffb681..0000000 --- a/Sort/c_InsertionSort.c +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/Sort/c_InsertionSort.h b/Sort/c_InsertionSort.h deleted file mode 100644 index 6c4b40e..0000000 --- a/Sort/c_InsertionSort.h +++ /dev/null @@ -1,68 +0,0 @@ -#ifndef INCLUDED_C_INSERTIONSORT_H -#define INCLUDED_C_INSERTIONSORT_H - -#ifndef INCLUDED_C_TYPES_H -#include -#endif /*INCLUDED_C_TYPES_H*/ - -#ifndef INCLUDED_C_MEMORY_H -#include -#endif /*INCLUDED_C_MEMORY_H*/ - - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - - -/** - * 通用插入排序函数 - * @param base 指向待排序数组首元素的指针 - * @param num 数组中元素的个数 - * @param size 每个元素的大小(字节数) - * @param compar 指向比较函数的指针 - */ -C_STATIC_FORCE_INLINE -void c_InsertionSort(void* base, c_size_t num, c_size_t size, - int (*compar)(const void*, const void*)) { - char* arr = (char*)base; // 强转为 char* 以便按单字节进行指针偏移 - - // 分配一块临时内存,用于存放当前要插入的“哨兵”元素(temp) -#define STACK_LIMIT 128 - char stack_buf[STACK_LIMIT]; - void* temp = NULL; - - if (size <= STACK_LIMIT) { - temp = stack_buf; - } else { - temp = C_ALLOC(size); - if (temp == NULL) return; - } - - for (c_size_t i = 1; i < num; i++) { - // temp = arr[i]:将当前元素复制到临时空间 - memcpy(temp, arr + (i * size), size); - - long long j = i - 1; - - // 循环条件:j >= 0 且 arr[j] > temp - // 使用 compar(arr + (j * size), temp) > 0 来判断是否需要后移 - while (j >= 0 && compar(arr + (j * size), temp) > 0) { - // arr[j + 1] = arr[j]:将前面的元素往后移一位 - memcpy(arr + ((j + 1) * size), arr + (j * size), size); - j--; - } - - // arr[j + 1] = temp:将目标元素插入到正确位置 - memcpy(arr + ((j + 1) * size), temp, size); - } - - // Only trigger free if it was actually allocated from the heap - if (size > STACK_LIMIT) { - C_FREE(temp); - } -#undef STACK_LIMIT -} - - - -#endif /*INCLUDED_C_INSERTIONSORT_H*/ diff --git a/Sort/c_LSDRadixSort.c b/Sort/c_LSDRadixSort.c deleted file mode 100644 index 63eeed6..0000000 --- a/Sort/c_LSDRadixSort.c +++ /dev/null @@ -1,62 +0,0 @@ -#include -#include - -/** - * Sorts an array of fixed-length strings stably using the LSD Radix Sort pipeline. - * Features upfront workspace allocations to completely eliminate heap thrashing in hot loops. - * - * Time Complexity: O(W * (N + R)) | Space Complexity: O(N + R) transient workspace memory - * @param sort Pointer to the initialized LSD config profile. - * @param arr Array of pointers to null-terminated char arrays (each must be at least W long). - * @param n Total number of strings inside the array. - */ -c_err_t c_LSDRadixSort_Sort(const c_LSDRadixSort_t* sort, char** arr, c_size_t n) { - if (sort == NULL || arr == NULL || sort->R == 0 || sort->W == 0) return C_ERR_PARAM; - if (n <= 1) return C_ERR_OK; // Trivial exit pass - - c_size_t R = sort->R; - c_size_t W = sort->W; - - // Upfront Transient Workspace Allocation: Eliminates allocation overhead in hot paths - char** aux = (char**)C_ALLOC(n * sizeof(char*)); - c_size_t* count = (c_size_t*)C_ALLOC((R + 1) * sizeof(c_size_t)); - - if (aux == NULL || count == NULL) { - C_FREE(aux); - C_FREE(count); - return C_ERR_NOMEM; - } - - // --- Core Iterative LSD Pass Loop --- - // Travel from right to left (Least Significant to Most Significant) - for (long long d = (long long)W - 1; d >= 0; d--) { - - // Reset the counting frequency registers - memset(count, 0, (R + 1) * sizeof(c_size_t)); - - // Pass A: Compute frequency counts using character indices as bucket addresses - for (c_size_t i = 0; i < n; i++) { - unsigned char c = (unsigned char)arr[i][d]; - count[c + 1]++; - } - - // Pass B: Transform frequencies into structural start indexes (Prefix Sums) - for (c_size_t r = 0; r < R; r++) { - count[r + 1] += count[r]; - } - - // Pass C: Distribute strings to the temporary aux array (Guarantees Stable Order Sorting) - for (c_size_t i = 0; i < n; i++) { - unsigned char c = (unsigned char)arr[i][d]; - aux[count[c]++] = arr[i]; - } - - // Pass D: Copy back copies natively to the primary tracking layout pointers - memcpy(arr, aux, n * sizeof(char*)); - } - - // Purge temporary scratchpad workspace containers cleanly - C_FREE(aux); - C_FREE(count); - return C_ERR_OK; -} diff --git a/Sort/c_LSDRadixSort.h b/Sort/c_LSDRadixSort.h deleted file mode 100644 index 20a5d6a..0000000 --- a/Sort/c_LSDRadixSort.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef INCLUDED_C_LSDRADIXSORT_H -#define INCLUDED_C_LSDRADIXSORT_H - -#ifndef INCLUDED_C_TYPES_H -#include -#endif /*INCLUDED_C_TYPES_H*/ - -typedef struct { - c_size_t R; // Alphabet size / Radix constraints (e.g., 256 for ASCII chars or bytes) - c_size_t W; // Fixed length key width criteria (number of sorting passes/characters) -} c_LSDRadixSort_t; - -c_err_t c_LSDRadixSort_Sort(const c_LSDRadixSort_t* sort, char** arr, c_size_t n); - - -#endif /*INCLUDED_C_LSDRADIXSORT_H*/ diff --git a/Sort/c_MSDRadixSort.c b/Sort/c_MSDRadixSort.c deleted file mode 100644 index a47dfc0..0000000 --- a/Sort/c_MSDRadixSort.c +++ /dev/null @@ -1,99 +0,0 @@ -#include -#include - -/** - * Inline helper to safely extract a character at string offset d. - * Automatically maps a string's null terminator to a sentinel value of -1. - */ -C_STATIC_FORCE_INLINE -int c_MSDRadixSort_CharAt(const char* str, c_size_t d) { - if (str == NULL) return -1; - // Walk down to offset d without triggering a buffer overflow lookup violation - c_size_t i = 0; - while (i < d && str[i] != '\0') { - i++; - } - if (str[i] == '\0' || i < d) return -1; - return (unsigned char)str[i]; -} - -/** - * Core Private Recursive Sub-partition Sorting Subroutine. - * Shares a single pre-allocated auxiliary buffer across stack frames to prevent heap allocation overhead. - * - * @param lo Lower boundary index of the target partition array slice (inclusive). - * @param hi Upper boundary index of the target partition array slice (inclusive). - * @param d The current character string evaluation offset cursor. - */ -static void c_MSDRadixSort_SortRecursive(char** arr, long long lo, long long hi, c_size_t d, - c_size_t R, char** aux, c_size_t* count_buf) { - if (hi <= lo) return; - - // Cutoff to Insertion Sort for tiny sub-arrays can be added here for production fine-tuning. - - // Calculate sub-slice width and initialize count registers - c_size_t n = (c_size_t)(hi - lo + 1); - // Elements are shifted forward by +2 slots to gracefully absorb the -1 string end sentinel - memset(count_buf, 0, (R + 2) * sizeof(c_size_t)); - - // Pass A: Compute frequency buckets - for (long long i = lo; i <= hi; i++) { - int c = c_MSDRadixSort_CharAt(arr[i], d); - count_buf[c + 2]++; - } - - // Pass B: Transform frequencies into structural start indexes (Prefix Sums) - for (c_size_t r = 0; r < R + 1; r++) { - count_buf[r + 1] += count_buf[r]; - } - - // Pass C: Distribute strings stably to the temporary auxiliary workspace slice - for (long long i = lo; i <= hi; i++) { - int c = c_MSDRadixSort_CharAt(arr[i], d); - aux[count_buf[c + 1]++] = arr[i]; - } - - // Pass D: Copy back copies natively to the primary tracking layout pointers - for (long long i = lo; i <= hi; i++) { - arr[i] = aux[i - lo]; - } - - // Recursively sort sub-arrays for each character bucket - // Note: count_buf[0] handles strings that hit a terminal '\0' sentinel, so we skip it to prevent loops - for (c_size_t r = 0; r < R; r++) { - long long next_lo = lo + (long long)count_buf[r]; - long long next_hi = lo + (long long)count_buf[r + 1] - 1; - - if (next_hi > next_lo) { - c_MSDRadixSort_SortRecursive(arr, next_lo, next_hi, d + 1, R, aux, count_buf); - } - } -} - -/** - * Sorts an array of variable-length strings using the MSD Radix Sort pipeline. - * Guarantees zero runtime heap thrashing via upfront workspace pooling. - * - * Time Complexity: O(N * String_Length) optimal | Space Complexity: O(N + R) transient workspace memory - */ -c_err_t c_MSDRadixSort_Sort(const c_MSDRadixSort_t* sort, char** arr, c_size_t n) { - if (sort == NULL || arr == NULL || sort->R == 0) return C_ERR_PARAM; - if (n <= 1) return C_ERR_OK; - - // Upfront Transient Workspace Allocation: Eliminates allocation overhead in deep recursions - char** aux = (char**)C_ALLOC(n * sizeof(char*)); - c_size_t* count_buf = (c_size_t*)C_ALLOC((sort->R + 2) * sizeof(c_size_t)); - - if (aux == NULL || count_buf == NULL) { - C_FREE(aux); - C_FREE(count_buf); - return C_ERR_NOMEM; - } - - // Launch the core string-wise recursive partition tree - c_MSDRadixSort_SortRecursive(arr, 0, (long long)n - 1, 0, sort->R, aux, count_buf); - - C_FREE(aux); - C_FREE(count_buf); - return C_ERR_OK; -} diff --git a/Sort/c_MSDRadixSort.h b/Sort/c_MSDRadixSort.h deleted file mode 100644 index 21ed3e0..0000000 --- a/Sort/c_MSDRadixSort.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef INCLUDED_C_MSDRADIXSORT_H -#define INCLUDED_C_MSDRADIXSORT_H - -#ifndef INCLUDED_C_TYPES_H -#include -#endif /*INCLUDED_C_TYPES_H*/ - -typedef struct { - c_size_t R; // Alphabet size / Radix constraints (e.g., 256 for standard byte arrays) -} c_MSDRadixSort_t; - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -c_err_t c_MSDRadixSort_Sort(const c_MSDRadixSort_t* sort, char** arr, c_size_t n); - -#endif /*INCLUDED_C_MSDRADIXSORT_H*/ diff --git a/Sort/c_MaxPQ.c b/Sort/c_MaxPQ.c deleted file mode 100644 index 55b2472..0000000 --- a/Sort/c_MaxPQ.c +++ /dev/null @@ -1,208 +0,0 @@ -#include -#include - - -/** - * Internal macro helper to swap two arbitrary blocks of memory. - */ -C_STATIC_FORCE_INLINE -void c_HeapSwap(char* arr, c_size_t idx1, c_size_t idx2, c_size_t size, void* temp) { - if (idx1 == idx2) return; - char* a = arr + (idx1 * size); - char* b = arr + (idx2 * size); - memcpy(temp, a, size); - memcpy(a, b, size); - memcpy(b, temp, size); -} - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -c_err_t c_MaxPQ_Init(c_MaxPQ_t* pq, c_size_t initial_capacity, c_size_t element_size, - int (*compar)(const void*, const void*)) { - if (pq == NULL || element_size == 0 || compar == NULL) return C_ERR_PARAM; - - pq->capacity = (initial_capacity > 0) ? initial_capacity : 4; - pq->element_size = element_size; - pq->size = 0; - pq->compar = compar; - pq->data = C_ALLOC(pq->capacity * element_size); - - if (pq->data == NULL) return C_ERR_NOMEM; - return C_ERR_OK; -} - -void c_MaxPQ_Destroy(c_MaxPQ_t* pq) { - if (!pq) return; - C_FREE(pq->data); - pq->size = 0; - pq->capacity = 0; -} - -c_err_t c_MaxPQ_Push(c_MaxPQ_t* pq, const void* element) { - if (pq == NULL || element == NULL) return C_ERR_PARAM; - - char* arr = (char*)pq->data; - - // Capacity check: Scale memory boundary out if full - if (pq->size >= pq->capacity) { - c_size_t new_capacity = pq->capacity * 2; - // Reallocate manually utilizing framework macros - void* new_data = C_ALLOC(new_capacity * pq->element_size); - if (new_data == NULL) return C_ERR_NOMEM; // Allocation failure block - - memcpy(new_data, pq->data, pq->size * pq->element_size); - C_FREE(pq->data); - pq->data = new_data; - pq->capacity = new_capacity; - arr = (char*)pq->data; - } - - // Allocate stack cache buffer for object swapping routines -#define PQ_STACK_LIMIT 128 - char stack_buf[PQ_STACK_LIMIT]; - void* temp = (pq->element_size <= PQ_STACK_LIMIT) ? stack_buf : C_ALLOC(pq->element_size); - if (temp == NULL) return C_ERR_NOMEM; - - // Place new element at the bottom-most leaf slot of the max-heap tree - c_size_t current = pq->size; - memcpy(arr + (current * pq->element_size), element, pq->element_size); - pq->size++; - - // Sift-Up loop processing - while (current > 0) { - c_size_t parent = (current - 1) / 2; - - // Max-heap rule tracking: If child <= parent, tree balancing properties are correct - if (pq->compar(arr + (current * pq->element_size), arr + (parent * pq->element_size)) <= 0) { - break; - } - - c_HeapSwap(arr, current, parent, pq->element_size, temp); - current = parent; - } - - if (pq->element_size > PQ_STACK_LIMIT) C_FREE(temp); -#undef PQ_STACK_LIMIT - return C_ERR_OK; -} - - -c_err_t c_MaxPQ_Pop(c_MaxPQ_t* pq, void* output_buffer) { - if (!pq) return C_ERR_PARAM; - - if (pq->size == 0) return C_ERR_EMPTY; - - char* arr = (char*)pq->data; - - // If a tracking output buffer pointer is supplied, export the maximum item - if (output_buffer != NULL) { - memcpy(output_buffer, arr, pq->element_size); - } - - // Shrink element count tracking early - pq->size--; - - if (pq->size > 0) { - // Swap the last leaf node up to root position - memcpy(arr, arr + (pq->size * pq->element_size), pq->element_size); - -#define PQ_STACK_LIMIT 128 - char stack_buf[PQ_STACK_LIMIT]; - void* temp = (pq->element_size <= PQ_STACK_LIMIT) ? stack_buf : C_ALLOC(pq->element_size); - if (temp == NULL) return C_ERR_NOMEM; - - // Sift-Down balancing loop processing - c_size_t current = 0; - while (1) { - c_size_t left_child = (2 * current) + 1; - c_size_t right_child = (2 * current) + 2; - c_size_t largest = current; - - // Check if left child is larger than current node - if (left_child < pq->size && - pq->compar(arr + (left_child * pq->element_size), arr + (largest * pq->element_size)) > 0) { - largest = left_child; - } - - // Check if right child is larger than the currently tracked largest node - if (right_child < pq->size && - pq->compar(arr + (right_child * pq->element_size), arr + (largest * pq->element_size)) > 0) { - largest = right_child; - } - - // Balanced condition achieved - if (largest == current) { - break; - } - - c_HeapSwap(arr, current, largest, pq->element_size, temp); - current = largest; - } - - if (pq->element_size > PQ_STACK_LIMIT) C_FREE(temp); -#undef PQ_STACK_LIMIT - } - - return C_ERR_OK; -} - -void* c_MaxPQ_Peek(c_MaxPQ_t* pq) { - if (pq == NULL || pq->size == 0) return NULL; - return pq->data; // Root node is consistently maximum element -} - -c_err_t c_MaxPQ_Clear(c_MaxPQ_t* pq) { - if (pq == NULL) return C_ERR_PARAM; - - // Simply reset the size to zero. The underlying buffer remains allocated. - pq->size = 0; - - return C_ERR_OK; -} - -/** - * Manually resize the memory allocation capacity of the Priority Queue. - * @param pq Pointer to the Max Priority Queue instance. - * @param new_capacity The desired number of element slots to allocate. - * @return C_ERR_OK if successful, C_ERR_INVALID for bad arguments, - * or C_ERR_NOMEM if memory allocation fails. - */ -c_err_t c_MaxPQ_Resize(c_MaxPQ_t* pq, c_size_t new_capacity) { - if (pq == NULL) return C_ERR_PARAM; - - // Prevent shrinking below the current number of active elements inside the heap - if (new_capacity < pq->size) return C_ERR_PARAM; - - // If the capacity is already identical, skip processing to avoid memory overhead - if (new_capacity == pq->capacity) return C_ERR_OK; - - // Handle downsizing down to 0 safely if the queue is empty - if (new_capacity == 0) { - if (pq->data != NULL) { - C_FREE(pq->data); - pq->data = NULL; - } - pq->capacity = 0; - return C_ERR_OK; - } - - // Allocate a new memory block according to your framework specification - void* new_data = C_ALLOC(new_capacity * pq->element_size); - if (new_data == NULL) return C_ERR_NOMEM; - - // If there are existing active elements, move them to the newly allocated block - if (pq->size > 0 && pq->data != NULL) { - memcpy(new_data, pq->data, pq->size * pq->element_size); - } - - // Free the old array and bind the new tracking parameters - if (pq->data != NULL) { - C_FREE(pq->data); - } - pq->data = new_data; - pq->capacity = new_capacity; - - return C_ERR_OK; -} - diff --git a/Sort/c_MaxPQ.h b/Sort/c_MaxPQ.h deleted file mode 100644 index d6ac7d4..0000000 --- a/Sort/c_MaxPQ.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef INCLUDED_C_MAXPQ_H -#define INCLUDED_C_MAXPQ_H - -#ifndef INCLUDED_C_TYPES_H -#include -#endif /*INCLUDED_C_TYPES_H*/ - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -typedef struct { - void* data; // Flat char pointer block tracking memory slots - c_size_t element_size; // Size of each complex structure element in bytes - c_size_t capacity; // Maximum allocated element capacity - c_size_t size; // Current active element count inside the heap - int (*compar)(const void*, const void*); // Custom comparison rule pointer -} c_MaxPQ_t; - - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -c_err_t c_MaxPQ_Init(c_MaxPQ_t* pq, c_size_t initial_capacity, c_size_t element_size, - int (*compar)(const void*, const void*)); - -void c_MaxPQ_Destroy(c_MaxPQ_t* pq); - -c_err_t c_MaxPQ_Push(c_MaxPQ_t* pq, const void* element); -c_err_t c_MaxPQ_Pop(c_MaxPQ_t* pq, void* output_buffer); -void* c_MaxPQ_Peek(c_MaxPQ_t* pq); -c_err_t c_MaxPQ_Clear(c_MaxPQ_t* pq); -c_err_t c_MaxPQ_Resize(c_MaxPQ_t* pq, c_size_t new_capacity); - -#endif /*INCLUDED_C_MAXPQ_H*/ diff --git a/Sort/c_MergeSort.c b/Sort/c_MergeSort.c deleted file mode 100644 index da73c93..0000000 --- a/Sort/c_MergeSort.c +++ /dev/null @@ -1,54 +0,0 @@ -#include - -/** - * Internal merging routine for top-down merge sort. - */ -C_STATIC_FORCE_INLINE -void c_MergeInternal(char* arr, c_size_t left, c_size_t mid, c_size_t right, - c_size_t size, char* aux, - int (*compar)(const void*, const void*)) { - c_size_t i = left; - c_size_t j = mid + 1; - c_size_t k = left; - - // Copy the target segment into the auxiliary working buffer - memcpy(aux + (left * size), arr + (left * size), (right - left + 1) * size); - - // Merge back into the original array tracking sorted boundaries - while (i <= mid && j <= right) { - if (compar(aux + (i * size), aux + (j * size)) <= 0) { - memcpy(arr + (k * size), aux + (i * size), size); - i++; - } else { - memcpy(arr + (k * size), aux + (j * size), size); - j++; - } - k++; - } - - // Copy any remaining elements of the left sub-array if any - while (i <= mid) { - memcpy(arr + (k * size), aux + (i * size), size); - i++; - k++; - } - // Note: Remaining items on the right side are already natively sitting in the correct slots. -} - -/** - * Recursive structural block splitting segments into halves. - */ -void c_MergeSortSub(char* arr, c_size_t left, c_size_t right, c_size_t size, char* aux, - int (*compar)(const void*, const void*)) { - if (left >= right) return; - - c_size_t mid = left + (right - left) / 2; - - c_MergeSortSub(arr, left, mid, size, aux, compar); - c_MergeSortSub(arr, mid + 1, right, size, aux, compar); - - // Optimization: If the array segment is already naturally sorted, skip the merge routine - if (compar(arr + (mid * size), arr + ((mid + 1) * size)) > 0) { - c_MergeInternal(arr, left, mid, right, size, aux, compar); - } -} diff --git a/Sort/c_MergeSort.h b/Sort/c_MergeSort.h deleted file mode 100644 index 9ae1551..0000000 --- a/Sort/c_MergeSort.h +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef INCLUDED_C_MERGESORT_H -#define INCLUDED_C_MERGESORT_H - -#ifndef INCLUDED_C_TYPES_H -#include -#endif /*INCLUDED_C_TYPES_H*/ - - -#ifndef INCLUDED_C_MEMORY_H -#include -#endif /*INCLUDED_C_MEMORY_H*/ - - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -void c_MergeSortSub(char* arr, c_size_t left, c_size_t right, c_size_t size, char* aux, - int (*compar)(const void*, const void*)); - -/** - * Top-Level Custom Framework Entry Point for Top-Down Merge Sort. - * Time Complexity: O(n log n) | Space Complexity: O(n) | Stable: Yes - */ -C_STATIC_FORCE_INLINE -void c_MergeSort(void* base, c_size_t num, c_size_t size, - int (*compar)(const void*, const void*)) { - if (base == NULL || num < 2 || size == 0) return; - - char* arr = (char*)base; - c_size_t total_bytes = num * size; - - // Optimization: Fallback to stack buffer allocation if overall payload fits locally - #define MERGE_STACK_LIMIT 512 - char stack_buf[MERGE_STACK_LIMIT]; - char* aux = NULL; - - if (total_bytes <= MERGE_STACK_LIMIT) { - aux = stack_buf; - } else { - aux = (char*)C_ALLOC(total_bytes); - if (aux == NULL) return; // Allocation safeguard - } - - // Execute recursive divide-and-conquer strategy - c_MergeSortSub(arr, 0, num - 1, size, aux, compar); - - if (total_bytes > MERGE_STACK_LIMIT) { - C_FREE(aux); - } - #undef MERGE_STACK_LIMIT -} - - -#endif /*INCLUDED_C_MERGESORT_H*/ diff --git a/Sort/c_MergeSortBU.c b/Sort/c_MergeSortBU.c deleted file mode 100644 index a956dc2..0000000 --- a/Sort/c_MergeSortBU.c +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/Sort/c_MergeSortBU.h b/Sort/c_MergeSortBU.h deleted file mode 100644 index fec8875..0000000 --- a/Sort/c_MergeSortBU.h +++ /dev/null @@ -1,98 +0,0 @@ -#ifndef INCLUDED_C_MERGESORTBU_H -#define INCLUDED_C_MERGESORTBU_H - -#ifndef INCLUDED_C_TYPES_H -#include -#endif /*INCLUDED_C_TYPES_H*/ - -#ifndef INCLUDED_C_MEMORY_H -#include -#endif /*INCLUDED_C_MEMORY_H*/ -#include "c_Macros.h" - - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - - -/** - * Internal merging routine for iterative blocks. - * Re-used from the top-down logic to guarantee stability. - */ -C_STATIC_FORCE_INLINE -void c_MergeInternalBU(char* arr, c_size_t left, c_size_t mid, c_size_t right, - c_size_t size, char* aux, - int (*compar)(const void*, const void*)) { - c_size_t i = left; - c_size_t j = mid + 1; - c_size_t k = left; - - // Snapshot target segment into tracking auxiliary zone - memcpy(aux + (left * size), arr + (left * size), (right - left + 1) * size); - - // Merge operational slots back sequentially - while (i <= mid && j <= right) { - if (compar(aux + (i * size), aux + (j * size)) <= 0) { - memcpy(arr + (k * size), aux + (i * size), size); - i++; - } else { - memcpy(arr + (k * size), aux + (j * size), size); - j++; - } - k++; - } - - // Flush remaining items sitting on the left slice - while (i <= mid) { - memcpy(arr + (k * size), aux + (i * size), size); - i++; - k++; - } -} - -/** - * Top-Level Iterative Framework Entry Point for Bottom-Up Merge Sort. - * Time Complexity: O(n log n) | Space Complexity: O(n) | Stable: Yes | Call Stack: O(1) - */ -C_STATIC_FORCE_INLINE -void c_MergeSortBottomUp(void* base, c_size_t num, c_size_t size, - int (*compar)(const void*, const void*)) { - if (base == NULL || num < 2 || size == 0) return; - - char* arr = (char*)base; - c_size_t total_bytes = num * size; - - // Optimization: Fallback to stack buffer allocation if memory payload fits locally - #define MERGE_BU_STACK_LIMIT 512 - char stack_buf[MERGE_BU_STACK_LIMIT]; - char* aux = NULL; - - if (total_bytes <= MERGE_BU_STACK_LIMIT) { - aux = stack_buf; - } else { - aux = (char*)C_ALLOC(total_bytes); - if (aux == NULL) return; - } - - // Step-wise sub-array size doubling loop: 1, 2, 4, 8, 16... - for (c_size_t width = 1; width < num; width *= 2) { - // Iterate through segments by blocks of 2 * width - for (c_size_t left = 0; left < num - width; left += 2 * width) { - c_size_t mid = left + width - 1; - c_size_t right = C_MIN(left + (2 * width) - 1, num - 1); - - // Optimization: Skip merge phase if the adjacent sub-segments are already sequentially sorted - if (compar(arr + (mid * size), arr + ((mid + 1) * size)) > 0) { - c_MergeInternalBU(arr, left, mid, right, size, aux, compar); - } - } - } - - if (total_bytes > MERGE_BU_STACK_LIMIT) { - C_FREE(aux); - } - #undef MERGE_BU_STACK_LIMIT -} - - -#endif /*INCLUDED_C_MERGESORTBU_H*/ diff --git a/Sort/c_MinPQ.c b/Sort/c_MinPQ.c deleted file mode 100644 index 67371e6..0000000 --- a/Sort/c_MinPQ.c +++ /dev/null @@ -1,160 +0,0 @@ -#include -#include - -/** - * Internal helper to swap two memory slots inside the heap array. - */ -C_STATIC_FORCE_INLINE -void c_MinPQ_HeapSwap(char* arr, c_size_t idx1, c_size_t idx2, c_size_t size, void* temp) { - if (idx1 == idx2) return; - char* a = arr + (idx1 * size); - char* b = arr + (idx2 * size); - memcpy(temp, a, size); - memcpy(a, b, size); - memcpy(b, temp, size); -} - -c_err_t c_MinPQ_Init(c_MinPQ_t* pq, c_size_t initial_capacity, c_size_t element_size, - int (*compar)(const void*, const void*)) { - if (pq == NULL || element_size == 0 || compar == NULL) return C_ERR_PARAM; - - pq->capacity = (initial_capacity > 0) ? initial_capacity : 4; - pq->element_size = element_size; - pq->size = 0; - pq->compar = compar; - pq->data = C_ALLOC(pq->capacity * element_size); - - return (pq->data != NULL) ? C_ERR_OK : C_ERR_NOMEM; -} - -void c_MinPQ_Destroy(c_MinPQ_t* pq) { - if (!pq) return; - C_FREE(pq->data); - pq->size = 0; - pq->capacity = 0; -} - -c_err_t c_MinPQ_Clear(c_MinPQ_t* pq) { - if (pq == NULL) return C_ERR_PARAM; - pq->size = 0; - return C_ERR_OK; -} - -c_err_t c_MinPQ_Resize(c_MinPQ_t* pq, c_size_t new_capacity) { - if (pq == NULL || new_capacity < pq->size) return C_ERR_PARAM; - if (new_capacity == pq->capacity) return C_ERR_OK; - - if (new_capacity == 0) { - if (pq->data != NULL) C_FREE(pq->data); - pq->data = NULL; - pq->capacity = 0; - return C_ERR_OK; - } - - void* new_data = C_ALLOC(new_capacity * pq->element_size); - if (new_data == NULL) return C_ERR_NOMEM; - - if (pq->size > 0 && pq->data != NULL) { - memcpy(new_data, pq->data, pq->size * pq->element_size); - } - - if (pq->data != NULL) C_FREE(pq->data); - pq->data = new_data; - pq->capacity = new_capacity; - - return C_ERR_OK; -} - -c_err_t c_MinPQ_Push(c_MinPQ_t* pq, const void* element) { - if (pq == NULL || element == NULL) return C_ERR_PARAM; - - char* arr = (char*)pq->data; - - // Handle dynamic capacity auto-doubling - if (pq->size >= pq->capacity) { - c_err_t err = c_MinPQ_Resize(pq, pq->capacity * 2); - if (err != C_ERR_OK) return err; - arr = (char*)pq->data; - } - - #define PQ_STACK_LIMIT 128 - char stack_buf[PQ_STACK_LIMIT]; - void* temp = (pq->element_size <= PQ_STACK_LIMIT) ? stack_buf : C_ALLOC(pq->element_size); - if (temp == NULL) return C_ERR_NOMEM; - - // Place element at the next available leaf position - c_size_t current = pq->size; - memcpy(arr + (current * pq->element_size), element, pq->element_size); - pq->size++; - - // Sift-Up for Min-Heap: Move up while element < parent - while (current > 0) { - c_size_t parent = (current - 1) / 2; - if (pq->compar(arr + (current * pq->element_size), arr + (parent * pq->element_size)) >= 0) { - break; - } - c_MinPQ_HeapSwap(arr, current, parent, pq->element_size, temp); - current = parent; - } - - if (pq->element_size > PQ_STACK_LIMIT) C_FREE(temp); - #undef PQ_STACK_LIMIT - return C_ERR_OK; -} - -c_err_t c_MinPQ_Pop(c_MinPQ_t* pq, void* output_buffer) { - if (pq == NULL) return C_ERR_PARAM; - if (pq->size == 0) return C_ERR_EMPTY; - - char* arr = (char*)pq->data; - - // Export root minimum element if buffer is provided - if (output_buffer != NULL) { - memcpy(output_buffer, arr, pq->element_size); - } - - pq->size--; - - if (pq->size > 0) { - // Move last leaf to root position - memcpy(arr, arr + (pq->size * pq->element_size), pq->element_size); - - #define PQ_STACK_LIMIT 128 - char stack_buf[PQ_STACK_LIMIT]; - void* temp = (pq->element_size <= PQ_STACK_LIMIT) ? stack_buf : C_ALLOC(pq->element_size); - if (temp == NULL) return C_ERR_NOMEM; - - // Sift-Down for Min-Heap: Swap with the smaller of the two children - c_size_t current = 0; - while (1) { - c_size_t left_child = (2 * current) + 1; - c_size_t right_child = (2 * current) + 2; - c_size_t smallest = current; - - if (left_child < pq->size && - pq->compar(arr + (left_child * pq->element_size), arr + (smallest * pq->element_size)) < 0) { - smallest = left_child; - } - if (right_child < pq->size && - pq->compar(arr + (right_child * pq->element_size), arr + (smallest * pq->element_size)) < 0) { - smallest = right_child; - } - if (smallest == current) { - break; - } - - c_MinPQ_HeapSwap(arr, current, smallest, pq->element_size, temp); - current = smallest; - } - - if (pq->element_size > PQ_STACK_LIMIT) C_FREE(temp); - #undef PQ_STACK_LIMIT - } - - return C_ERR_OK; -} - -void* c_MinPQ_Peek(c_MinPQ_t* pq) { - if (pq == NULL || pq->size == 0) return NULL; - return pq->data; -} diff --git a/Sort/c_MinPQ.h b/Sort/c_MinPQ.h deleted file mode 100644 index 2100633..0000000 --- a/Sort/c_MinPQ.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef INCLUDED_C_MINPQ_H -#define INCLUDED_C_MINPQ_H - -#ifndef INCLUDED_C_TYPES_H -#include -#endif /*INCLUDED_C_TYPES_H*/ - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -typedef struct { - void* data; - c_size_t element_size; - c_size_t capacity; - c_size_t size; - int (*compar)(const void*, const void*); -} c_MinPQ_t; - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -c_err_t c_MinPQ_Init(c_MinPQ_t* pq, c_size_t initial_capacity, c_size_t element_size, - int (*compar)(const void*, const void*)); - -void c_MinPQ_Destroy(c_MinPQ_t* pq); - -c_err_t c_MinPQ_Clear(c_MinPQ_t* pq); -c_err_t c_MinPQ_Resize(c_MinPQ_t* pq, c_size_t new_capacity); - -c_err_t c_MinPQ_Push(c_MinPQ_t* pq, const void* element); -c_err_t c_MinPQ_Pop(c_MinPQ_t* pq, void* output_buffer); -void* c_MinPQ_Peek(c_MinPQ_t* pq); - -#endif /*INCLUDED_C_MINPQ_H*/ diff --git a/Sort/c_QuickSort.c b/Sort/c_QuickSort.c deleted file mode 100644 index 5411fa2..0000000 --- a/Sort/c_QuickSort.c +++ /dev/null @@ -1,84 +0,0 @@ -#include - - -/** - * Internal macro helper to swap two arbitrary blocks of memory of given size. - */ -C_STATIC_FORCE_INLINE -void c_SwapInternal(char* a, char* b, c_size_t size, void* temp) { - if (a == b) return; - memcpy(temp, a, size); - memcpy(a, b, size); - memcpy(b, temp, size); -} - -/** - * Chooses the median of left, center, and right elements as the pivot, - * hides it at (right - 1), and returns a pointer to it. - */ -C_STATIC_FORCE_INLINE -void* c_MedianOfThree(char* arr, long long left, long long right, c_size_t size, - void* temp, int (*compar)(const void*, const void*)) { - long long center = left + (right - left) / 2; - - // Order left, center, right - if (compar(arr + (left * size), arr + (center * size)) > 0) { - c_SwapInternal(arr + (left * size), arr + (center * size), size, temp); - } - if (compar(arr + (left * size), arr + (right * size)) > 0) { - c_SwapInternal(arr + (left * size), arr + (right * size), size, temp); - } - if (compar(arr + (center * size), arr + (right * size)) > 0) { - c_SwapInternal(arr + (center * size), arr + (right * size), size, temp); - } - - // Place pivot at position (right - 1) - c_SwapInternal(arr + (center * size), arr + ((right - 1) * size), size, temp); - return arr + ((right - 1) * size); -} - - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -void c_QuickSortSub(char* arr, long long left, long long right, c_size_t size, void* temp, - int (*compar)(const void*, const void*)) { - // Optimization: Fallback to manual insertion sort for tiny arrays to prune deep recursion - if (left + 10 > right) { - // Basic Inline Insertion Sort boundary loop - for (long long i = left + 1; i <= right; i++) { - memcpy(temp, arr + (i * size), size); - long long j = i; - while (j > left && compar(arr + ((j - 1) * size), temp) > 0) { - memcpy(arr + (j * size), arr + ((j - 1) * size), size); - j--; - } - memcpy(arr + (j * size), temp, size); - } - return; - } - - // Retrieve Median Pivot - c_MedianOfThree(arr, left, right, size, temp, compar); - - long long i = left; - long long j = right - 1; - - // Hoare Partitioning Loop - while (1) { - while (compar(arr + ((++i) * size), arr + ((right - 1) * size)) < 0); - while (compar(arr + ((--j) * size), arr + ((right - 1) * size)) > 0); - if (i < j) { - c_SwapInternal(arr + (i * size), arr + (j * size), size, temp); - } else { - break; - } - } - - // Restore pivot to its correct final slot - c_SwapInternal(arr + (i * size), arr + ((right - 1) * size), size, temp); - - // Recursively execute left and right segments - c_QuickSortSub(arr, left, i - 1, size, temp, compar); - c_QuickSortSub(arr, i + 1, right, size, temp, compar); -} diff --git a/Sort/c_QuickSort.h b/Sort/c_QuickSort.h deleted file mode 100644 index 1456060..0000000 --- a/Sort/c_QuickSort.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef INCLUDED_C_QUICKSORT_H -#define INCLUDED_C_QUICKSORT_H - -#ifndef INCLUDED_C_TYPES_H -#include -#endif /*INCLUDED_C_TYPES_H*/ - -#ifndef INCLUDED_C_MEMORY_H -#include -#endif /*INCLUDED_C_MEMORY_H*/ - - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -/** - * Recursive partitioning sub-routine. - */ - -void c_QuickSortSub(char* arr, long long left, long long right, c_size_t size, void* temp, - int (*compar)(const void*, const void*)); - -/** - * Top-Level Framework Entry Point for Quicksort. - * Time Complexity: O(n log n) average | Space Complexity: O(log n) call stack | Stable: No - */ -C_STATIC_FORCE_INLINE -void c_QuickSort(void* base, c_size_t num, c_size_t size, - int (*compar)(const void*, const void*)) { - if (base == NULL || num < 2 || size == 0) return; - - char* arr = (char*)base; - - // Optimization: Use a local stack buffer if element size fits comfortably - #define QSORT_STACK_LIMIT 128 - char stack_buf[QSORT_STACK_LIMIT]; - void* temp = NULL; - - if (size <= QSORT_STACK_LIMIT) { - temp = stack_buf; - } else { - temp = C_ALLOC(size); - if (temp == NULL) return; - } - - // Invoke processing across signed range bounds safely - c_QuickSortSub(arr, 0, (long long)num - 1, size, temp, compar); - - if (size > QSORT_STACK_LIMIT) { - C_FREE(temp); - } - #undef QSORT_STACK_LIMIT -} - - -#endif /*INCLUDED_C_QUICKSORT_H*/ diff --git a/Sort/c_QuickSortIterative.c b/Sort/c_QuickSortIterative.c deleted file mode 100644 index 8e050e0..0000000 --- a/Sort/c_QuickSortIterative.c +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/Sort/c_QuickSortIterative.h b/Sort/c_QuickSortIterative.h deleted file mode 100644 index 9ddf60c..0000000 --- a/Sort/c_QuickSortIterative.h +++ /dev/null @@ -1,102 +0,0 @@ -#ifndef INCLUDED_C_QUICKSORTITERATIVE_H -#define INCLUDED_C_QUICKSORTITERATIVE_H - -#ifndef INCLUDED_C_TYPES_H -#include -#endif /*INCLUDED_C_TYPES_H*/ - -#ifndef INCLUDED_C_MEMORY_H -#include -#endif /*INCLUDED_C_MEMORY_H*/ - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -/** - * Internal macro helper to swap two arbitrary blocks of memory. - */ -C_STATIC_FORCE_INLINE -void c_SwapInternal(char* a, char* b, c_size_t size, void* temp) { - if (a == b) return; - memcpy(temp, a, size); - memcpy(a, b, size); - memcpy(b, temp, size); -} - -/** - * Standard Lomuto or Hoare-style tracking partition loop. - * Uses the rightmost element as the pivot for flat linear execution. - */ -C_STATIC_FORCE_INLINE -long long c_PartitionIterative(char* arr, long long left, long long right, c_size_t size, - void* temp, int (*compar)(const void*, const void*)) { - char* pivot = arr + (right * size); - long long i = left - 1; - - for (long long j = left; j < right; j++) { - if (compar(arr + (j * size), pivot) <= 0) { - i++; - c_SwapInternal(arr + (i * size), arr + (j * size), size, temp); - } - } - c_SwapInternal(arr + ((i + 1) * size), arr + (right * size), size, temp); - return (i + 1); -} - -/** - * Top-Level Custom Framework Entry Point for Non-Recursive Quicksort. - * Time Complexity: O(n log n) average | Space Complexity: O(log n) explicit stack | Stable: No - */ -C_STATIC_FORCE_INLINE -void c_QuickSortIterative(void* base, c_size_t num, c_size_t size, - int (*compar)(const void*, const void*)) { - if (base == NULL || num < 2 || size == 0) return; - - char* arr = (char*)base; - - // Optimization: Stack buffer allocation for pivot element swaps -#define QSORT_STACK_LIMIT 128 - char stack_buf[QSORT_STACK_LIMIT]; - void* temp = (size <= QSORT_STACK_LIMIT) ? stack_buf : C_ALLOC(size); - if (temp == NULL) return; - - // Allocate the explicit partition boundary stack. - // Max required stack depth for range tracking is 2 * ceil(log2(num)) + 2. - // For a 64-bit address space, 128 slots safely handles any possible array size. - long long range_stack[128]; - long long top = -1; - - // Push initial array boundaries onto the tracking stack - range_stack[++top] = 0; - range_stack[++top] = (long long)num - 1; - - // Keep processing partitions until the explicit boundary stack is empty - while (top >= 0) { - // Pop right and left boundaries - long long right = range_stack[top--]; - long long left = range_stack[top--]; - - // Execute linear pivot segmentation - long long p = c_PartitionIterative(arr, left, right, size, temp, compar); - - // If there are elements on the left side of the pivot, push their range to the stack - if (p - 1 > left) { - range_stack[++top] = left; - range_stack[++top] = p - 1; - } - - // If there are elements on the right side of the pivot, push their range to the stack - if (p + 1 < right) { - range_stack[++top] = p + 1; - range_stack[++top] = right; - } - } - - if (size > QSORT_STACK_LIMIT) { - C_FREE(temp); - } -#undef QSORT_STACK_LIMIT -} - - -#endif /*INCLUDED_C_QUICKSORTITERATIVE_H*/ diff --git a/Sort/c_SelectionSort.c b/Sort/c_SelectionSort.c deleted file mode 100644 index 33a3cd9..0000000 --- a/Sort/c_SelectionSort.c +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/Sort/c_SelectionSort.h b/Sort/c_SelectionSort.h deleted file mode 100644 index c53c403..0000000 --- a/Sort/c_SelectionSort.h +++ /dev/null @@ -1,67 +0,0 @@ -#ifndef INCLUDED_C_SELECTIONSORT_H -#define INCLUDED_C_SELECTIONSORT_H - -#ifndef INCLUDED_C_TYPES_H -#include -#endif /*INCLUDED_C_TYPES_H*/ - -#ifndef INCLUDED_C_MEMORY_H -#include -#endif /*INCLUDED_C_MEMORY_H*/ - - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -/** - * Generic Selection Sort Function - * @param base Pointer to the first element of the array to be sorted - * @param num Number of elements in the array - * @param size Size of each element in bytes - * @param compar Pointer to the comparison function - */ -C_STATIC_FORCE_INLINE -void c_SelectionSort(void* base, c_size_t num, c_size_t size, - int (*compar)(const void*, const void*)) { - // Avoid execution if array is empty or has only one element - if (base == NULL || num < 2 || size == 0) return; - - char* arr = (char*)base; - - // OPTIMIZATION: Use stack allocation for small element sizes - // to bypass heap overhead completely during force-inlining. -#define STACK_LIMIT 128 - char stack_buf[STACK_LIMIT]; - void* temp = NULL; - - if (size <= STACK_LIMIT) { - temp = stack_buf; - } else { - temp = C_ALLOC(size); - if (temp == NULL) return; - } - - for (c_size_t i = 0; i < num - 1; i++) { - c_size_t minIndex = i; - - for (c_size_t j = i + 1; j < num; j++) { - if (compar(arr + (j * size), arr + (minIndex * size)) < 0) { - minIndex = j; - } - } - - if (minIndex != i) { - memcpy(temp, arr + (i * size), size); - memcpy(arr + (i * size), arr + (minIndex * size), size); - memcpy(arr + (minIndex * size), temp, size); - } - } - - // Only trigger free if it was actually allocated from the heap - if (size > STACK_LIMIT) { - C_FREE(temp); - } -#undef STACK_LIMIT -} - -#endif /*INCLUDED_C_SELECTIONSORT_H*/ diff --git a/Sort/c_ShellSort.c b/Sort/c_ShellSort.c deleted file mode 100644 index f8dbcc3..0000000 --- a/Sort/c_ShellSort.c +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/Sort/c_ShellSort.h b/Sort/c_ShellSort.h deleted file mode 100644 index 4ce5e5b..0000000 --- a/Sort/c_ShellSort.h +++ /dev/null @@ -1,71 +0,0 @@ -#ifndef INCLUDED_C_SHELLSORT_H -#define INCLUDED_C_SHELLSORT_H - -#ifndef INCLUDED_C_TYPES_H -#include -#endif /*INCLUDED_C_TYPES_H*/ - -#ifndef INCLUDED_C_MEMORY_H -#include -#endif /*INCLUDED_C_MEMORY_H*/ - - -/* ------------------------------------------------------------------------------------------------------------------ */ -/* */ - -C_STATIC_FORCE_INLINE -void c_ShellSort(void* base, c_size_t num, c_size_t size, - int (*compar)(const void*, const void*)) { - if (base == NULL || num < 2 || size == 0) return; - - char* arr = (char*)base; - - // Stack optimization for memory swap space -#define STACK_LIMIT 128 - char stack_buf[STACK_LIMIT]; - void* temp = NULL; - - if (size <= STACK_LIMIT) { - temp = stack_buf; - } else { - temp = C_ALLOC(size); - if (temp == NULL) return; - } - - // Using Knuth's gap sequence: h = h * 3 + 1 (1, 4, 13, 40, 121, ...) - c_size_t gap = 1; - while (gap < num / 3) { - gap = gap * 3 + 1; - } - - // Start with the largest gap and work down to a gap of 1 - while (gap > 0) { - for (c_size_t i = gap; i < num; i++) { - // temp = arr[i] - memcpy(temp, arr + (i * size), size); - - c_size_t j = i; - - // Shift elements of the gap-sorted variant until the correct position is found - // Loop guards prevent underflow on unsigned c_size_t subtraction (j >= gap) - while (j >= gap && compar(arr + ((j - gap) * size), temp) > 0) { - // arr[j] = arr[j - gap] - memcpy(arr + (j * size), arr + ((j - gap) * size), size); - j -= gap; - } - - // arr[j] = temp - memcpy(arr + (j * size), temp, size); - } - // Reduce the gap - gap /= 3; - } - - if (size > STACK_LIMIT) { - C_FREE(temp); - } -#undef STACK_LIMIT -} - - -#endif /*INCLUDED_C_SHELLSORT_H*/