Branch data Line data Source code
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 : : #if defined(_MSC_VER)
56 : : #define MP_STATIC_ASSERT_NOT_MSC(cond) (1)
57 : : #else
58 : : #define MP_STATIC_ASSERT_NOT_MSC(cond) MP_STATIC_ASSERT(cond)
59 : : #endif
60 : :
61 : : // Round-up integer division
62 : : #define MP_CEIL_DIVIDE(a, b) (((a) + (b) - 1) / (b))
63 : : #define MP_ROUND_DIVIDE(a, b) (((a) + (b) / 2) / (b))
64 : :
65 : : /** memory allocation ******************************************/
66 : :
67 : : // TODO make a lazy m_renew that can increase by a smaller amount than requested (but by at least 1 more element)
68 : :
69 : : #define m_new(type, num) ((type *)(m_malloc(sizeof(type) * (num))))
70 : : #define m_new_maybe(type, num) ((type *)(m_malloc_maybe(sizeof(type) * (num))))
71 : : #define m_new0(type, num) ((type *)(m_malloc0(sizeof(type) * (num))))
72 : : #define m_new_obj(type) (m_new(type, 1))
73 : : #define m_new_obj_maybe(type) (m_new_maybe(type, 1))
74 : : #define m_new_obj_var(obj_type, var_type, var_num) ((obj_type *)m_malloc(sizeof(obj_type) + sizeof(var_type) * (var_num)))
75 : : #define m_new_obj_var0(obj_type, var_type, var_num) ((obj_type *)m_malloc0(sizeof(obj_type) + sizeof(var_type) * (var_num)))
76 : : #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)))
77 : : #if MICROPY_ENABLE_FINALISER
78 : : #define m_new_obj_with_finaliser(type) ((type *)(m_malloc_with_finaliser(sizeof(type))))
79 : : #define m_new_obj_var_with_finaliser(type, var_type, var_num) ((type *)m_malloc_with_finaliser(sizeof(type) + sizeof(var_type) * (var_num)))
80 : : #else
81 : : #define m_new_obj_with_finaliser(type) m_new_obj(type)
82 : : #define m_new_obj_var_with_finaliser(type, var_type, var_num) m_new_obj_var(type, var_type, var_num)
83 : : #endif
84 : : #if MICROPY_MALLOC_USES_ALLOCATED_SIZE
85 : : #define m_renew(type, ptr, old_num, new_num) ((type *)(m_realloc((ptr), sizeof(type) * (old_num), sizeof(type) * (new_num))))
86 : : #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))))
87 : : #define m_del(type, ptr, num) m_free(ptr, sizeof(type) * (num))
88 : : #define m_del_var(obj_type, var_type, var_num, ptr) (m_free(ptr, sizeof(obj_type) + sizeof(var_type) * (var_num)))
89 : : #else
90 : : #define m_renew(type, ptr, old_num, new_num) ((type *)(m_realloc((ptr), sizeof(type) * (new_num))))
91 : : #define m_renew_maybe(type, ptr, old_num, new_num, allow_move) ((type *)(m_realloc_maybe((ptr), sizeof(type) * (new_num), (allow_move))))
92 : : #define m_del(type, ptr, num) ((void)(num), m_free(ptr))
93 : : #define m_del_var(obj_type, var_type, var_num, ptr) ((void)(var_num), m_free(ptr))
94 : : #endif
95 : : #define m_del_obj(type, ptr) (m_del(type, ptr, 1))
96 : :
97 : : void *m_malloc(size_t num_bytes);
98 : : void *m_malloc_maybe(size_t num_bytes);
99 : : void *m_malloc_with_finaliser(size_t num_bytes);
100 : : void *m_malloc0(size_t num_bytes);
101 : : #if MICROPY_MALLOC_USES_ALLOCATED_SIZE
102 : : void *m_realloc(void *ptr, size_t old_num_bytes, size_t new_num_bytes);
103 : : void *m_realloc_maybe(void *ptr, size_t old_num_bytes, size_t new_num_bytes, bool allow_move);
104 : : void m_free(void *ptr, size_t num_bytes);
105 : : #else
106 : : void *m_realloc(void *ptr, size_t new_num_bytes);
107 : : void *m_realloc_maybe(void *ptr, size_t new_num_bytes, bool allow_move);
108 : : void m_free(void *ptr);
109 : : #endif
110 : : NORETURN void m_malloc_fail(size_t num_bytes);
111 : :
112 : : #if MICROPY_TRACKED_ALLOC
113 : : // These alloc/free functions track the pointers in a linked list so the GC does not reclaim
114 : : // them. They can be used by code that requires traditional C malloc/free semantics.
115 : : void *m_tracked_calloc(size_t nmemb, size_t size);
116 : : void m_tracked_free(void *ptr_in);
117 : : #endif
118 : :
119 : : #if MICROPY_MEM_STATS
120 : : size_t m_get_total_bytes_allocated(void);
121 : : size_t m_get_current_bytes_allocated(void);
122 : : size_t m_get_peak_bytes_allocated(void);
123 : : #endif
124 : :
125 : : /** array helpers ***********************************************/
126 : :
127 : : // get the number of elements in a fixed-size array
128 : : #define MP_ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
129 : :
130 : : // align ptr to the nearest multiple of "alignment"
131 : : #define MP_ALIGN(ptr, alignment) (void *)(((uintptr_t)(ptr) + ((alignment) - 1)) & ~((alignment) - 1))
132 : :
133 : : /** unichar / UTF-8 *********************************************/
134 : :
135 : : #if MICROPY_PY_BUILTINS_STR_UNICODE
136 : : // with unicode enabled we need a type which can fit chars up to 0x10ffff
137 : : typedef uint32_t unichar;
138 : : #else
139 : : // without unicode enabled we can only need to fit chars up to 0xff
140 : : // (on 16-bit archs uint is 16-bits and more efficient than uint32_t)
141 : : typedef uint unichar;
142 : : #endif
143 : :
144 : : #if MICROPY_PY_BUILTINS_STR_UNICODE
145 : : unichar utf8_get_char(const byte *s);
146 : : const byte *utf8_next_char(const byte *s);
147 : : size_t utf8_charlen(const byte *str, size_t len);
148 : : #else
149 : : static inline unichar utf8_get_char(const byte *s) {
150 : : return *s;
151 : : }
152 : : static inline const byte *utf8_next_char(const byte *s) {
153 : : return s + 1;
154 : : }
155 : : static inline size_t utf8_charlen(const byte *str, size_t len) {
156 : : (void)str;
157 : : return len;
158 : : }
159 : : #endif
160 : :
161 : : bool unichar_isspace(unichar c);
162 : : bool unichar_isalpha(unichar c);
163 : : bool unichar_isprint(unichar c);
164 : : bool unichar_isdigit(unichar c);
165 : : bool unichar_isxdigit(unichar c);
166 : : bool unichar_isident(unichar c);
167 : : bool unichar_isalnum(unichar c);
168 : : bool unichar_isupper(unichar c);
169 : : bool unichar_islower(unichar c);
170 : : unichar unichar_tolower(unichar c);
171 : : unichar unichar_toupper(unichar c);
172 : : mp_uint_t unichar_xdigit_value(unichar c);
173 : : #define UTF8_IS_NONASCII(ch) ((ch) & 0x80)
174 : : #define UTF8_IS_CONT(ch) (((ch) & 0xC0) == 0x80)
175 : :
176 : : /** variable string *********************************************/
177 : :
178 : : typedef struct _vstr_t {
179 : : size_t alloc;
180 : : size_t len;
181 : : char *buf;
182 : : bool fixed_buf;
183 : : } vstr_t;
184 : :
185 : : // convenience macro to declare a vstr with a fixed size buffer on the stack
186 : : #define VSTR_FIXED(vstr, alloc) vstr_t vstr; char vstr##_buf[(alloc)]; vstr_init_fixed_buf(&vstr, (alloc), vstr##_buf);
187 : :
188 : : void vstr_init(vstr_t *vstr, size_t alloc);
189 : : void vstr_init_len(vstr_t *vstr, size_t len);
190 : : void vstr_init_fixed_buf(vstr_t *vstr, size_t alloc, char *buf);
191 : : struct _mp_print_t;
192 : : void vstr_init_print(vstr_t *vstr, size_t alloc, struct _mp_print_t *print);
193 : : void vstr_clear(vstr_t *vstr);
194 : : vstr_t *vstr_new(size_t alloc);
195 : : void vstr_free(vstr_t *vstr);
196 : 537365 : static inline void vstr_reset(vstr_t *vstr) {
197 : 537333 : vstr->len = 0;
198 : 1504 : }
199 : 275 : static inline char *vstr_str(vstr_t *vstr) {
200 [ + + + + ]: 263 : return vstr->buf;
201 : : }
202 : 1669 : static inline size_t vstr_len(vstr_t *vstr) {
203 [ + + + + : 1669 : return vstr->len;
+ + + + +
- + + + +
+ + + + +
- ]
204 : : }
205 : : void vstr_hint_size(vstr_t *vstr, size_t size);
206 : : char *vstr_extend(vstr_t *vstr, size_t size);
207 : : char *vstr_add_len(vstr_t *vstr, size_t len);
208 : : char *vstr_null_terminated_str(vstr_t *vstr);
209 : : void vstr_add_byte(vstr_t *vstr, byte v);
210 : : void vstr_add_char(vstr_t *vstr, unichar chr);
211 : : void vstr_add_str(vstr_t *vstr, const char *str);
212 : : void vstr_add_strn(vstr_t *vstr, const char *str, size_t len);
213 : : void vstr_ins_byte(vstr_t *vstr, size_t byte_pos, byte b);
214 : : void vstr_ins_char(vstr_t *vstr, size_t char_pos, unichar chr);
215 : : void vstr_cut_head_bytes(vstr_t *vstr, size_t bytes_to_cut);
216 : : void vstr_cut_tail_bytes(vstr_t *vstr, size_t bytes_to_cut);
217 : : void vstr_cut_out_bytes(vstr_t *vstr, size_t byte_pos, size_t bytes_to_cut);
218 : : void vstr_printf(vstr_t *vstr, const char *fmt, ...);
219 : :
220 : : /** non-dynamic size-bounded variable buffer/string *************/
221 : :
222 : : #define CHECKBUF(buf, max_size) char buf[max_size + 1]; size_t buf##_len = max_size; char *buf##_p = buf;
223 : : #define CHECKBUF_RESET(buf, max_size) buf##_len = max_size; buf##_p = buf;
224 : : #define CHECKBUF_APPEND(buf, src, src_len) \
225 : : { size_t l = MIN(src_len, buf##_len); \
226 : : memcpy(buf##_p, src, l); \
227 : : buf##_len -= l; \
228 : : buf##_p += l; }
229 : : #define CHECKBUF_APPEND_0(buf) { *buf##_p = 0; }
230 : : #define CHECKBUF_LEN(buf) (buf##_p - buf)
231 : :
232 : : #ifdef va_start
233 : : void vstr_vprintf(vstr_t *vstr, const char *fmt, va_list ap);
234 : : #endif
235 : :
236 : : // Debugging helpers
237 : : int DEBUG_printf(const char *fmt, ...);
238 : :
239 : : extern mp_uint_t mp_verbose_flag;
240 : :
241 : : /** float internals *************/
242 : :
243 : : #if MICROPY_PY_BUILTINS_FLOAT
244 : :
245 : : #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE
246 : : #define MP_FLOAT_EXP_BITS (11)
247 : : #define MP_FLOAT_EXP_OFFSET (1023)
248 : : #define MP_FLOAT_FRAC_BITS (52)
249 : : typedef uint64_t mp_float_uint_t;
250 : : #elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
251 : : #define MP_FLOAT_EXP_BITS (8)
252 : : #define MP_FLOAT_EXP_OFFSET (127)
253 : : #define MP_FLOAT_FRAC_BITS (23)
254 : : typedef uint32_t mp_float_uint_t;
255 : : #endif
256 : :
257 : : #define MP_FLOAT_EXP_BIAS ((1 << (MP_FLOAT_EXP_BITS - 1)) - 1)
258 : :
259 : : typedef union _mp_float_union_t {
260 : : mp_float_t f;
261 : : #if MP_ENDIANNESS_LITTLE
262 : : struct {
263 : : mp_float_uint_t frc : MP_FLOAT_FRAC_BITS;
264 : : mp_float_uint_t exp : MP_FLOAT_EXP_BITS;
265 : : mp_float_uint_t sgn : 1;
266 : : } p;
267 : : #else
268 : : struct {
269 : : mp_float_uint_t sgn : 1;
270 : : mp_float_uint_t exp : MP_FLOAT_EXP_BITS;
271 : : mp_float_uint_t frc : MP_FLOAT_FRAC_BITS;
272 : : } p;
273 : : #endif
274 : : mp_float_uint_t i;
275 : : } mp_float_union_t;
276 : :
277 : : #endif // MICROPY_PY_BUILTINS_FLOAT
278 : :
279 : : /** ROM string compression *************/
280 : :
281 : : #if MICROPY_ROM_TEXT_COMPRESSION
282 : :
283 : : #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_NONE
284 : : #error "MICROPY_ERROR_REPORTING_NONE requires MICROPY_ROM_TEXT_COMPRESSION disabled"
285 : : #endif
286 : :
287 : : #ifdef NO_QSTR
288 : :
289 : : // Compression enabled but doing QSTR extraction.
290 : : // So leave MP_COMPRESSED_ROM_TEXT in place for makeqstrdefs.py / makecompresseddata.py to find them.
291 : :
292 : : #else
293 : :
294 : : // Compression enabled and doing a regular build.
295 : : // Map MP_COMPRESSED_ROM_TEXT to the compressed strings.
296 : :
297 : : // Force usage of the MP_ERROR_TEXT macro by requiring an opaque type.
298 : : typedef struct {
299 : : #if defined(__clang__) || defined(_MSC_VER)
300 : : // Fix "error: empty struct has size 0 in C, size 1 in C++", and the msvc counterpart
301 : : // "C requires that a struct or union have at least one member"
302 : : char dummy;
303 : : #endif
304 : : } *mp_rom_error_text_t;
305 : :
306 : : #include <string.h>
307 : :
308 : 2746 : inline MP_ALWAYSINLINE const char *MP_COMPRESSED_ROM_TEXT(const char *msg) {
309 : : // "genhdr/compressed.data.h" contains an invocation of the MP_MATCH_COMPRESSED macro for each compressed string.
310 : : // The giant if(strcmp) tree is optimized by the compiler, which turns this into a direct return of the compressed data.
311 : : #define MP_MATCH_COMPRESSED(a, b) if (strcmp(msg, a) == 0) { return b; } else
312 : :
313 : : // It also contains a single invocation of the MP_COMPRESSED_DATA macro, we don't need that here.
314 : : #define MP_COMPRESSED_DATA(x)
315 : :
316 : : #include "genhdr/compressed.data.h"
317 : :
318 : : #undef MP_COMPRESSED_DATA
319 : : #undef MP_MATCH_COMPRESSED
320 : :
321 : : return msg;
322 : : }
323 : :
324 : : #endif
325 : :
326 : : #else
327 : :
328 : : // Compression not enabled, just make it a no-op.
329 : :
330 : : typedef const char *mp_rom_error_text_t;
331 : : #define MP_COMPRESSED_ROM_TEXT(x) x
332 : :
333 : : #endif // MICROPY_ROM_TEXT_COMPRESSION
334 : :
335 : : // Might add more types of compressed text in the future.
336 : : // For now, forward directly to MP_COMPRESSED_ROM_TEXT.
337 : : #define MP_ERROR_TEXT(x) (mp_rom_error_text_t)MP_COMPRESSED_ROM_TEXT(x)
338 : :
339 : : #endif // MICROPY_INCLUDED_PY_MISC_H
|