124 lines
3.8 KiB
C
124 lines
3.8 KiB
C
#include <c_PtrBag.h>
|
|||
|
|
|
||
|
|
#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;
|
||
|
|
}
|
||
|
|
|