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