1 /**
2 * @file lv_iter.c
3 *
4 */
5
6 /*********************
7 * INCLUDES
8 *********************/
9
10 #include "lv_assert.h"
11
12 #include "lv_iter.h"
13
14 #include "lv_circle_buf.h"
15
16 /*********************
17 * DEFINES
18 *********************/
19
20 /**********************
21 * TYPEDEFS
22 **********************/
23
24 struct _lv_iter_t {
25 /* Iterator state */
26 void * instance; /**< Pointer to the object to iterate over */
27 uint32_t elem_size; /**< Size of one element in bytes */
28 void * context; /**< Custom context for the iteration */
29 uint32_t context_size; /**< Size of the custom context in bytes */
30
31 /* Peeking */
32 lv_circle_buf_t * peek_buf; /**< Circular buffer for peeking */
33 uint32_t peek_offset; /**< Offset in the peek buffer */
34
35 /* Callbacks */
36 lv_iter_next_cb next_cb; /**< Callback to get the next element */
37 };
38
39 /**********************
40 * STATIC PROTOTYPES
41 **********************/
42
43 static bool peek_fill_cb(void * buf, uint32_t buf_len, int32_t index, void * user_data);
44
45 /**********************
46 * GLOBAL VARIABLES
47 **********************/
48
49 /**********************
50 * STATIC VARIABLES
51 **********************/
52
53 /**********************
54 * MACROS
55 **********************/
56
57 /**********************
58 * GLOBAL FUNCTIONS
59 **********************/
60
lv_iter_create(void * instance,const uint32_t elem_size,const uint32_t context_size,lv_iter_next_cb next_cb)61 lv_iter_t * lv_iter_create(void * instance, const uint32_t elem_size, const uint32_t context_size,
62 lv_iter_next_cb next_cb)
63 {
64 lv_iter_t * iter = lv_malloc_zeroed(sizeof(lv_iter_t));
65 LV_ASSERT_MALLOC(iter);
66
67 if(iter == NULL) {
68 LV_LOG_ERROR("Could not allocate memory for iterator");
69 return NULL;
70 }
71
72 iter->instance = instance;
73 iter->elem_size = elem_size;
74 iter->context_size = context_size;
75 iter->next_cb = next_cb;
76
77 if(context_size > 0) {
78 iter->context = lv_malloc_zeroed(context_size);
79 LV_ASSERT_MALLOC(iter->context);
80 }
81
82 return iter;
83 }
84
lv_iter_get_context(const lv_iter_t * iter)85 void * lv_iter_get_context(const lv_iter_t * iter)
86 {
87 LV_ASSERT_NULL(iter);
88
89 return iter ? iter->context : NULL;
90 }
91
lv_iter_destroy(lv_iter_t * iter)92 void lv_iter_destroy(lv_iter_t * iter)
93 {
94 LV_ASSERT_NULL(iter);
95 if(iter == NULL) return;
96
97 if(iter->context_size > 0) lv_free(iter->context);
98 if(iter->peek_buf != NULL) lv_circle_buf_destroy(iter->peek_buf);
99
100 iter->context = NULL;
101 iter->peek_buf = NULL;
102
103 lv_free(iter);
104 }
105
lv_iter_make_peekable(lv_iter_t * iter,const uint32_t capacity)106 void lv_iter_make_peekable(lv_iter_t * iter, const uint32_t capacity)
107 {
108 LV_ASSERT_NULL(iter);
109 if(iter == NULL) return;
110
111 if(capacity == 0 || iter->peek_buf != NULL) return;
112 iter->peek_buf = lv_circle_buf_create(capacity, iter->elem_size);
113 LV_ASSERT_NULL(iter->peek_buf);
114 }
115
lv_iter_next(lv_iter_t * iter,void * elem)116 lv_result_t lv_iter_next(lv_iter_t * iter, void * elem)
117 {
118 LV_ASSERT_NULL(iter);
119 if(iter == NULL) return LV_RESULT_INVALID;
120
121 lv_circle_buf_t * c_buf = iter->peek_buf;
122 if(c_buf != NULL && !lv_circle_buf_is_empty(c_buf)) {
123 if(elem) lv_circle_buf_read(c_buf, elem);
124 else lv_circle_buf_skip(c_buf);
125 iter->peek_offset = 0;
126 return LV_RESULT_OK;
127 }
128
129 const lv_result_t iter_res = iter->next_cb(iter->instance, iter->context, elem);
130 if(iter_res == LV_RESULT_INVALID) return LV_RESULT_INVALID;
131
132 if(c_buf != NULL) iter->peek_offset = 0;
133
134 return iter_res;
135 }
136
lv_iter_peek(lv_iter_t * iter,void * elem)137 lv_result_t lv_iter_peek(lv_iter_t * iter, void * elem)
138 {
139 LV_ASSERT_NULL(iter);
140 if(iter == NULL) return LV_RESULT_INVALID;
141
142 lv_circle_buf_t * c_buf = iter->peek_buf;
143 if(c_buf == NULL) return LV_RESULT_INVALID;
144
145 const uint32_t peek_count = lv_circle_buf_size(c_buf);
146 if(iter->peek_offset >= peek_count) {
147 const uint32_t required = iter->peek_offset + 1 - peek_count;
148 const uint32_t filled = lv_circle_buf_fill(c_buf, required, peek_fill_cb, iter);
149 if(filled != required) return LV_RESULT_INVALID;
150 }
151
152 lv_circle_buf_peek_at(c_buf, iter->peek_offset, elem);
153
154 return LV_RESULT_OK;
155 }
156
lv_iter_peek_advance(lv_iter_t * iter)157 lv_result_t lv_iter_peek_advance(lv_iter_t * iter)
158 {
159 LV_ASSERT_NULL(iter);
160 if(iter == NULL) return LV_RESULT_INVALID;
161
162 if(iter->peek_buf == NULL || iter->peek_offset + 1 >= lv_circle_buf_capacity(iter->peek_buf))
163 return LV_RESULT_INVALID;
164 iter->peek_offset++;
165 return LV_RESULT_OK;
166 }
167
lv_iter_peek_reset(lv_iter_t * iter)168 lv_result_t lv_iter_peek_reset(lv_iter_t * iter)
169 {
170 LV_ASSERT_NULL(iter);
171 if(iter == NULL) return LV_RESULT_INVALID;
172
173 if(iter->peek_buf == NULL) return LV_RESULT_INVALID;
174
175 iter->peek_offset = 0;
176 return LV_RESULT_OK;
177 }
178
lv_iter_inspect(lv_iter_t * iter,const lv_iter_inspect_cb inspect_cb)179 void lv_iter_inspect(lv_iter_t * iter, const lv_iter_inspect_cb inspect_cb)
180 {
181 LV_ASSERT_NULL(iter);
182 if(iter == NULL) return;
183
184 void * elem = lv_malloc_zeroed(iter->elem_size);
185 LV_ASSERT_MALLOC(elem);
186
187 if(elem == NULL) {
188 LV_LOG_ERROR("Could not allocate memory for element");
189 return;
190 }
191
192 while(lv_iter_next(iter, elem) == LV_RESULT_OK) {
193 inspect_cb(elem);
194 }
195
196 lv_free(elem);
197 }
198
199 /**********************
200 * STATIC FUNCTIONS
201 **********************/
202
peek_fill_cb(void * buf,const uint32_t buf_len,const int32_t index,void * user_data)203 static bool peek_fill_cb(void * buf, const uint32_t buf_len, const int32_t index, void * user_data)
204 {
205 LV_UNUSED(buf_len);
206 LV_UNUSED(index);
207
208 const lv_iter_t * iter = user_data;
209 const lv_result_t iter_res = iter->next_cb(iter->instance, iter->context, buf);
210 if(iter_res == LV_RESULT_INVALID) return false;
211
212 return true;
213 }
214