Numworks Epsilon  1.4.1
Graphing Calculator Operating System
binary.c
Go to the documentation of this file.
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 
27 #include <stdint.h>
28 #include <stdlib.h>
29 #include <stddef.h>
30 #include <string.h>
31 #include <assert.h>
32 
33 #include "py/binary.h"
34 #include "py/smallint.h"
35 #include "py/objint.h"
36 #include "py/runtime.h"
37 
38 // Helpers to work with binary-encoded data
39 
40 #ifndef alignof
41 #define alignof(type) offsetof(struct { char c; type t; }, t)
42 #endif
43 
44 size_t mp_binary_get_size(char struct_type, char val_type, mp_uint_t *palign) {
45  size_t size = 0;
46  int align = 1;
47  switch (struct_type) {
48  case '<': case '>':
49  switch (val_type) {
50  case 'b': case 'B':
51  size = 1; break;
52  case 'h': case 'H':
53  size = 2; break;
54  case 'i': case 'I':
55  size = 4; break;
56  case 'l': case 'L':
57  size = 4; break;
58  case 'q': case 'Q':
59  size = 8; break;
60  case 'P': case 'O': case 'S':
61  size = sizeof(void*); break;
62  case 'f':
63  size = sizeof(float); break;
64  case 'd':
65  size = sizeof(double); break;
66  }
67  break;
68  case '@': {
69  // TODO:
70  // The simplest heuristic for alignment is to align by value
71  // size, but that doesn't work for "bigger than int" types,
72  // for example, long long may very well have long alignment
73  // So, we introduce separate alignment handling, but having
74  // formal support for that is different from actually supporting
75  // particular (or any) ABI.
76  switch (val_type) {
77  case BYTEARRAY_TYPECODE:
78  case 'b': case 'B':
79  align = size = 1; break;
80  case 'h': case 'H':
81  align = alignof(short);
82  size = sizeof(short); break;
83  case 'i': case 'I':
84  align = alignof(int);
85  size = sizeof(int); break;
86  case 'l': case 'L':
87  align = alignof(long);
88  size = sizeof(long); break;
89  case 'q': case 'Q':
90  align = alignof(long long);
91  size = sizeof(long long); break;
92  case 'P': case 'O': case 'S':
93  align = alignof(void*);
94  size = sizeof(void*); break;
95  case 'f':
96  align = alignof(float);
97  size = sizeof(float); break;
98  case 'd':
99  align = alignof(double);
100  size = sizeof(double); break;
101  }
102  }
103  }
104 
105  if (size == 0) {
106  mp_raise_ValueError("bad typecode");
107  }
108 
109  if (palign != NULL) {
110  *palign = align;
111  }
112  return size;
113 }
114 
115 mp_obj_t mp_binary_get_val_array(char typecode, void *p, mp_uint_t index) {
116  mp_int_t val = 0;
117  switch (typecode) {
118  case 'b':
119  val = ((signed char*)p)[index];
120  break;
121  case BYTEARRAY_TYPECODE:
122  case 'B':
123  val = ((unsigned char*)p)[index];
124  break;
125  case 'h':
126  val = ((short*)p)[index];
127  break;
128  case 'H':
129  val = ((unsigned short*)p)[index];
130  break;
131  case 'i':
132  return mp_obj_new_int(((int*)p)[index]);
133  case 'I':
134  return mp_obj_new_int_from_uint(((unsigned int*)p)[index]);
135  case 'l':
136  return mp_obj_new_int(((long*)p)[index]);
137  case 'L':
138  return mp_obj_new_int_from_uint(((unsigned long*)p)[index]);
139  #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
140  case 'q':
141  return mp_obj_new_int_from_ll(((long long*)p)[index]);
142  case 'Q':
143  return mp_obj_new_int_from_ull(((unsigned long long*)p)[index]);
144  #endif
145 #if MICROPY_PY_BUILTINS_FLOAT
146  case 'f':
147  return mp_obj_new_float(((float*)p)[index]);
148  case 'd':
149  return mp_obj_new_float(((double*)p)[index]);
150 #endif
151  // Extension to CPython: array of objects
152  case 'O':
153  return ((mp_obj_t*)p)[index];
154  // Extension to CPython: array of pointers
155  case 'P':
156  return mp_obj_new_int((mp_int_t)(uintptr_t)((void**)p)[index]);
157  }
158  return MP_OBJ_NEW_SMALL_INT(val);
159 }
160 
161 // The long long type is guaranteed to hold at least 64 bits, and size is at
162 // most 8 (for q and Q), so we will always be able to parse the given data
163 // and fit it into a long long.
164 long long mp_binary_get_int(mp_uint_t size, bool is_signed, bool big_endian, const byte *src) {
165  int delta;
166  if (!big_endian) {
167  delta = -1;
168  src += size - 1;
169  } else {
170  delta = 1;
171  }
172 
173  long long val = 0;
174  if (is_signed && *src & 0x80) {
175  val = -1;
176  }
177  for (uint i = 0; i < size; i++) {
178  val <<= 8;
179  val |= *src;
180  src += delta;
181  }
182 
183  return val;
184 }
185 
186 #define is_signed(typecode) (typecode > 'Z')
187 mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte **ptr) {
188  byte *p = *ptr;
189  mp_uint_t align;
190 
191  size_t size = mp_binary_get_size(struct_type, val_type, &align);
192  if (struct_type == '@') {
193  // Make pointer aligned
194  p = (byte*)MP_ALIGN(p, (size_t)align);
195  #if MP_ENDIANNESS_LITTLE
196  struct_type = '<';
197  #else
198  struct_type = '>';
199  #endif
200  }
201  *ptr = p + size;
202 
203  long long val = mp_binary_get_int(size, is_signed(val_type), (struct_type == '>'), p);
204 
205  if (val_type == 'O') {
206  return (mp_obj_t)(mp_uint_t)val;
207  } else if (val_type == 'S') {
208  const char *s_val = (const char*)(uintptr_t)(mp_uint_t)val;
209  return mp_obj_new_str(s_val, strlen(s_val), false);
210 #if MICROPY_PY_BUILTINS_FLOAT
211  } else if (val_type == 'f') {
212  union { uint32_t i; float f; } fpu = {val};
213  return mp_obj_new_float(fpu.f);
214  } else if (val_type == 'd') {
215  union { uint64_t i; double f; } fpu = {val};
216  return mp_obj_new_float(fpu.f);
217 #endif
218  } else if (is_signed(val_type)) {
219  if ((long long)MP_SMALL_INT_MIN <= val && val <= (long long)MP_SMALL_INT_MAX) {
220  return mp_obj_new_int((mp_int_t)val);
221  } else {
222  return mp_obj_new_int_from_ll(val);
223  }
224  } else {
225  if ((unsigned long long)val <= (unsigned long long)MP_SMALL_INT_MAX) {
226  return mp_obj_new_int_from_uint((mp_uint_t)val);
227  } else {
228  return mp_obj_new_int_from_ull(val);
229  }
230  }
231 }
232 
233 void mp_binary_set_int(mp_uint_t val_sz, bool big_endian, byte *dest, mp_uint_t val) {
234  if (MP_ENDIANNESS_LITTLE && !big_endian) {
235  memcpy(dest, &val, val_sz);
236  } else if (MP_ENDIANNESS_BIG && big_endian) {
237  // only copy the least-significant val_sz bytes
238  memcpy(dest, (byte*)&val + sizeof(mp_uint_t) - val_sz, val_sz);
239  } else {
240  const byte *src;
241  if (MP_ENDIANNESS_LITTLE) {
242  src = (const byte*)&val + val_sz;
243  } else {
244  src = (const byte*)&val + sizeof(mp_uint_t);
245  }
246  while (val_sz--) {
247  *dest++ = *--src;
248  }
249  }
250 }
251 
252 void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte **ptr) {
253  byte *p = *ptr;
254  mp_uint_t align;
255 
256  size_t size = mp_binary_get_size(struct_type, val_type, &align);
257  if (struct_type == '@') {
258  // Make pointer aligned
259  p = (byte*)MP_ALIGN(p, (size_t)align);
260  if (MP_ENDIANNESS_LITTLE) {
261  struct_type = '<';
262  } else {
263  struct_type = '>';
264  }
265  }
266  *ptr = p + size;
267 
268  mp_uint_t val;
269  switch (val_type) {
270  case 'O':
271  val = (mp_uint_t)val_in;
272  break;
273 #if MICROPY_PY_BUILTINS_FLOAT
274  case 'f': {
275  union { uint32_t i; float f; } fp_sp;
276  fp_sp.f = mp_obj_get_float(val_in);
277  val = fp_sp.i;
278  break;
279  }
280  case 'd': {
281  union { uint64_t i64; uint32_t i32[2]; double f; } fp_dp;
282  fp_dp.f = mp_obj_get_float(val_in);
283  if (BYTES_PER_WORD == 8) {
284  val = fp_dp.i64;
285  } else {
286  int be = struct_type == '>';
287  mp_binary_set_int(sizeof(uint32_t), be, p, fp_dp.i32[MP_ENDIANNESS_BIG ^ be]);
288  p += sizeof(uint32_t);
289  val = fp_dp.i32[MP_ENDIANNESS_LITTLE ^ be];
290  }
291  break;
292  }
293 #endif
294  default:
295  #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
296  if (MP_OBJ_IS_TYPE(val_in, &mp_type_int)) {
297  mp_obj_int_to_bytes_impl(val_in, struct_type == '>', size, p);
298  return;
299  } else
300  #endif
301  {
302  val = mp_obj_get_int(val_in);
303  // zero/sign extend if needed
304  if (BYTES_PER_WORD < 8 && size > sizeof(val)) {
305  int c = (is_signed(val_type) && (mp_int_t)val < 0) ? 0xff : 0x00;
306  memset(p, c, size);
307  if (struct_type == '>') {
308  p += size - sizeof(val);
309  }
310  }
311  }
312  }
313 
314  mp_binary_set_int(MIN((size_t)size, sizeof(val)), struct_type == '>', p, val);
315 }
316 
317 void mp_binary_set_val_array(char typecode, void *p, mp_uint_t index, mp_obj_t val_in) {
318  switch (typecode) {
319 #if MICROPY_PY_BUILTINS_FLOAT
320  case 'f':
321  ((float*)p)[index] = mp_obj_get_float(val_in);
322  break;
323  case 'd':
324  ((double*)p)[index] = mp_obj_get_float(val_in);
325  break;
326 #endif
327  // Extension to CPython: array of objects
328  case 'O':
329  ((mp_obj_t*)p)[index] = val_in;
330  break;
331  default:
332  #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
333  if (MP_OBJ_IS_TYPE(val_in, &mp_type_int)) {
334  size_t size = mp_binary_get_size('@', typecode, NULL);
336  size, (uint8_t*)p + index * size);
337  return;
338  }
339  #endif
340  mp_binary_set_val_array_from_int(typecode, p, index, mp_obj_get_int(val_in));
341  }
342 }
343 
344 void mp_binary_set_val_array_from_int(char typecode, void *p, mp_uint_t index, mp_int_t val) {
345  switch (typecode) {
346  case 'b':
347  ((signed char*)p)[index] = val;
348  break;
349  case BYTEARRAY_TYPECODE:
350  case 'B':
351  ((unsigned char*)p)[index] = val;
352  break;
353  case 'h':
354  ((short*)p)[index] = val;
355  break;
356  case 'H':
357  ((unsigned short*)p)[index] = val;
358  break;
359  case 'i':
360  ((int*)p)[index] = val;
361  break;
362  case 'I':
363  ((unsigned int*)p)[index] = val;
364  break;
365  case 'l':
366  ((long*)p)[index] = val;
367  break;
368  case 'L':
369  ((unsigned long*)p)[index] = val;
370  break;
371  #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
372  case 'q':
373  ((long long*)p)[index] = val;
374  break;
375  case 'Q':
376  ((unsigned long long*)p)[index] = val;
377  break;
378  #endif
379 #if MICROPY_PY_BUILTINS_FLOAT
380  case 'f':
381  ((float*)p)[index] = val;
382  break;
383  case 'd':
384  ((double*)p)[index] = val;
385  break;
386 #endif
387  // Extension to CPython: array of pointers
388  case 'P':
389  ((void**)p)[index] = (void*)(uintptr_t)val;
390  break;
391  }
392 }
#define MP_ALIGN(ptr, alignment)
Definition: misc.h:109
intptr_t mp_int_t
Definition: mpconfigport.h:73
uintptr_t mp_uint_t
Definition: mpconfigport.h:74
#define MP_SMALL_INT_MAX
Definition: smallint.h:62
#define BYTES_PER_WORD
Definition: mpconfig.h:1183
void * memset(void *b, int c, size_t len)
Definition: memset.c:3
void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte **ptr)
Definition: binary.c:252
#define MIN(x, y)
Definition: table_view.cpp:8
#define MP_OBJ_IS_TYPE(o, t)
Definition: obj.h:254
unsigned int uintptr_t
Definition: stdint.h:14
size_t mp_binary_get_size(char struct_type, char val_type, mp_uint_t *palign)
Definition: binary.c:44
#define BYTEARRAY_TYPECODE
Definition: binary.h:34
unsigned char uint8_t
Definition: stdint.h:4
mp_int_t mp_obj_get_int(mp_const_obj_t arg)
Definition: obj.c:225
mp_obj_t mp_obj_new_int_from_ll(long long val)
Definition: objint.c:332
mp_obj_t mp_obj_new_int_from_ull(unsigned long long val)
Definition: objint.c:338
long long mp_binary_get_int(mp_uint_t size, bool is_signed, bool big_endian, const byte *src)
Definition: binary.c:164
c(generic_all_nodes)
#define MP_OBJ_NEW_SMALL_INT(small_int)
Definition: obj.h:87
size_t strlen(const char *s)
Definition: strlen.c:3
unsigned int uint32_t
Definition: stdint.h:6
#define NULL
Definition: stddef.h:4
unsigned long long uint64_t
Definition: stdint.h:7
void mp_binary_set_val_array(char typecode, void *p, mp_uint_t index, mp_obj_t val_in)
Definition: binary.c:317
mp_obj_t mp_obj_new_int_from_uint(mp_uint_t value)
Definition: objint.c:343
mp_obj_t mp_obj_new_str(const char *data, size_t len, bool make_qstr_if_not_already)
Definition: objstr.c:2025
mp_obj_t mp_binary_get_val_array(char typecode, void *p, mp_uint_t index)
Definition: binary.c:115
mp_obj_t mp_obj_new_int(mp_int_t value)
Definition: objint.c:353
#define is_signed(typecode)
Definition: binary.c:186
unsigned char byte
Definition: misc.h:37
void mp_binary_set_val_array_from_int(char typecode, void *p, mp_uint_t index, mp_int_t val)
Definition: binary.c:344
NORETURN void mp_raise_ValueError(const char *msg)
Definition: runtime.c:1456
#define MP_ENDIANNESS_BIG
Definition: mpconfig.h:1221
void mp_binary_set_int(mp_uint_t val_sz, bool big_endian, byte *dest, mp_uint_t val)
Definition: binary.c:233
mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte **ptr)
Definition: binary.c:187
uint64_t mp_obj_t
Definition: obj.h:39
#define MP_SMALL_INT_MIN
Definition: smallint.h:39
const mp_obj_type_t mp_type_int
Definition: obj.h:544
void mp_obj_int_to_bytes_impl(mp_obj_t self_in, bool big_endian, size_t len, byte *buf)
void * memcpy(void *dst, const void *src, size_t n)
Definition: memcpy.c:3
unsigned int uint
Definition: misc.h:38