1 /**
2 * @file lv_array.c
3 * Array.
4 * The nodes are dynamically allocated by the 'lv_mem' module,
5 */
6
7 /*********************
8 * INCLUDES
9 *********************/
10 #include "lv_array.h"
11 #include "../stdlib/lv_mem.h"
12 #include "../stdlib/lv_string.h"
13
14 #include "lv_assert.h"
15 /*********************
16 * DEFINES
17 *********************/
18
19 /**********************
20 * TYPEDEFS
21 **********************/
22
23 /**********************
24 * STATIC PROTOTYPES
25 **********************/
26
27 /**********************
28 * STATIC VARIABLES
29 **********************/
30
31 /**********************
32 * MACROS
33 **********************/
34
35 /**********************
36 * GLOBAL FUNCTIONS
37 **********************/
lv_array_init(lv_array_t * array,uint32_t capacity,uint32_t element_size)38 void lv_array_init(lv_array_t * array, uint32_t capacity, uint32_t element_size)
39 {
40 array->size = 0;
41 array->capacity = capacity;
42 array->element_size = element_size;
43
44 array->data = lv_malloc(capacity * element_size);
45 array->inner_alloc = true;
46 LV_ASSERT_MALLOC(array->data);
47 }
48
lv_array_init_from_buf(lv_array_t * array,void * buf,uint32_t capacity,uint32_t element_size)49 void lv_array_init_from_buf(lv_array_t * array, void * buf, uint32_t capacity, uint32_t element_size)
50 {
51 LV_ASSERT_NULL(buf);
52 array->size = 0;
53 array->capacity = capacity;
54 array->element_size = element_size;
55
56 array->data = buf;
57 array->inner_alloc = false;
58 }
59
lv_array_deinit(lv_array_t * array)60 void lv_array_deinit(lv_array_t * array)
61 {
62 if(array->data) {
63 if(array->inner_alloc) lv_free(array->data);
64 array->data = NULL;
65 }
66
67 array->size = 0;
68 array->capacity = 0;
69 }
70
lv_array_copy(lv_array_t * target,const lv_array_t * source)71 void lv_array_copy(lv_array_t * target, const lv_array_t * source)
72 {
73 if(lv_array_is_empty(source)) {
74 return;
75 }
76 lv_array_deinit(target);
77 lv_array_init(target, source->capacity, source->element_size);
78 lv_memcpy(target->data, source->data, source->size * source->element_size);
79 target->size = source->size;
80 }
81
lv_array_shrink(lv_array_t * array)82 void lv_array_shrink(lv_array_t * array)
83 {
84 if(array->size <= array->capacity / LV_ARRAY_DEFAULT_SHRINK_RATIO) {
85 lv_array_resize(array, array->size);
86 }
87 }
88
lv_array_remove(lv_array_t * array,uint32_t index)89 lv_result_t lv_array_remove(lv_array_t * array, uint32_t index)
90 {
91 if(index >= array->size) {
92 return LV_RESULT_INVALID;
93 }
94
95 /*Shortcut*/
96 if(index == array->size - 1) {
97 array->size--;
98 lv_array_shrink(array);
99 return LV_RESULT_OK;
100 }
101
102 uint8_t * start = lv_array_at(array, index);
103 uint8_t * remaining = start + array->element_size;
104 uint32_t remaining_size = (array->size - index - 1) * array->element_size;
105 lv_memmove(start, remaining, remaining_size);
106 array->size--;
107 lv_array_shrink(array);
108 return LV_RESULT_OK;
109 }
110
lv_array_erase(lv_array_t * array,uint32_t start,uint32_t end)111 lv_result_t lv_array_erase(lv_array_t * array, uint32_t start, uint32_t end)
112 {
113 if(end > array->size) {
114 end = array->size;
115 }
116
117 if(start >= end) {
118 return LV_RESULT_INVALID;
119 }
120
121 /*Shortcut*/
122 if(end == array->size) {
123 array->size = start;
124 lv_array_shrink(array);
125 return LV_RESULT_OK;
126 }
127
128 uint8_t * start_p = lv_array_at(array, start);
129 uint8_t * remaining = start_p + (end - start) * array->element_size;
130 uint32_t remaining_size = (array->size - end) * array->element_size;
131 lv_memcpy(start_p, remaining, remaining_size);
132 array->size -= (end - start);
133 lv_array_shrink(array);
134 return LV_RESULT_OK;
135 }
136
lv_array_resize(lv_array_t * array,uint32_t new_capacity)137 bool lv_array_resize(lv_array_t * array, uint32_t new_capacity)
138 {
139 if(array->inner_alloc == false) {
140 LV_LOG_WARN("Cannot resize array with external buffer");
141 return false;
142 }
143
144 uint8_t * data = lv_realloc(array->data, new_capacity * array->element_size);
145 LV_ASSERT_NULL(data);
146
147 if(data == NULL) return false;
148
149 array->data = data;
150 array->capacity = new_capacity;
151 if(array->size > new_capacity) {
152 array->size = new_capacity;
153 }
154 return true;
155 }
156
lv_array_concat(lv_array_t * array,const lv_array_t * other)157 lv_result_t lv_array_concat(lv_array_t * array, const lv_array_t * other)
158 {
159 LV_ASSERT_NULL(array->data);
160 uint32_t size = other->size;
161 if(array->size + size > array->capacity) {
162 /*array is full*/
163 if(lv_array_resize(array, array->size + size) == false) {
164 return LV_RESULT_INVALID;
165 }
166 }
167
168 uint8_t * data = array->data + array->size * array->element_size;
169 lv_memcpy(data, other->data, array->element_size * size);
170 array->size += size;
171 return LV_RESULT_OK;
172 }
173
lv_array_push_back(lv_array_t * array,const void * element)174 lv_result_t lv_array_push_back(lv_array_t * array, const void * element)
175 {
176 LV_ASSERT_NULL(array->data);
177
178 if(array->size == array->capacity) {
179 /*array is full*/
180 if(lv_array_resize(array, array->capacity + LV_ARRAY_DEFAULT_CAPACITY) == false) {
181 return LV_RESULT_INVALID;
182 }
183 }
184
185 /**
186 * When the element is NULL, it means that the user wants to add an empty element.
187 */
188 uint8_t * data = array->data + array->size * array->element_size;
189 if(element) lv_memcpy(data, element, array->element_size);
190 else lv_memzero(data, array->element_size);
191
192 array->size++;
193 return LV_RESULT_OK;
194 }
195
lv_array_at(const lv_array_t * array,uint32_t index)196 void * lv_array_at(const lv_array_t * array, uint32_t index)
197 {
198 if(index >= array->size) {
199 return NULL;
200 }
201
202 LV_ASSERT_NULL(array->data);
203 return array->data + index * array->element_size;
204 }
205
lv_array_assign(lv_array_t * array,uint32_t index,const void * value)206 lv_result_t lv_array_assign(lv_array_t * array, uint32_t index, const void * value)
207 {
208 uint8_t * data = lv_array_at(array, index);
209 if(data == NULL) return LV_RESULT_INVALID;
210
211 lv_memcpy(data, value, array->element_size);
212 return LV_RESULT_OK;
213 }
214
lv_array_size(const lv_array_t * array)215 uint32_t lv_array_size(const lv_array_t * array)
216 {
217 return array->size;
218 }
219
lv_array_capacity(const lv_array_t * array)220 uint32_t lv_array_capacity(const lv_array_t * array)
221 {
222 return array->capacity;
223 }
224
lv_array_is_empty(const lv_array_t * array)225 bool lv_array_is_empty(const lv_array_t * array)
226 {
227 return array->size == 0;
228 }
229
lv_array_is_full(const lv_array_t * array)230 bool lv_array_is_full(const lv_array_t * array)
231 {
232 return array->size == array->capacity;
233 }
234
lv_array_clear(lv_array_t * array)235 void lv_array_clear(lv_array_t * array)
236 {
237 array->size = 0;
238 }
239
lv_array_front(const lv_array_t * array)240 void * lv_array_front(const lv_array_t * array)
241 {
242 return lv_array_at(array, 0);
243 }
244
lv_array_back(const lv_array_t * array)245 void * lv_array_back(const lv_array_t * array)
246 {
247 return lv_array_at(array, lv_array_size(array) - 1);
248 }
249
250 /**********************
251 * STATIC FUNCTIONS
252 **********************/
253