From d6a6bacbb0e2e0319a0ccb65568dbd32b2dc96f0 Mon Sep 17 00:00:00 2001 From: wjf-hs Date: Fri, 15 May 2026 10:34:25 +0800 Subject: [PATCH] ringbuf: add random access --- include/darray.h | 12 ++--- include/ringbuf.h | 5 ++ src/ringbuf.c | 51 ++++++++++++++++++++ test/test_darray.c | 87 +++++++++++++++++---------------- test/test_ringbuf.c | 114 +++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 217 insertions(+), 52 deletions(-) diff --git a/include/darray.h b/include/darray.h index d00107c..233798a 100644 --- a/include/darray.h +++ b/include/darray.h @@ -39,13 +39,13 @@ struct _darray bool (*append)(struct _darray *self, const void *obj); // O(1) bool (*pop)(struct _darray *self, void *obj); // O(1) - bool (*insert)(struct _darray *self, size_t index, const void *obj); // O(n) - bool (*remove)(struct _darray *self, size_t index, void *obj); // O(n) + bool (*insert)(struct _darray *self, size_t index, const void *obj); // O(n) + bool (*remove)(struct _darray *self, size_t index, void *obj); // O(n) - bool (*set)(struct _darray *self, size_t index, const void *obj); // O(1) - bool (*get)(struct _darray *self, size_t index, void *obj); // O(1) - - const void* (*at)(struct _darray *self, size_t index); // O(1) + // -------------------- random access -------------------- + bool (*set)(struct _darray *self, size_t index, const void *obj); // O(1) + bool (*get)(struct _darray *self, size_t index, void *obj); // O(1) + const void* (*at)(struct _darray *self, size_t index); // O(1) // base bool (*resize)(struct _darray *self, size_t capacity); diff --git a/include/ringbuf.h b/include/ringbuf.h index 7ca5729..07cc787 100644 --- a/include/ringbuf.h +++ b/include/ringbuf.h @@ -43,6 +43,11 @@ struct _ringbuf bool (*pop_front)(struct _ringbuf* self, void* obj); bool (*back)(struct _ringbuf* self, void* obj); bool (*front)(struct _ringbuf* self, void* obj); + + // -------------------- random access -------------------- + bool (*set)(struct _ringbuf *self, size_t index, const void *obj); // O(1) + bool (*get)(struct _ringbuf *self, size_t index, void *obj); // O(1) + const void* (*at)(struct _ringbuf *self, size_t index); // O(1) // base bool (*resize)(struct _ringbuf *self, size_t capacity); diff --git a/src/ringbuf.c b/src/ringbuf.c index 73277a8..9d94bbf 100644 --- a/src/ringbuf.c +++ b/src/ringbuf.c @@ -20,6 +20,11 @@ static inline size_t index_prev(size_t index, size_t capacity) return index == 0 ? (capacity - 1) : index - 1; } +static inline size_t ring_index(size_t head, size_t index, size_t capacity) +{ + return (head + index) % capacity; +} + static bool ringbuf_push_back(struct _ringbuf *self, const void *obj) { unicstl_assert(self != NULL); @@ -143,6 +148,47 @@ static bool ringbuf_front(struct _ringbuf *self, void *obj) return true; } +static bool ringbuf_set(struct _ringbuf *self, size_t index, const void *obj) +{ + unicstl_assert(self != NULL); + if (index >= self->size(self) || obj == NULL) + { + return false; + } + index = ring_index(self->_head, index, self->_capacity); + + size_t offset = index * self->_obj_size; + memmove((char *)self->obj + offset, obj, self->_obj_size); + return true; +} + +static bool ringbuf_get(struct _ringbuf *self, size_t index, void *obj) +{ + unicstl_assert(self != NULL); + if (index >= self->size(self) || obj == NULL) + { + return false; + } + index = ring_index(self->_head, index, self->_capacity); + + size_t offset = index * self->_obj_size; + memmove(obj, (char *)self->obj + offset, self->_obj_size); + return true; +} + +static const void* ringbuf_at(struct _ringbuf *self, size_t index) +{ + unicstl_assert(self != NULL); + if (index >= self->size(self)) + { + return false; + } + index = ring_index(self->_head, index, self->_capacity); + + size_t offset = index * self->_obj_size; + return (const char *)self->obj + offset; +} + static bool ringbuf_resize(struct _ringbuf *self, size_t capacity) { unicstl_assert(self != NULL); @@ -374,6 +420,11 @@ bool ringbuf_init(struct _ringbuf *self, size_t obj_size, size_t capacity, void self->back = ringbuf_back; self->front = ringbuf_front; + // random access + self->get = ringbuf_get; + self->set = ringbuf_set; + self->at = ringbuf_at; + // base self->resize = ringbuf_resize; self->size = ringbuf_size; diff --git a/test/test_darray.c b/test/test_darray.c index f366bac..78f9bb7 100644 --- a/test/test_darray.c +++ b/test/test_darray.c @@ -280,6 +280,47 @@ static void test_darray_set_invalid(void) darray_free(&darray); } +static void test_darray_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; + + darray_t darray = darray_new(sizeof(int), len); + darray->compare = compare_num; + for(i = 0; i < len; i++) + { + darray->append(darray, &data[i]); + } + + const int *p_int = NULL; + p_int = darray->at(darray, 0); + TEST_ASSERT_EQUAL_INT(1, *p_int); + + p_int = darray->at(darray, 4); + TEST_ASSERT_EQUAL_INT(5, *p_int); + + p_int = darray->at(darray, 9); + TEST_ASSERT_EQUAL_INT(10, *p_int); + + TEST_ASSERT_NULL(darray->at(darray, 10)); + TEST_ASSERT_NULL(darray->at(darray, -1)); + + + // warning: initialization discards 'const' qualifier from pointer target type + // int *p_int_warring = darray->at(darray, 0); + + // !!! you should not do this. + int *p_int_warring = (int *)darray->at(darray, 0); + *p_int_warring = 100; + + darray->get(darray, 0, &temp); + TEST_ASSERT_EQUAL_INT(100, temp); + + darray_free(&darray); +} + static void test_darray_resize(void) { int temp = 0; @@ -397,48 +438,6 @@ static void test_darray_index_invalid(void) darray_free(&darray); } - -static void test_darray_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; - - darray_t darray = darray_new(sizeof(int), len); - darray->compare = compare_num; - for(i = 0; i < len; i++) - { - darray->append(darray, &data[i]); - } - - const int *p_int = NULL; - p_int = darray->at(darray, 0); - TEST_ASSERT_EQUAL_INT(1, *p_int); - - p_int = darray->at(darray, 4); - TEST_ASSERT_EQUAL_INT(5, *p_int); - - p_int = darray->at(darray, 9); - TEST_ASSERT_EQUAL_INT(10, *p_int); - - TEST_ASSERT_NULL(darray->at(darray, 10)); - TEST_ASSERT_NULL(darray->at(darray, -1)); - - - // warning: initialization discards 'const' qualifier from pointer target type - // int *p_int_warring = darray->at(darray, 0); - - // !!! you should not do this. - int *p_int_warring = (int *)darray->at(darray, 0); - *p_int_warring = 100; - - darray->get(darray, 0, &temp); - TEST_ASSERT_EQUAL_INT(100, temp); - - darray_free(&darray); -} - static void test_darray_dynamic(void) { int temp = 0; @@ -688,14 +687,14 @@ void test_darray(void) RUN_TEST(test_darray_set); RUN_TEST(test_darray_set_invalid); + RUN_TEST(test_darray_at); + RUN_TEST(test_darray_resize); RUN_TEST(test_darray_resize_invalid); RUN_TEST(test_darray_index); // index, search, contains RUN_TEST(test_darray_index_invalid); - RUN_TEST(test_darray_at); - RUN_TEST(test_darray_dynamic); RUN_TEST(test_darray_iter); diff --git a/test/test_ringbuf.c b/test/test_ringbuf.c index 57872c0..e4b30db 100644 --- a/test/test_ringbuf.c +++ b/test/test_ringbuf.c @@ -373,6 +373,110 @@ static void test_ringbuf_front_invalid(void) ringbuf_free(&ringbuf); } + +static void test_ringbuf_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; + + ringbuf_t ringbuf = ringbuf_new(sizeof(int), len); + // ringbuf->compare = compare_num; + + for(i = 0; i < len; i++) + { + TEST_ASSERT_TRUE(ringbuf->push_back(ringbuf, &data[i])); + TEST_ASSERT_EQUAL_INT(i + 1, ringbuf->size(ringbuf)); + + size_t index = ringbuf->size(ringbuf) - 1; + TEST_ASSERT_TRUE(ringbuf->get(ringbuf, index, &temp)); + TEST_ASSERT_EQUAL_INT(data[i], temp); + } + + temp = 0x11; + TEST_ASSERT_TRUE(ringbuf->set(ringbuf, 0, &temp)); + temp = 0x22; + TEST_ASSERT_TRUE(ringbuf->set(ringbuf, 5, &temp)); + temp = 0x33; + TEST_ASSERT_TRUE(ringbuf->set(ringbuf, 9, &temp)); + + TEST_ASSERT_TRUE(ringbuf->get(ringbuf, 0, &temp)); + TEST_ASSERT_EQUAL_INT(0x11, temp); + TEST_ASSERT_TRUE(ringbuf->get(ringbuf, 5, &temp)); + TEST_ASSERT_EQUAL_INT(0x22, temp); + TEST_ASSERT_TRUE(ringbuf->get(ringbuf, 9, &temp)); + TEST_ASSERT_EQUAL_INT(0x33, temp); + + ringbuf_free(&ringbuf); +} + +static void test_ringbuf_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; + + ringbuf_t ringbuf = ringbuf_new(sizeof(int), len); + // ringbuf->compare = compare_num; + + for(i = 0; i < len; i++) + { + ringbuf->push_back(ringbuf, &data[i]); + } + + // ---------- invalid index ---------- + temp = 0x11; + TEST_ASSERT_FALSE(ringbuf->set(ringbuf, -1, &temp)); + TEST_ASSERT_FALSE(ringbuf->set(ringbuf, len, &temp)); + TEST_ASSERT_FALSE(ringbuf->set(ringbuf, 999, &temp)); + + TEST_ASSERT_FALSE(ringbuf->set(ringbuf, 0, NULL)); + + ringbuf_free(&ringbuf); +} + +static void test_ringbuf_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; + + ringbuf_t ringbuf = ringbuf_new(sizeof(int), len); + // ringbuf->compare = compare_num; + for(i = 0; i < len; i++) + { + ringbuf->push_back(ringbuf, &data[i]); + } + + const int *p_int = NULL; + p_int = ringbuf->at(ringbuf, 0); + TEST_ASSERT_EQUAL_INT(1, *p_int); + + p_int = ringbuf->at(ringbuf, 4); + TEST_ASSERT_EQUAL_INT(5, *p_int); + + p_int = ringbuf->at(ringbuf, 9); + TEST_ASSERT_EQUAL_INT(10, *p_int); + + TEST_ASSERT_NULL(ringbuf->at(ringbuf, 10)); + TEST_ASSERT_NULL(ringbuf->at(ringbuf, -1)); + + // warning: initialization discards 'const' qualifier from pointer target type + // int *p_int_warring = ringbuf->at(ringbuf, 0); + + // !!! you should not do this. + int *p_int_warring = (int *)ringbuf->at(ringbuf, 0); + *p_int_warring = 100; + + ringbuf->get(ringbuf, 0, &temp); + TEST_ASSERT_EQUAL_INT(100, temp); + + ringbuf_free(&ringbuf); +} + static void test_ringbuf_iter(void) { size_t i = 0; @@ -750,6 +854,13 @@ void test_ringbuf(void) RUN_TEST(test_ringbuf_front); RUN_TEST(test_ringbuf_front_invalid); + // ---------- random access ---------- + RUN_TEST(test_ringbuf_set); + RUN_TEST(test_ringbuf_set_invalid); + + RUN_TEST(test_ringbuf_at); + + // ---------- base ---------- RUN_TEST(test_ringbuf_iter); RUN_TEST(test_ringbuf_resize); @@ -758,9 +869,8 @@ void test_ringbuf(void) RUN_TEST(test_ringbuf_dynamic); - // ---------- base ---------- RUN_TEST(test_ringbuf_status); - + // ---------- ext ---------- RUN_TEST(test_ringbuf_struct); }