ringbuf: add random access

This commit is contained in:
建峰 2026-05-15 10:34:25 +08:00
parent dcce634326
commit d6a6bacbb0
5 changed files with 217 additions and 52 deletions

View File

@ -42,9 +42,9 @@ struct _darray
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)
// -------------------- 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

View File

@ -44,6 +44,11 @@ struct _ringbuf
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);
size_t (*size)(struct _ringbuf* self);

View File

@ -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;

View File

@ -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);

View File

@ -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,7 +869,6 @@ void test_ringbuf(void)
RUN_TEST(test_ringbuf_dynamic);
// ---------- base ----------
RUN_TEST(test_ringbuf_status);
// ---------- ext ----------