1 /*
2  * This file is part of the MicroPython project, http://micropython.org/
3  *
4  * The MIT License (MIT)
5  *
6  * Copyright (c) 2013, 2014 Damien P. George
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a copy
9  * of this software and associated documentation files (the "Software"), to deal
10  * in the Software without restriction, including without limitation the rights
11  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12  * copies of the Software, and to permit persons to whom the Software is
13  * furnished to do so, subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be included in
16  * all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24  * THE SOFTWARE.
25  */
26 #ifndef MICROPY_INCLUDED_PY_MISC_H
27 #define MICROPY_INCLUDED_PY_MISC_H
28 
29 // a mini library of useful types and functions
30 
31 /** types *******************************************************/
32 
33 #include <stdbool.h>
34 #include <stdint.h>
35 #include <stddef.h>
36 
37 typedef unsigned char byte;
38 typedef unsigned int uint;
39 
40 /** generic ops *************************************************/
41 
42 #ifndef MIN
43 #define MIN(x, y) ((x) < (y) ? (x) : (y))
44 #endif
45 #ifndef MAX
46 #define MAX(x, y) ((x) > (y) ? (x) : (y))
47 #endif
48 
49 // Classical double-indirection stringification of preprocessor macro's value
50 #define MP_STRINGIFY_HELPER(x) #x
51 #define MP_STRINGIFY(x) MP_STRINGIFY_HELPER(x)
52 
53 // Static assertion macro
54 #define MP_STATIC_ASSERT(cond) ((void)sizeof(char[1 - 2 * !(cond)]))
55 
56 // Round-up integer division
57 #define MP_CEIL_DIVIDE(a, b) (((a) + (b) - 1) / (b))
58 #define MP_ROUND_DIVIDE(a, b) (((a) + (b) / 2) / (b))
59 
60 /** memory allocation ******************************************/
61 
62 // TODO make a lazy m_renew that can increase by a smaller amount than requested (but by at least 1 more element)
63 
64 #define m_new(type, num) ((type *)(m_malloc(sizeof(type) * (num))))
65 #define m_new_maybe(type, num) ((type *)(m_malloc_maybe(sizeof(type) * (num))))
66 #define m_new0(type, num) ((type *)(m_malloc0(sizeof(type) * (num))))
67 #define m_new_obj(type) (m_new(type, 1))
68 #define m_new_obj_maybe(type) (m_new_maybe(type, 1))
69 #define m_new_obj_var(obj_type, var_type, var_num) ((obj_type *)m_malloc(sizeof(obj_type) + sizeof(var_type) * (var_num)))
70 #define m_new_obj_var_maybe(obj_type, var_type, var_num) ((obj_type *)m_malloc_maybe(sizeof(obj_type) + sizeof(var_type) * (var_num)))
71 #if MICROPY_ENABLE_FINALISER
72 #define m_new_obj_with_finaliser(type) ((type *)(m_malloc_with_finaliser(sizeof(type))))
73 #define m_new_obj_var_with_finaliser(type, var_type, var_num) ((type *)m_malloc_with_finaliser(sizeof(type) + sizeof(var_type) * (var_num)))
74 #else
75 #define m_new_obj_with_finaliser(type) m_new_obj(type)
76 #define m_new_obj_var_with_finaliser(type, var_type, var_num) m_new_obj_var(type, var_type, var_num)
77 #endif
78 #if MICROPY_MALLOC_USES_ALLOCATED_SIZE
79 #define m_renew(type, ptr, old_num, new_num) ((type *)(m_realloc((ptr), sizeof(type) * (old_num), sizeof(type) * (new_num))))
80 #define m_renew_maybe(type, ptr, old_num, new_num, allow_move) ((type *)(m_realloc_maybe((ptr), sizeof(type) * (old_num), sizeof(type) * (new_num), (allow_move))))
81 #define m_del(type, ptr, num) m_free(ptr, sizeof(type) * (num))
82 #define m_del_var(obj_type, var_type, var_num, ptr) (m_free(ptr, sizeof(obj_type) + sizeof(var_type) * (var_num)))
83 #else
84 #define m_renew(type, ptr, old_num, new_num) ((type *)(m_realloc((ptr), sizeof(type) * (new_num))))
85 #define m_renew_maybe(type, ptr, old_num, new_num, allow_move) ((type *)(m_realloc_maybe((ptr), sizeof(type) * (new_num), (allow_move))))
86 #define m_del(type, ptr, num) ((void)(num), m_free(ptr))
87 #define m_del_var(obj_type, var_type, var_num, ptr) ((void)(var_num), m_free(ptr))
88 #endif
89 #define m_del_obj(type, ptr) (m_del(type, ptr, 1))
90 
91 void *m_malloc(size_t num_bytes);
92 void *m_malloc_maybe(size_t num_bytes);
93 void *m_malloc_with_finaliser(size_t num_bytes);
94 void *m_malloc0(size_t num_bytes);
95 #if MICROPY_MALLOC_USES_ALLOCATED_SIZE
96 void *m_realloc(void *ptr, size_t old_num_bytes, size_t new_num_bytes);
97 void *m_realloc_maybe(void *ptr, size_t old_num_bytes, size_t new_num_bytes, bool allow_move);
98 void m_free(void *ptr, size_t num_bytes);
99 #else
100 void *m_realloc(void *ptr, size_t new_num_bytes);
101 void *m_realloc_maybe(void *ptr, size_t new_num_bytes, bool allow_move);
102 void m_free(void *ptr);
103 #endif
104 NORETURN void m_malloc_fail(size_t num_bytes);
105 
106 #if MICROPY_MEM_STATS
107 size_t m_get_total_bytes_allocated(void);
108 size_t m_get_current_bytes_allocated(void);
109 size_t m_get_peak_bytes_allocated(void);
110 #endif
111 
112 /** array helpers ***********************************************/
113 
114 // get the number of elements in a fixed-size array
115 #define MP_ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
116 
117 // align ptr to the nearest multiple of "alignment"
118 #define MP_ALIGN(ptr, alignment) (void *)(((uintptr_t)(ptr) + ((alignment) - 1)) & ~((alignment) - 1))
119 
120 /** unichar / UTF-8 *********************************************/
121 
122 #if MICROPY_PY_BUILTINS_STR_UNICODE
123 // with unicode enabled we need a type which can fit chars up to 0x10ffff
124 typedef uint32_t unichar;
125 #else
126 // without unicode enabled we can only need to fit chars up to 0xff
127 // (on 16-bit archs uint is 16-bits and more efficient than uint32_t)
128 typedef uint unichar;
129 #endif
130 
131 #if MICROPY_PY_BUILTINS_STR_UNICODE
132 unichar utf8_get_char(const byte *s);
133 const byte *utf8_next_char(const byte *s);
134 size_t utf8_charlen(const byte *str, size_t len);
135 #else
utf8_get_char(const byte * s)136 static inline unichar utf8_get_char(const byte *s) {
137     return *s;
138 }
utf8_next_char(const byte * s)139 static inline const byte *utf8_next_char(const byte *s) {
140     return s + 1;
141 }
utf8_charlen(const byte * str,size_t len)142 static inline size_t utf8_charlen(const byte *str, size_t len) {
143     (void)str;
144     return len;
145 }
146 #endif
147 
148 bool unichar_isspace(unichar c);
149 bool unichar_isalpha(unichar c);
150 bool unichar_isprint(unichar c);
151 bool unichar_isdigit(unichar c);
152 bool unichar_isxdigit(unichar c);
153 bool unichar_isident(unichar c);
154 bool unichar_isalnum(unichar c);
155 bool unichar_isupper(unichar c);
156 bool unichar_islower(unichar c);
157 unichar unichar_tolower(unichar c);
158 unichar unichar_toupper(unichar c);
159 mp_uint_t unichar_xdigit_value(unichar c);
160 #define UTF8_IS_NONASCII(ch) ((ch) & 0x80)
161 #define UTF8_IS_CONT(ch) (((ch) & 0xC0) == 0x80)
162 
163 /** variable string *********************************************/
164 
165 typedef struct _vstr_t {
166     size_t alloc;
167     size_t len;
168     char *buf;
169     bool fixed_buf : 1;
170 } vstr_t;
171 
172 // convenience macro to declare a vstr with a fixed size buffer on the stack
173 #define VSTR_FIXED(vstr, alloc) vstr_t vstr; char vstr##_buf[(alloc)]; vstr_init_fixed_buf(&vstr, (alloc), vstr##_buf);
174 
175 void vstr_init(vstr_t *vstr, size_t alloc);
176 void vstr_init_len(vstr_t *vstr, size_t len);
177 void vstr_init_fixed_buf(vstr_t *vstr, size_t alloc, char *buf);
178 struct _mp_print_t;
179 void vstr_init_print(vstr_t *vstr, size_t alloc, struct _mp_print_t *print);
180 void vstr_clear(vstr_t *vstr);
181 vstr_t *vstr_new(size_t alloc);
182 void vstr_free(vstr_t *vstr);
vstr_reset(vstr_t * vstr)183 static inline void vstr_reset(vstr_t *vstr) {
184     vstr->len = 0;
185 }
vstr_str(vstr_t * vstr)186 static inline char *vstr_str(vstr_t *vstr) {
187     return vstr->buf;
188 }
vstr_len(vstr_t * vstr)189 static inline size_t vstr_len(vstr_t *vstr) {
190     return vstr->len;
191 }
192 void vstr_hint_size(vstr_t *vstr, size_t size);
193 char *vstr_extend(vstr_t *vstr, size_t size);
194 char *vstr_add_len(vstr_t *vstr, size_t len);
195 char *vstr_null_terminated_str(vstr_t *vstr);
196 void vstr_add_byte(vstr_t *vstr, byte v);
197 void vstr_add_char(vstr_t *vstr, unichar chr);
198 void vstr_add_str(vstr_t *vstr, const char *str);
199 void vstr_add_strn(vstr_t *vstr, const char *str, size_t len);
200 void vstr_ins_byte(vstr_t *vstr, size_t byte_pos, byte b);
201 void vstr_ins_char(vstr_t *vstr, size_t char_pos, unichar chr);
202 void vstr_cut_head_bytes(vstr_t *vstr, size_t bytes_to_cut);
203 void vstr_cut_tail_bytes(vstr_t *vstr, size_t bytes_to_cut);
204 void vstr_cut_out_bytes(vstr_t *vstr, size_t byte_pos, size_t bytes_to_cut);
205 void vstr_printf(vstr_t *vstr, const char *fmt, ...);
206 
207 /** non-dynamic size-bounded variable buffer/string *************/
208 
209 #define CHECKBUF(buf, max_size) char buf[max_size + 1]; size_t buf##_len = max_size; char *buf##_p = buf;
210 #define CHECKBUF_RESET(buf, max_size) buf##_len = max_size; buf##_p = buf;
211 #define CHECKBUF_APPEND(buf, src, src_len) \
212     { size_t l = MIN(src_len, buf##_len); \
213       memcpy(buf##_p, src, l); \
214       buf##_len -= l; \
215       buf##_p += l; }
216 #define CHECKBUF_APPEND_0(buf) { *buf##_p = 0; }
217 #define CHECKBUF_LEN(buf) (buf##_p - buf)
218 
219 #ifdef va_start
220 void vstr_vprintf(vstr_t *vstr, const char *fmt, va_list ap);
221 #endif
222 
223 // Debugging helpers
224 int DEBUG_printf(const char *fmt, ...);
225 
226 extern mp_uint_t mp_verbose_flag;
227 
228 /** float internals *************/
229 
230 #if MICROPY_PY_BUILTINS_FLOAT
231 
232 #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE
233 #define MP_FLOAT_EXP_BITS (11)
234 #define MP_FLOAT_FRAC_BITS (52)
235 typedef uint64_t mp_float_uint_t;
236 #elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
237 #define MP_FLOAT_EXP_BITS (8)
238 #define MP_FLOAT_FRAC_BITS (23)
239 typedef uint32_t mp_float_uint_t;
240 #endif
241 
242 #define MP_FLOAT_EXP_BIAS ((1 << (MP_FLOAT_EXP_BITS - 1)) - 1)
243 
244 typedef union _mp_float_union_t {
245     mp_float_t f;
246     #if MP_ENDIANNESS_LITTLE
247     struct {
248         mp_float_uint_t frc : MP_FLOAT_FRAC_BITS;
249         mp_float_uint_t exp : MP_FLOAT_EXP_BITS;
250         mp_float_uint_t sgn : 1;
251     } p;
252     #else
253     struct {
254         mp_float_uint_t sgn : 1;
255         mp_float_uint_t exp : MP_FLOAT_EXP_BITS;
256         mp_float_uint_t frc : MP_FLOAT_FRAC_BITS;
257     } p;
258     #endif
259     mp_float_uint_t i;
260 } mp_float_union_t;
261 
262 #endif // MICROPY_PY_BUILTINS_FLOAT
263 
264 /** ROM string compression *************/
265 
266 #if MICROPY_ROM_TEXT_COMPRESSION
267 
268 #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_NONE
269 #error "MICROPY_ERROR_REPORTING_NONE requires MICROPY_ROM_TEXT_COMPRESSION disabled"
270 #endif
271 
272 #ifdef NO_QSTR
273 
274 // Compression enabled but doing QSTR extraction.
275 // So leave MP_COMPRESSED_ROM_TEXT in place for makeqstrdefs.py / makecompresseddata.py to find them.
276 
277 #else
278 
279 // Compression enabled and doing a regular build.
280 // Map MP_COMPRESSED_ROM_TEXT to the compressed strings.
281 
282 // Force usage of the MP_ERROR_TEXT macro by requiring an opaque type.
283 typedef struct {
284     #ifdef __clang__
285     // Fix "error: empty struct has size 0 in C, size 1 in C++".
286     char dummy;
287     #endif
288 } *mp_rom_error_text_t;
289 
290 #include <string.h>
291 
MP_COMPRESSED_ROM_TEXT(const char * msg)292 inline __attribute__((always_inline)) const char *MP_COMPRESSED_ROM_TEXT(const char *msg) {
293     // "genhdr/compressed.data.h" contains an invocation of the MP_MATCH_COMPRESSED macro for each compressed string.
294     // The giant if(strcmp) tree is optimized by the compiler, which turns this into a direct return of the compressed data.
295     #define MP_MATCH_COMPRESSED(a, b) if (strcmp(msg, a) == 0) { return b; } else
296 
297     // It also contains a single invocation of the MP_COMPRESSED_DATA macro, we don't need that here.
298     #define MP_COMPRESSED_DATA(x)
299 
300     #include "genhdr/compressed.data.h"
301 
302 #undef MP_COMPRESSED_DATA
303 #undef MP_MATCH_COMPRESSED
304 
305     return msg;
306 }
307 
308 #endif
309 
310 #else
311 
312 // Compression not enabled, just make it a no-op.
313 
314 typedef const char *mp_rom_error_text_t;
315 #define MP_COMPRESSED_ROM_TEXT(x) x
316 
317 #endif // MICROPY_ROM_TEXT_COMPRESSION
318 
319 // Might add more types of compressed text in the future.
320 // For now, forward directly to MP_COMPRESSED_ROM_TEXT.
321 #define MP_ERROR_TEXT(x) (mp_rom_error_text_t)MP_COMPRESSED_ROM_TEXT(x)
322 
323 #endif // MICROPY_INCLUDED_PY_MISC_H
324