214 lines
5.2 KiB
C
214 lines
5.2 KiB
C
/**
|
|
* @file lv_iter.c
|
|
*
|
|
*/
|
|
|
|
/*********************
|
|
* INCLUDES
|
|
*********************/
|
|
|
|
#include "lv_assert.h"
|
|
|
|
#include "lv_iter.h"
|
|
|
|
#include "lv_circle_buf.h"
|
|
|
|
/*********************
|
|
* DEFINES
|
|
*********************/
|
|
|
|
/**********************
|
|
* TYPEDEFS
|
|
**********************/
|
|
|
|
struct _lv_iter_t {
|
|
/* Iterator state */
|
|
void * instance; /**< Pointer to the object to iterate over */
|
|
uint32_t elem_size; /**< Size of one element in bytes */
|
|
void * context; /**< Custom context for the iteration */
|
|
uint32_t context_size; /**< Size of the custom context in bytes */
|
|
|
|
/* Peeking */
|
|
lv_circle_buf_t * peek_buf; /**< Circular buffer for peeking */
|
|
uint32_t peek_offset; /**< Offset in the peek buffer */
|
|
|
|
/* Callbacks */
|
|
lv_iter_next_cb next_cb; /**< Callback to get the next element */
|
|
};
|
|
|
|
/**********************
|
|
* STATIC PROTOTYPES
|
|
**********************/
|
|
|
|
static bool peek_fill_cb(void * buf, uint32_t buf_len, int32_t index, void * user_data);
|
|
|
|
/**********************
|
|
* GLOBAL VARIABLES
|
|
**********************/
|
|
|
|
/**********************
|
|
* STATIC VARIABLES
|
|
**********************/
|
|
|
|
/**********************
|
|
* MACROS
|
|
**********************/
|
|
|
|
/**********************
|
|
* GLOBAL FUNCTIONS
|
|
**********************/
|
|
|
|
lv_iter_t * lv_iter_create(void * instance, const uint32_t elem_size, const uint32_t context_size,
|
|
lv_iter_next_cb next_cb)
|
|
{
|
|
lv_iter_t * iter = lv_malloc_zeroed(sizeof(lv_iter_t));
|
|
LV_ASSERT_MALLOC(iter);
|
|
|
|
if(iter == NULL) {
|
|
LV_LOG_ERROR("Could not allocate memory for iterator");
|
|
return NULL;
|
|
}
|
|
|
|
iter->instance = instance;
|
|
iter->elem_size = elem_size;
|
|
iter->context_size = context_size;
|
|
iter->next_cb = next_cb;
|
|
|
|
if(context_size > 0) {
|
|
iter->context = lv_malloc_zeroed(context_size);
|
|
LV_ASSERT_MALLOC(iter->context);
|
|
}
|
|
|
|
return iter;
|
|
}
|
|
|
|
void * lv_iter_get_context(const lv_iter_t * iter)
|
|
{
|
|
LV_ASSERT_NULL(iter);
|
|
|
|
return iter ? iter->context : NULL;
|
|
}
|
|
|
|
void lv_iter_destroy(lv_iter_t * iter)
|
|
{
|
|
LV_ASSERT_NULL(iter);
|
|
if(iter == NULL) return;
|
|
|
|
if(iter->context_size > 0) lv_free(iter->context);
|
|
if(iter->peek_buf != NULL) lv_circle_buf_destroy(iter->peek_buf);
|
|
|
|
iter->context = NULL;
|
|
iter->peek_buf = NULL;
|
|
|
|
lv_free(iter);
|
|
}
|
|
|
|
void lv_iter_make_peekable(lv_iter_t * iter, const uint32_t capacity)
|
|
{
|
|
LV_ASSERT_NULL(iter);
|
|
if(iter == NULL) return;
|
|
|
|
if(capacity == 0 || iter->peek_buf != NULL) return;
|
|
iter->peek_buf = lv_circle_buf_create(capacity, iter->elem_size);
|
|
LV_ASSERT_NULL(iter->peek_buf);
|
|
}
|
|
|
|
lv_result_t lv_iter_next(lv_iter_t * iter, void * elem)
|
|
{
|
|
LV_ASSERT_NULL(iter);
|
|
if(iter == NULL) return LV_RESULT_INVALID;
|
|
|
|
lv_circle_buf_t * c_buf = iter->peek_buf;
|
|
if(c_buf != NULL && !lv_circle_buf_is_empty(c_buf)) {
|
|
if(elem) lv_circle_buf_read(c_buf, elem);
|
|
else lv_circle_buf_skip(c_buf);
|
|
iter->peek_offset = 0;
|
|
return LV_RESULT_OK;
|
|
}
|
|
|
|
const lv_result_t iter_res = iter->next_cb(iter->instance, iter->context, elem);
|
|
if(iter_res == LV_RESULT_INVALID) return LV_RESULT_INVALID;
|
|
|
|
if(c_buf != NULL) iter->peek_offset = 0;
|
|
|
|
return iter_res;
|
|
}
|
|
|
|
lv_result_t lv_iter_peek(lv_iter_t * iter, void * elem)
|
|
{
|
|
LV_ASSERT_NULL(iter);
|
|
if(iter == NULL) return LV_RESULT_INVALID;
|
|
|
|
lv_circle_buf_t * c_buf = iter->peek_buf;
|
|
if(c_buf == NULL) return LV_RESULT_INVALID;
|
|
|
|
const uint32_t peek_count = lv_circle_buf_size(c_buf);
|
|
if(iter->peek_offset >= peek_count) {
|
|
const uint32_t required = iter->peek_offset + 1 - peek_count;
|
|
const uint32_t filled = lv_circle_buf_fill(c_buf, required, peek_fill_cb, iter);
|
|
if(filled != required) return LV_RESULT_INVALID;
|
|
}
|
|
|
|
lv_circle_buf_peek_at(c_buf, iter->peek_offset, elem);
|
|
|
|
return LV_RESULT_OK;
|
|
}
|
|
|
|
lv_result_t lv_iter_peek_advance(lv_iter_t * iter)
|
|
{
|
|
LV_ASSERT_NULL(iter);
|
|
if(iter == NULL) return LV_RESULT_INVALID;
|
|
|
|
if(iter->peek_buf == NULL || iter->peek_offset + 1 >= lv_circle_buf_capacity(iter->peek_buf))
|
|
return LV_RESULT_INVALID;
|
|
iter->peek_offset++;
|
|
return LV_RESULT_OK;
|
|
}
|
|
|
|
lv_result_t lv_iter_peek_reset(lv_iter_t * iter)
|
|
{
|
|
LV_ASSERT_NULL(iter);
|
|
if(iter == NULL) return LV_RESULT_INVALID;
|
|
|
|
if(iter->peek_buf == NULL) return LV_RESULT_INVALID;
|
|
|
|
iter->peek_offset = 0;
|
|
return LV_RESULT_OK;
|
|
}
|
|
|
|
void lv_iter_inspect(lv_iter_t * iter, const lv_iter_inspect_cb inspect_cb)
|
|
{
|
|
LV_ASSERT_NULL(iter);
|
|
if(iter == NULL) return;
|
|
|
|
void * elem = lv_malloc_zeroed(iter->elem_size);
|
|
LV_ASSERT_MALLOC(elem);
|
|
|
|
if(elem == NULL) {
|
|
LV_LOG_ERROR("Could not allocate memory for element");
|
|
return;
|
|
}
|
|
|
|
while(lv_iter_next(iter, elem) == LV_RESULT_OK) {
|
|
inspect_cb(elem);
|
|
}
|
|
|
|
lv_free(elem);
|
|
}
|
|
|
|
/**********************
|
|
* STATIC FUNCTIONS
|
|
**********************/
|
|
|
|
static bool peek_fill_cb(void * buf, const uint32_t buf_len, const int32_t index, void * user_data)
|
|
{
|
|
LV_UNUSED(buf_len);
|
|
LV_UNUSED(index);
|
|
|
|
const lv_iter_t * iter = user_data;
|
|
const lv_result_t iter_res = iter->next_cb(iter->instance, iter->context, buf);
|
|
if(iter_res == LV_RESULT_INVALID) return false;
|
|
|
|
return true;
|
|
}
|