diff --git a/README.md b/README.md index 2ddc384..b2ab87f 100644 --- a/README.md +++ b/README.md @@ -21,22 +21,27 @@ ```mermaid flowchart TB subgraph low + ringbuf[ringbuf
小数据或尽量不扩容] + rawbuf + darray linklist dlinklist - ringbuffer[ringbuffer
小数据或尽量不扩容] end subgraph hal - segarray[segarray
大数据扩容优先] --> darray + segarray[segarray
大数据扩容优先] + + segarray -.-> ringbuf + segarray -.-> rawbuf + string --> darray hashtable --> darray end subgraph adapter - deque -->|仅学习| dlinklist deque ==> segarray - deque --> ringbuffer + deque --> ringbuf end subgraph top @@ -51,8 +56,8 @@ flowchart TB end subgraph embed - estack --> ringbuffer - equeue --> ringbuffer + estack --> ringbuf + equeue --> ringbuf end ``` @@ -62,9 +67,11 @@ flowchart TB |数据结构 |名称 |说明 | |---|---|---| | darray | 动态数组 | 扩容 -| ringbuf | 环形缓存区 | 扩容/固定容量 +| ringbuf | 环形缓存区 | 扩容/外部缓存 | linlist | 单链表 | | dlinlist | 双向链表 | +| rawbuf | 原始缓冲区 | 动态分配固定容量/外部缓存 +| segarray | 分段数组 | 扩容 ### 容器结构 |数据结构 |名称 |说明 | @@ -76,8 +83,8 @@ flowchart TB ### 嵌入式结构 |数据结构 |名称 |说明 | |---|---|---| -| estack | 栈 | 固定容量 -| equeue | 队列 | 固定容量 +| estack | 栈 | 外部缓存 +| equeue | 队列 | 外部缓存 ## 接口函数原型 @@ -86,7 +93,7 @@ flowchart TB struct* new(size_t obj_size, size_t capacity); // 创建 void free(struct**); // 释放 -bool init(size_t obj_size, size_t capacity, void *mem_pool); // 静态初始化,支持传入内存池,不扩容 +bool init(size_t obj_size, size_t capacity, void *mem_base); // 静态初始化,支持传入外部缓存 // 外部实现 int compare(void* obj1, void* obj2); // 比较函数,若调用了和比较有关的接口,需要在初始化后配置(树、图必须) diff --git a/doc/notes.md b/doc/notes.md index 9520494..2f28351 100644 --- a/doc/notes.md +++ b/doc/notes.md @@ -1,8 +1,11 @@ # notes -## segarray +## rawbuf +> 只对malloc封装,方便对特定目标进行index访问 +- 特点:支持随机访问,不支持扩容 +## segarray 1. 扩容方案1 ``` if map.full diff --git a/include/rawbuf.h b/include/rawbuf.h new file mode 100644 index 0000000..68c74f9 --- /dev/null +++ b/include/rawbuf.h @@ -0,0 +1,43 @@ +/** + * @file rawbuf.c + * @author wenjf (orig5826@163.com) + * @brief + * @version 0.1 + * @date 2026-05-15 + * + * @copyright Copyright (c) 2026 + * + */ +#ifndef _RAWBUF_H_ +#define _RAWBUF_H_ + +#include "unicstl_internal.h" + +struct _rawbuf +{ + // -------------------- private -------------------- + void *obj; + size_t _obj_size; + size_t _capacity; + bool _dynamic; + + void (*_destory)(struct _rawbuf *self); + // -------------------- public -------------------- + // kernel -> random access + bool (*set)(struct _rawbuf *self, size_t index, const void *obj); // O(1) + bool (*get)(struct _rawbuf *self, size_t index, void *obj); // O(1) + const void* (*at)(struct _rawbuf *self, size_t index); // O(1) + + // base + size_t (*capacity)(struct _rawbuf *self); +}; +typedef struct _rawbuf *rawbuf_t; + +rawbuf_t rawbuf_new(size_t obj_size, size_t capacity); +void rawbuf_free(rawbuf_t *rawbuf); + +#ifdef UNICSTL_STATIC_MEMORY +bool rawbuf_init(struct _rawbuf *self, size_t obj_size, size_t capacity, void *mem_base); +#endif + +#endif diff --git a/include/ringbuf.h b/include/ringbuf.h index 07cc787..b474223 100644 --- a/include/ringbuf.h +++ b/include/ringbuf.h @@ -70,7 +70,7 @@ ringbuf_t ringbuf_new(size_t obj_size, size_t capacity); void ringbuf_free(ringbuf_t* ringbuf); #ifdef UNICSTL_STATIC_MEMORY -bool ringbuf_init(struct _ringbuf *self, size_t obj_size, size_t capacity, void *mem_pool); +bool ringbuf_init(struct _ringbuf *self, size_t obj_size, size_t capacity, void *mem_base); #endif #endif diff --git a/include/unicstl.h b/include/unicstl.h index 7a45756..5176af6 100644 --- a/include/unicstl.h +++ b/include/unicstl.h @@ -22,6 +22,7 @@ #include "linklist.h" #include "dlinklist.h" #include "ringbuf.h" +#include "rawbuf.h" #include "segarray.h" diff --git a/src/rawbuf.c b/src/rawbuf.c new file mode 100644 index 0000000..41589d2 --- /dev/null +++ b/src/rawbuf.c @@ -0,0 +1,129 @@ +/** + * @file rawbuf.c + * @author wenjf (orig5826@163.com) + * @brief + * @version 0.1 + * @date 2026-05-15 + * + * @copyright Copyright (c) 2026 + * + */ +#include "rawbuf.h" + +static size_t rawbuf_capacity(struct _rawbuf *self) +{ + unicstl_assert(self != NULL); + return self->_capacity; +} + +static bool rawbuf_set(struct _rawbuf *self, size_t index, const void *obj) +{ + unicstl_assert(self != NULL); + if (index >= self->capacity(self) || obj == NULL) + { + return false; + } + size_t offset = index * self->_obj_size; + memmove((char *)self->obj + offset, obj, self->_obj_size); + return true; +} + +static bool rawbuf_get(struct _rawbuf *self, size_t index, void *obj) +{ + unicstl_assert(self != NULL); + if (index >= self->capacity(self) || obj == NULL) + { + return false; + } + size_t offset = index * self->_obj_size; + memmove(obj, (char *)self->obj + offset, self->_obj_size); + return true; +} + +const void *rawbuf_at(struct _rawbuf *self, size_t index) +{ + unicstl_assert(self != NULL); + if (index >= self->capacity(self)) + { + return false; + } + size_t offset = index * self->_obj_size; + return (const char *)self->obj + offset; +} + +static void rawbuf_destory(struct _rawbuf *self) +{ + unicstl_assert(self != NULL); + if (self->obj != NULL && self->_dynamic == true) + { + free(self->obj); + } +} + +bool rawbuf_init(struct _rawbuf *self, size_t obj_size, size_t capacity, void *mem_base) +{ + unicstl_assert(self != NULL); + unicstl_assert(obj_size > 0); + if(capacity == 0) + { + return false; + } + + // -------------------- private -------------------- + self->_obj_size = obj_size; + self->_capacity = capacity; + + self->obj = mem_base; + self->_dynamic = false; + + self->_destory = rawbuf_destory; + // -------------------- public -------------------- + // kernel + self->set = rawbuf_set; + self->get = rawbuf_get; + self->at = rawbuf_at; + + self->capacity = rawbuf_capacity; + + // -------------------- malloc -------------------- + if(self->obj == NULL) + { + self->obj = unicstl_malloc(capacity * obj_size); + if (self->obj == NULL) + { + return false; + } + self->_dynamic = true; + } + return true; +} + +rawbuf_t rawbuf_new(size_t obj_size, size_t capacity) +{ + struct _rawbuf *rawbuf = NULL; + rawbuf = (struct _rawbuf *)unicstl_malloc(sizeof(struct _rawbuf)); + if (rawbuf == NULL) + { + return NULL; + } + + if (rawbuf_init(rawbuf, obj_size, capacity, NULL) != true) + { + free(rawbuf); + return NULL; + } + return rawbuf; +} + +void rawbuf_free(rawbuf_t *rawbuf) +{ + if (rawbuf != NULL && *rawbuf != NULL) + { + if ((*rawbuf)->_destory != NULL) + { + (*rawbuf)->_destory((*rawbuf)); + } + free(*rawbuf); + *rawbuf = NULL; + } +} diff --git a/src/ringbuf.c b/src/ringbuf.c index c01a31f..f30e323 100644 --- a/src/ringbuf.c +++ b/src/ringbuf.c @@ -366,7 +366,7 @@ iterator_t ringbuf_iter(struct _ringbuf *self, enum _ringbuf_order order) * @return true * @return false */ -bool ringbuf_init(struct _ringbuf *self, size_t obj_size, size_t capacity, void *mem_pool) +bool ringbuf_init(struct _ringbuf *self, size_t obj_size, size_t capacity, void *mem_base) { unicstl_assert(self != NULL); unicstl_assert(obj_size > 0); @@ -376,20 +376,8 @@ bool ringbuf_init(struct _ringbuf *self, size_t obj_size, size_t capacity, void self->_size = 0; self->_capacity = capacity + 1; - if (mem_pool != NULL) - { - self->obj = (char *)mem_pool; - self->_dynamic = false; - } - else - { - self->obj = (char *)unicstl_malloc(self->_obj_size * self->_capacity); - if (self->obj == NULL) - { - return false; - } - self->_dynamic = true; - } + self->obj = mem_base; + self->_dynamic = false; self->_head = 0; self->_tail = 0; @@ -427,6 +415,16 @@ bool ringbuf_init(struct _ringbuf *self, size_t obj_size, size_t capacity, void // -------------------- debug -------------------- self->print = ringbuf_print; + // -------------------- malloc -------------------- + if (mem_base == NULL) + { + self->obj = (char *)unicstl_malloc(self->_obj_size * self->_capacity); + if (self->obj == NULL) + { + return false; + } + self->_dynamic = true; + } return true; } diff --git a/test/test.c b/test/test.c index 847e542..fbf62c1 100644 --- a/test/test.c +++ b/test/test.c @@ -95,7 +95,8 @@ int main(int argc, char const *argv[]) TEST_ADD(test_tree); TEST_ADD(test_graph); - TEST_ADD(test_segarray); + TEST_ADD(test_rawbuf); + // TEST_ADD(test_segarray); return UNITY_END(); } diff --git a/test/test.h b/test/test.h index 14611f3..d2fbca0 100644 --- a/test/test.h +++ b/test/test.h @@ -47,10 +47,10 @@ void test_unicstl(void); void test_darray(void); void test_linklist(void); void test_dlinklist(void); -void test_segarray(void); - void test_ringbuf(void); +void test_rawbuf(void); +void test_segarray(void); void test_deque(void); void test_queue(void); diff --git a/test/test_rawbuf.c b/test/test_rawbuf.c new file mode 100644 index 0000000..d7380bc --- /dev/null +++ b/test/test_rawbuf.c @@ -0,0 +1,204 @@ +/** + * @file test_rawbuf.c + * @author wenjf (orig5826@163.com) + * @brief + * @version 0.1 + * @date 2026-05-15 + * + * @copyright Copyright (c) 2026 + * + */ +#include "test.h" + +static void test_rawbuf_new(void) +{ + // if obj_size must > 0, illegal. so no test case. + + rawbuf_t rawbuf = rawbuf_new(sizeof(int), 10); + TEST_ASSERT_NOT_NULL(rawbuf); + rawbuf_free(&rawbuf); + TEST_ASSERT_NULL(rawbuf); +} + +static void test_rawbuf_new_invalid(void) +{ + rawbuf_t rawbuf = rawbuf_new(sizeof(int), 0); + TEST_ASSERT_NULL(rawbuf); +} + +#ifdef UNICSTL_STATIC_MEMORY +static void test_rawbuf_init(void) +{ + size_t i = 0; + const size_t len = 10; + + int data[10]; + int temp = 0; + + struct _rawbuf rawbuf; + TEST_ASSERT_TRUE(rawbuf_init(&rawbuf, sizeof(int), len, data)); + for (i = 0; i < len; i++) + { + size_t index = len - 1 - i; + TEST_ASSERT_TRUE(rawbuf.set(&rawbuf, index, &data[i])); + + TEST_ASSERT_TRUE(rawbuf.get((rawbuf_t)&rawbuf, index, &temp)); + TEST_ASSERT_EQUAL_INT(data[i], temp); + } + TEST_ASSERT_TRUE(rawbuf.set(&rawbuf, 0, &data[0])); +} +#endif + +static void test_rawbuf_set(void) +{ + int temp = 0; + int data[] = { 1,2,3,4,5,6,7,8,9,10 }; + size_t len = sizeof(data) / sizeof(data[0]); + size_t i = 0; + + rawbuf_t rawbuf = rawbuf_new(sizeof(int), len); + + // set from start to end + for(i = 0; i < len; i++) + { + TEST_ASSERT_TRUE(rawbuf->set(rawbuf, i, &data[i])); + + TEST_ASSERT_TRUE(rawbuf->get(rawbuf, i, &temp)); + TEST_ASSERT_EQUAL_INT(data[i], temp); + } + + temp = 0x11; + TEST_ASSERT_TRUE(rawbuf->set(rawbuf, 0, &temp)); + temp = 0x22; + TEST_ASSERT_TRUE(rawbuf->set(rawbuf, 5, &temp)); + temp = 0x33; + TEST_ASSERT_TRUE(rawbuf->set(rawbuf, 9, &temp)); + + TEST_ASSERT_TRUE(rawbuf->get(rawbuf, 0, &temp)); + TEST_ASSERT_EQUAL_INT(0x11, temp); + TEST_ASSERT_TRUE(rawbuf->get(rawbuf, 5, &temp)); + TEST_ASSERT_EQUAL_INT(0x22, temp); + TEST_ASSERT_TRUE(rawbuf->get(rawbuf, 9, &temp)); + TEST_ASSERT_EQUAL_INT(0x33, temp); + + rawbuf_free(&rawbuf); +} + +static void test_rawbuf_set_invalid(void) +{ + int temp = 0; + int data[] = { 1,2,3,4,5,6,7,8,9,10 }; + size_t len = sizeof(data) / sizeof(data[0]); + size_t i = 0; + + rawbuf_t rawbuf = rawbuf_new(sizeof(int), len); + for(i = 0; i < len; i++) + { + rawbuf->set(rawbuf, i, &data[i]); + } + + // ---------- invalid index ---------- + temp = 0x11; + TEST_ASSERT_FALSE(rawbuf->set(rawbuf, -1, &temp)); + TEST_ASSERT_FALSE(rawbuf->set(rawbuf, len, &temp)); + TEST_ASSERT_FALSE(rawbuf->set(rawbuf, 999, &temp)); + + TEST_ASSERT_FALSE(rawbuf->set(rawbuf, 0, NULL)); + + rawbuf_free(&rawbuf); +} + +static void test_rawbuf_at(void) +{ + int temp = 0; + int data[] = { 1,2,3,4,5,6,7,8,9,10 }; + size_t len = sizeof(data) / sizeof(data[0]); + size_t i = 0; + + rawbuf_t rawbuf = rawbuf_new(sizeof(int), len); + for(i = 0; i < len; i++) + { + rawbuf->set(rawbuf, i, &data[i]); + } + + const int *p_int = NULL; + p_int = rawbuf->at(rawbuf, 0); + TEST_ASSERT_EQUAL_INT(1, *p_int); + + p_int = rawbuf->at(rawbuf, 4); + TEST_ASSERT_EQUAL_INT(5, *p_int); + + p_int = rawbuf->at(rawbuf, 9); + TEST_ASSERT_EQUAL_INT(10, *p_int); + + TEST_ASSERT_NULL(rawbuf->at(rawbuf, 10)); + TEST_ASSERT_NULL(rawbuf->at(rawbuf, -1)); + + + // warning: initialization discards 'const' qualifier from pointer target type + // int *p_int_warring = rawbuf->at(rawbuf, 0); + + // !!! you should not do this. + int *p_int_warring = (int *)rawbuf->at(rawbuf, 0); + *p_int_warring = 100; + + rawbuf->get(rawbuf, 0, &temp); + TEST_ASSERT_EQUAL_INT(100, temp); + + rawbuf_free(&rawbuf); +} + +static void test_rawbuf_struct(void) +{ + size_t i = 0; + struct _student data[] = { + "zhao", 1001, "qian", 1002, "sun", 1003, "li", 1004, + "zhou", 1005, "wu", 1006, "zheng", 1007, "wang", 1008, + "feng", 1009, "cheng",1010, + }; + struct _student temp = {0}; + size_t len = sizeof(data) / sizeof(data[0]); + + rawbuf_t rawbuf = rawbuf_new(sizeof(struct _student), len); + TEST_ASSERT_NOT_NULL(rawbuf); + TEST_ASSERT_EQUAL_INT(len, rawbuf->capacity(rawbuf)); + + // set from end to start + for (i = 0; i < len; i++) + { + size_t index = len-1-i; + TEST_ASSERT_TRUE(rawbuf->set(rawbuf, index, &data[i])); + + TEST_ASSERT_TRUE(rawbuf->get(rawbuf, index, &temp)); + TEST_ASSERT_EQUAL_INT(data[i].id, temp.id); + TEST_ASSERT_EQUAL_STRING(data[i].name, temp.name); + } + for (i = 0; i < len; i++) + { + size_t index = len-1-i; + TEST_ASSERT_TRUE(rawbuf->get(rawbuf, i, &temp)); + TEST_ASSERT_EQUAL_INT(data[index].id, temp.id); + TEST_ASSERT_EQUAL_STRING(data[index].name, temp.name); + } + rawbuf_free(&rawbuf); + TEST_ASSERT_NULL(rawbuf); +} + +void test_rawbuf(void) +{ + UnitySetTestFile(__FILE__); + + // ---------- kernel ---------- + RUN_TEST(test_rawbuf_new); + RUN_TEST(test_rawbuf_new_invalid); + + RUN_TEST(test_rawbuf_init); + + RUN_TEST(test_rawbuf_set); + RUN_TEST(test_rawbuf_set_invalid); + + RUN_TEST(test_rawbuf_at); + + // ---------- ext ---------- + RUN_TEST(test_rawbuf_struct); +} diff --git a/test/test_segarray.c b/test/test_segarray.c index 3cbe357..0925321 100644 --- a/test/test_segarray.c +++ b/test/test_segarray.c @@ -841,8 +841,8 @@ void test_segarray(void) // RUN_TEST(test_segarray_init); // #endif - RUN_TEST(test_segarray_push_back); - RUN_TEST(test_segarray_push_back_invalid); + // RUN_TEST(test_segarray_push_back); + // RUN_TEST(test_segarray_push_back_invalid); // RUN_TEST(test_segarray_push_front); // RUN_TEST(test_segarray_push_front_invalid);