1 /**
2  * @file lv_string.c
3  */
4 
5 /*********************
6  *      INCLUDES
7  *********************/
8 #include "../../lv_conf_internal.h"
9 #if LV_USE_STDLIB_STRING == LV_STDLIB_BUILTIN
10 #include "../../misc/lv_assert.h"
11 #include "../../misc/lv_log.h"
12 #include "../../misc/lv_math.h"
13 #include "../../stdlib/lv_string.h"
14 #include "../../stdlib/lv_mem.h"
15 
16 /*********************
17  *      DEFINES
18  *********************/
19 #ifdef LV_ARCH_64
20     #define MEM_UNIT         uint64_t
21     #define ALIGN_MASK       0x7
22 #else
23     #define MEM_UNIT         uint32_t
24     #define ALIGN_MASK       0x3
25 #endif
26 
27 /**********************
28  *      TYPEDEFS
29  **********************/
30 
31 /**********************
32  *  STATIC PROTOTYPES
33  **********************/
34 
35 /**********************
36  *  STATIC VARIABLES
37  **********************/
38 
39 /**********************
40  *      MACROS
41  **********************/
42 #if LV_USE_LOG && LV_LOG_TRACE_MEM
43     #define LV_TRACE_MEM(...) LV_LOG_TRACE(__VA_ARGS__)
44 #else
45     #define LV_TRACE_MEM(...)
46 #endif
47 
48 #define _COPY(d, s) *d = *s; d++; s++;
49 #define _SET(d, v) *d = v; d++;
50 #define _REPEAT8(expr) expr expr expr expr expr expr expr expr
51 
52 /**********************
53  *   GLOBAL FUNCTIONS
54  **********************/
55 
lv_memcpy(void * dst,const void * src,size_t len)56 void * LV_ATTRIBUTE_FAST_MEM lv_memcpy(void * dst, const void * src, size_t len)
57 {
58     uint8_t * d8 = dst;
59     const uint8_t * s8 = src;
60 
61     /*Simplify for small memories*/
62     if(len < 16) {
63         while(len) {
64             *d8 = *s8;
65             d8++;
66             s8++;
67             len--;
68         }
69         return dst;
70     }
71 
72     lv_uintptr_t d_align = (lv_uintptr_t)d8 & ALIGN_MASK;
73     lv_uintptr_t s_align = (lv_uintptr_t)s8 & ALIGN_MASK;
74 
75     /*Byte copy for unaligned memories*/
76     if(s_align != d_align) {
77         while(len > 32) {
78             _REPEAT8(_COPY(d8, s8));
79             _REPEAT8(_COPY(d8, s8));
80             _REPEAT8(_COPY(d8, s8));
81             _REPEAT8(_COPY(d8, s8));
82             len -= 32;
83         }
84         while(len) {
85             _COPY(d8, s8)
86             len--;
87         }
88         return dst;
89     }
90 
91     /*Make the memories aligned*/
92     if(d_align) {
93         d_align = ALIGN_MASK + 1 - d_align;
94         while(d_align && len) {
95             _COPY(d8, s8);
96             d_align--;
97             len--;
98         }
99     }
100 
101     uint32_t * d32 = (uint32_t *)d8;
102     const uint32_t * s32 = (uint32_t *)s8;
103     while(len > 32) {
104         _REPEAT8(_COPY(d32, s32))
105         len -= 32;
106     }
107 
108     d8 = (uint8_t *)d32;
109     s8 = (const uint8_t *)s32;
110     while(len) {
111         _COPY(d8, s8)
112         len--;
113     }
114 
115     return dst;
116 }
117 
lv_memset(void * dst,uint8_t v,size_t len)118 void LV_ATTRIBUTE_FAST_MEM lv_memset(void * dst, uint8_t v, size_t len)
119 {
120     uint8_t * d8 = (uint8_t *)dst;
121     uintptr_t d_align = (lv_uintptr_t) d8 & ALIGN_MASK;
122 
123     /*Make the address aligned*/
124     if(d_align) {
125         d_align = ALIGN_MASK + 1 - d_align;
126         while(d_align && len) {
127             _SET(d8, v);
128             len--;
129             d_align--;
130         }
131     }
132 
133     uint32_t v32 = (uint32_t)v + ((uint32_t)v << 8) + ((uint32_t)v << 16) + ((uint32_t)v << 24);
134     uint32_t * d32 = (uint32_t *)d8;
135 
136     while(len > 32) {
137         _REPEAT8(_SET(d32, v32));
138         len -= 32;
139     }
140 
141     d8 = (uint8_t *)d32;
142     while(len) {
143         _SET(d8, v);
144         len--;
145     }
146 }
147 
lv_memmove(void * dst,const void * src,size_t len)148 void * LV_ATTRIBUTE_FAST_MEM lv_memmove(void * dst, const void * src, size_t len)
149 {
150     if(dst < src || (char *)dst > ((char *)src + len)) {
151         return lv_memcpy(dst, src, len);
152     }
153 
154     if(dst > src) {
155         char * tmp = (char *)dst + len - 1;
156         char * s   = (char *)src + len - 1;
157 
158         while(len--) {
159             *tmp-- = *s--;
160         }
161     }
162     else {
163         char * tmp = (char *)dst;
164         char * s   = (char *)src;
165 
166         while(len--) {
167             *tmp++ = *s++;
168         }
169     }
170 
171     return dst;
172 }
173 
lv_memcmp(const void * p1,const void * p2,size_t len)174 int lv_memcmp(const void * p1, const void * p2, size_t len)
175 {
176     const char * s1 = (const char *) p1;
177     const char * s2 = (const char *) p2;
178     while(--len > 0 && (*s1 == *s2)) {
179         s1++;
180         s2++;
181     }
182     return *s1 - *s2;
183 }
184 
185 /* See https://en.cppreference.com/w/c/string/byte/strlen for reference */
lv_strlen(const char * str)186 size_t lv_strlen(const char * str)
187 {
188     size_t i = 0;
189     while(str[i]) i++;
190 
191     return i;
192 }
193 
lv_strlcpy(char * dst,const char * src,size_t dst_size)194 size_t lv_strlcpy(char * dst, const char * src, size_t dst_size)
195 {
196     size_t i = 0;
197     if(dst_size > 0) {
198         for(; i < dst_size - 1 && src[i]; i++) {
199             dst[i] = src[i];
200         }
201         dst[i] = '\0';
202     }
203     while(src[i]) i++;
204     return i;
205 }
206 
lv_strncpy(char * dst,const char * src,size_t dst_size)207 char * lv_strncpy(char * dst, const char * src, size_t dst_size)
208 {
209     size_t i;
210     for(i = 0; i < dst_size && src[i]; i++) {
211         dst[i] = src[i];
212     }
213     for(; i < dst_size; i++) {
214         dst[i] = '\0';
215     }
216     return dst;
217 }
218 
lv_strcpy(char * dst,const char * src)219 char * lv_strcpy(char * dst, const char * src)
220 {
221     char * tmp = dst;
222     while((*dst++ = *src++) != '\0');
223     return tmp;
224 }
225 
lv_strcmp(const char * s1,const char * s2)226 int lv_strcmp(const char * s1, const char * s2)
227 {
228     while(*s1 && (*s1 == *s2)) {
229         s1++;
230         s2++;
231     }
232     return *(const unsigned char *)s1 - *(const unsigned char *)s2;
233 }
234 
lv_strncmp(const char * s1,const char * s2,size_t len)235 int lv_strncmp(const char * s1, const char * s2, size_t len)
236 {
237     if(len == 0) {
238         return 0;
239     }
240 
241     while(len > 0 && *s1 && (*s1 == *s2)) {
242         if(--len == 0) {
243             return 0;
244         }
245         s1++;
246         s2++;
247     }
248     return *(const unsigned char *)s1 - *(const unsigned char *)s2;
249 }
250 
lv_strdup(const char * src)251 char * lv_strdup(const char * src)
252 {
253     size_t len = lv_strlen(src) + 1;
254     char * dst = lv_malloc(len);
255     if(dst == NULL) return NULL;
256 
257     lv_memcpy(dst, src, len); /*memcpy is faster than strncpy when length is known*/
258     return dst;
259 }
260 
lv_strcat(char * dst,const char * src)261 char * lv_strcat(char * dst, const char * src)
262 {
263     lv_strcpy(dst + lv_strlen(dst), src);
264     return dst;
265 }
266 
lv_strncat(char * dst,const char * src,size_t src_len)267 char * lv_strncat(char * dst, const char * src, size_t src_len)
268 {
269     char * tmp = dst;
270     while(*dst != '\0') {
271         dst++;
272     }
273     while(src_len != 0 && *src != '\0') {
274         src_len--;
275         *dst++ = *src++;
276     }
277     *dst = '\0';
278     return tmp;
279 }
280 
lv_strchr(const char * s,int c)281 char * lv_strchr(const char * s, int c)
282 {
283     for(; ; s++) {
284         if(*s == c) {
285             return (char *)s;
286         }
287 
288         if(*s == '\0') {
289             break;
290         }
291     }
292 
293     return NULL;
294 }
295 
296 /**********************
297  *   STATIC FUNCTIONS
298  **********************/
299 
300 #endif /*LV_STDLIB_BUILTIN*/
301