blob: d22e0f342dfe384979574f4a74ea7e6667fa859c [file] [log] [blame]
Damien George04b91472014-05-03 23:27:38 +01001/*
2 * This file is part of the Micro Python 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
Paul Sokolovsky8bc35162014-02-14 17:16:35 +020027#include <stdint.h>
Paul Sokolovsky1355cf42014-04-19 01:25:49 +030028#include <stdlib.h>
Paul Sokolovskyecca53b2014-08-10 20:16:39 +030029#include <stddef.h>
Paul Sokolovsky62798832014-06-02 16:04:26 +030030#include <string.h>
Paul Sokolovsky8bc35162014-02-14 17:16:35 +020031#include <assert.h>
32
Damien George51dfcb42015-01-01 20:27:54 +000033#include "py/binary.h"
34#include "py/smallint.h"
Damien George271d18e2015-04-25 23:16:39 +010035#include "py/objint.h"
Paul Sokolovsky8bc35162014-02-14 17:16:35 +020036
37// Helpers to work with binary-encoded data
38
Paul Sokolovskyecca53b2014-08-10 20:16:39 +030039#ifndef alignof
40#define alignof(type) offsetof(struct { char c; type t; }, t)
41#endif
42
Kaspar Schleiserf5dd6f72015-05-10 13:04:38 +020043size_t mp_binary_get_size(char struct_type, char val_type, mp_uint_t *palign) {
44 size_t size = 0;
Paul Sokolovsky1355cf42014-04-19 01:25:49 +030045 int align = 1;
46 switch (struct_type) {
47 case '<': case '>':
48 switch (val_type) {
49 case 'b': case 'B':
50 size = 1; break;
51 case 'h': case 'H':
52 size = 2; break;
53 case 'i': case 'I':
54 size = 4; break;
55 case 'l': case 'L':
56 size = 4; break;
57 case 'q': case 'Q':
58 size = 8; break;
Paul Sokolovsky78fde482014-09-06 19:24:52 +030059 case 'P': case 'O': case 'S':
60 size = sizeof(void*); break;
Damien Georgec9f8f652014-11-21 18:16:25 +000061 case 'f':
62 size = sizeof(float); break;
63 case 'd':
64 size = sizeof(double); break;
Paul Sokolovsky1355cf42014-04-19 01:25:49 +030065 }
66 break;
67 case '@': {
68 // TODO:
69 // The simplest heuristic for alignment is to align by value
70 // size, but that doesn't work for "bigger than int" types,
71 // for example, long long may very well have long alignment
72 // So, we introduce separate alignment handling, but having
73 // formal support for that is different from actually supporting
74 // particular (or any) ABI.
75 switch (val_type) {
76 case BYTEARRAY_TYPECODE:
77 case 'b': case 'B':
78 align = size = 1; break;
79 case 'h': case 'H':
Paul Sokolovskyecca53b2014-08-10 20:16:39 +030080 align = alignof(short);
81 size = sizeof(short); break;
Paul Sokolovsky1355cf42014-04-19 01:25:49 +030082 case 'i': case 'I':
Paul Sokolovskyecca53b2014-08-10 20:16:39 +030083 align = alignof(int);
84 size = sizeof(int); break;
Paul Sokolovsky1355cf42014-04-19 01:25:49 +030085 case 'l': case 'L':
Paul Sokolovskyecca53b2014-08-10 20:16:39 +030086 align = alignof(long);
87 size = sizeof(long); break;
Paul Sokolovsky1355cf42014-04-19 01:25:49 +030088 case 'q': case 'Q':
Paul Sokolovskyecca53b2014-08-10 20:16:39 +030089 align = alignof(long long);
90 size = sizeof(long long); break;
Paul Sokolovsky62798832014-06-02 16:04:26 +030091 case 'P': case 'O': case 'S':
Paul Sokolovskyecca53b2014-08-10 20:16:39 +030092 align = alignof(void*);
93 size = sizeof(void*); break;
Damien Georgec9f8f652014-11-21 18:16:25 +000094 case 'f':
95 align = alignof(float);
96 size = sizeof(float); break;
97 case 'd':
98 align = alignof(double);
99 size = sizeof(double); break;
Paul Sokolovsky1355cf42014-04-19 01:25:49 +0300100 }
101 }
Paul Sokolovskyc2033242014-02-14 20:21:50 +0200102 }
Paul Sokolovsky1355cf42014-04-19 01:25:49 +0300103 if (palign != NULL) {
104 *palign = align;
105 }
106 return size;
Paul Sokolovskyc2033242014-02-14 20:21:50 +0200107}
108
Damien George42f3de92014-10-03 17:44:14 +0000109mp_obj_t mp_binary_get_val_array(char typecode, void *p, mp_uint_t index) {
Damien George40f3c022014-07-03 13:25:24 +0100110 mp_int_t val = 0;
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200111 switch (typecode) {
112 case 'b':
Paul Sokolovsky91232d32015-01-24 03:18:10 +0200113 val = ((signed char*)p)[index];
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200114 break;
115 case BYTEARRAY_TYPECODE:
116 case 'B':
Paul Sokolovsky91232d32015-01-24 03:18:10 +0200117 val = ((unsigned char*)p)[index];
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200118 break;
119 case 'h':
Paul Sokolovsky91232d32015-01-24 03:18:10 +0200120 val = ((short*)p)[index];
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200121 break;
122 case 'H':
Paul Sokolovsky91232d32015-01-24 03:18:10 +0200123 val = ((unsigned short*)p)[index];
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200124 break;
125 case 'i':
Paul Sokolovsky91232d32015-01-24 03:18:10 +0200126 return mp_obj_new_int(((int*)p)[index]);
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200127 case 'I':
Paul Sokolovsky91232d32015-01-24 03:18:10 +0200128 return mp_obj_new_int_from_uint(((unsigned int*)p)[index]);
129 case 'l':
130 return mp_obj_new_int(((long*)p)[index]);
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200131 case 'L':
Paul Sokolovsky91232d32015-01-24 03:18:10 +0200132 return mp_obj_new_int_from_uint(((unsigned long*)p)[index]);
Damien George81794fc2015-09-01 16:25:29 +0100133 #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200134 case 'q':
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200135 return mp_obj_new_int_from_ll(((long long*)p)[index]);
Damien George81794fc2015-09-01 16:25:29 +0100136 case 'Q':
137 return mp_obj_new_int_from_ull(((unsigned long long*)p)[index]);
138 #endif
Damien Georgefb510b32014-06-01 13:32:54 +0100139#if MICROPY_PY_BUILTINS_FLOAT
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200140 case 'f':
141 return mp_obj_new_float(((float*)p)[index]);
142 case 'd':
143 return mp_obj_new_float(((double*)p)[index]);
144#endif
Paul Sokolovsky24c10002015-03-05 22:57:36 +0200145 // Extension to CPython: array of objects
146 case 'O':
147 return ((mp_obj_t*)p)[index];
Paul Sokolovsky91fc0752015-10-12 10:10:39 +0300148 // Extension to CPython: array of pointers
149 case 'P':
Damien George999cedb2015-11-27 17:01:44 +0000150 return mp_obj_new_int((mp_int_t)(uintptr_t)((void**)p)[index]);
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200151 }
152 return MP_OBJ_NEW_SMALL_INT(val);
153}
154
Damien George95307432014-09-10 22:10:33 +0100155// The long long type is guaranteed to hold at least 64 bits, and size is at
156// most 8 (for q and Q), so we will always be able to parse the given data
157// and fit it into a long long.
Damien George9336ee32014-10-06 15:05:35 +0000158long long mp_binary_get_int(mp_uint_t size, bool is_signed, bool big_endian, const byte *src) {
Paul Sokolovsky7a2f1662014-06-25 22:25:53 +0300159 int delta;
160 if (!big_endian) {
161 delta = -1;
Damien George9336ee32014-10-06 15:05:35 +0000162 src += size - 1;
Paul Sokolovsky7a2f1662014-06-25 22:25:53 +0300163 } else {
164 delta = 1;
165 }
166
Damien George95307432014-09-10 22:10:33 +0100167 long long val = 0;
Damien George9336ee32014-10-06 15:05:35 +0000168 if (is_signed && *src & 0x80) {
Paul Sokolovsky7a2f1662014-06-25 22:25:53 +0300169 val = -1;
170 }
171 for (uint i = 0; i < size; i++) {
172 val <<= 8;
Damien George9336ee32014-10-06 15:05:35 +0000173 val |= *src;
174 src += delta;
Paul Sokolovsky7a2f1662014-06-25 22:25:53 +0300175 }
176
177 return val;
178}
179
Paul Sokolovsky6582d642014-04-10 22:19:32 +0300180#define is_signed(typecode) (typecode > 'Z')
Paul Sokolovsky0c43cf92014-04-11 03:47:21 +0300181mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte **ptr) {
Paul Sokolovskye9db8402014-04-10 03:45:38 +0300182 byte *p = *ptr;
Damien George4abff752014-08-30 14:59:21 +0100183 mp_uint_t align;
Paul Sokolovsky1355cf42014-04-19 01:25:49 +0300184
Kaspar Schleiserf5dd6f72015-05-10 13:04:38 +0200185 size_t size = mp_binary_get_size(struct_type, val_type, &align);
Paul Sokolovsky1355cf42014-04-19 01:25:49 +0300186 if (struct_type == '@') {
187 // Make pointer aligned
Damien George88a91032015-11-27 12:05:11 +0000188 p = (byte*)MP_ALIGN(p, (size_t)align);
Paul Sokolovsky1355cf42014-04-19 01:25:49 +0300189 #if MP_ENDIANNESS_LITTLE
190 struct_type = '<';
191 #else
192 struct_type = '>';
193 #endif
Paul Sokolovskye9db8402014-04-10 03:45:38 +0300194 }
Paul Sokolovsky7a2f1662014-06-25 22:25:53 +0300195 *ptr = p + size;
Paul Sokolovsky6582d642014-04-10 22:19:32 +0300196
Damien George95307432014-09-10 22:10:33 +0100197 long long val = mp_binary_get_int(size, is_signed(val_type), (struct_type == '>'), p);
Paul Sokolovsky6582d642014-04-10 22:19:32 +0300198
Paul Sokolovsky0f836ef2014-04-20 05:19:10 +0300199 if (val_type == 'O') {
Damien George95307432014-09-10 22:10:33 +0100200 return (mp_obj_t)(mp_uint_t)val;
Paul Sokolovsky62798832014-06-02 16:04:26 +0300201 } else if (val_type == 'S') {
Damien George999cedb2015-11-27 17:01:44 +0000202 const char *s_val = (const char*)(uintptr_t)(mp_uint_t)val;
Damien George95307432014-09-10 22:10:33 +0100203 return mp_obj_new_str(s_val, strlen(s_val), false);
David Steinberg0b3014c2015-01-25 02:50:34 +0000204#if MICROPY_PY_BUILTINS_FLOAT
205 } else if (val_type == 'f') {
206 union { uint32_t i; float f; } fpu = {val};
207 return mp_obj_new_float(fpu.f);
208 } else if (val_type == 'd') {
209 union { uint64_t i; double f; } fpu = {val};
210 return mp_obj_new_float(fpu.f);
211#endif
Paul Sokolovsky0f836ef2014-04-20 05:19:10 +0300212 } else if (is_signed(val_type)) {
Damien George95307432014-09-10 22:10:33 +0100213 if ((long long)MP_SMALL_INT_MIN <= val && val <= (long long)MP_SMALL_INT_MAX) {
214 return mp_obj_new_int((mp_int_t)val);
215 } else {
216 return mp_obj_new_int_from_ll(val);
217 }
Paul Sokolovsky6582d642014-04-10 22:19:32 +0300218 } else {
Damien George95307432014-09-10 22:10:33 +0100219 if ((unsigned long long)val <= (unsigned long long)MP_SMALL_INT_MAX) {
220 return mp_obj_new_int_from_uint((mp_uint_t)val);
221 } else {
222 return mp_obj_new_int_from_ull(val);
223 }
Paul Sokolovsky6582d642014-04-10 22:19:32 +0300224 }
Paul Sokolovskye9db8402014-04-10 03:45:38 +0300225}
226
Damien George9336ee32014-10-06 15:05:35 +0000227void mp_binary_set_int(mp_uint_t val_sz, bool big_endian, byte *dest, mp_uint_t val) {
228 if (MP_ENDIANNESS_LITTLE && !big_endian) {
229 memcpy(dest, &val, val_sz);
230 } else if (MP_ENDIANNESS_BIG && big_endian) {
231 // only copy the least-significant val_sz bytes
232 memcpy(dest, (byte*)&val + sizeof(mp_uint_t) - val_sz, val_sz);
Paul Sokolovsky5fa5ca42014-07-05 23:43:00 +0300233 } else {
Damien George9336ee32014-10-06 15:05:35 +0000234 const byte *src;
235 if (MP_ENDIANNESS_LITTLE) {
236 src = (const byte*)&val + val_sz;
237 } else {
238 src = (const byte*)&val + sizeof(mp_uint_t);
239 }
240 while (val_sz--) {
241 *dest++ = *--src;
242 }
Paul Sokolovsky5fa5ca42014-07-05 23:43:00 +0300243 }
244}
245
Paul Sokolovsky62044602014-04-19 03:13:15 +0300246void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte **ptr) {
247 byte *p = *ptr;
Damien George4abff752014-08-30 14:59:21 +0100248 mp_uint_t align;
Paul Sokolovsky62044602014-04-19 03:13:15 +0300249
Kaspar Schleiserf5dd6f72015-05-10 13:04:38 +0200250 size_t size = mp_binary_get_size(struct_type, val_type, &align);
Paul Sokolovsky62044602014-04-19 03:13:15 +0300251 if (struct_type == '@') {
252 // Make pointer aligned
Damien George88a91032015-11-27 12:05:11 +0000253 p = (byte*)MP_ALIGN(p, (size_t)align);
Damien George9336ee32014-10-06 15:05:35 +0000254 if (MP_ENDIANNESS_LITTLE) {
255 struct_type = '<';
256 } else {
257 struct_type = '>';
258 }
Paul Sokolovsky62044602014-04-19 03:13:15 +0300259 }
Paul Sokolovsky7a2f1662014-06-25 22:25:53 +0300260 *ptr = p + size;
Paul Sokolovsky62044602014-04-19 03:13:15 +0300261
Damien George9336ee32014-10-06 15:05:35 +0000262 mp_uint_t val;
Paul Sokolovsky0f836ef2014-04-20 05:19:10 +0300263 switch (val_type) {
264 case 'O':
Damien George9336ee32014-10-06 15:05:35 +0000265 val = (mp_uint_t)val_in;
Paul Sokolovsky0f836ef2014-04-20 05:19:10 +0300266 break;
David Steinberg0b3014c2015-01-25 02:50:34 +0000267#if MICROPY_PY_BUILTINS_FLOAT
268 case 'f': {
269 union { uint32_t i; float f; } fp_sp;
270 fp_sp.f = mp_obj_get_float(val_in);
271 val = fp_sp.i;
272 break;
273 }
274 case 'd': {
275 union { uint64_t i64; uint32_t i32[2]; double f; } fp_dp;
276 fp_dp.f = mp_obj_get_float(val_in);
277 if (BYTES_PER_WORD == 8) {
278 val = fp_dp.i64;
279 } else {
280 int be = struct_type == '>';
281 mp_binary_set_int(sizeof(uint32_t), be, p, fp_dp.i32[MP_ENDIANNESS_BIG ^ be]);
282 p += sizeof(uint32_t);
283 val = fp_dp.i32[MP_ENDIANNESS_LITTLE ^ be];
284 }
285 break;
286 }
287#endif
Paul Sokolovsky0f836ef2014-04-20 05:19:10 +0300288 default:
Damien George271d18e2015-04-25 23:16:39 +0100289 #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
Damien Georgebe6d8be2014-12-05 23:13:52 +0000290 if (MP_OBJ_IS_TYPE(val_in, &mp_type_int)) {
Damien George271d18e2015-04-25 23:16:39 +0100291 mp_obj_int_to_bytes_impl(val_in, struct_type == '>', size, p);
292 return;
293 } else
294 #endif
295 {
Damien Georgebe6d8be2014-12-05 23:13:52 +0000296 val = mp_obj_get_int(val_in);
Damien Georgea3c61002016-12-12 15:00:06 +1100297 // zero/sign extend if needed
298 if (BYTES_PER_WORD < 8 && size > sizeof(val)) {
299 int c = (is_signed(val_type) && (mp_int_t)val < 0) ? 0xff : 0x00;
300 memset(p + sizeof(val), c, size - sizeof(val));
Damien George94729072015-04-25 23:51:14 +0100301 }
Damien Georgebe6d8be2014-12-05 23:13:52 +0000302 }
Paul Sokolovsky0f836ef2014-04-20 05:19:10 +0300303 }
304
Damien George963a5a32015-01-16 17:47:07 +0000305 mp_binary_set_int(MIN((size_t)size, sizeof(val)), struct_type == '>', p, val);
Paul Sokolovsky62044602014-04-19 03:13:15 +0300306}
307
Damien George42f3de92014-10-03 17:44:14 +0000308void mp_binary_set_val_array(char typecode, void *p, mp_uint_t index, mp_obj_t val_in) {
Damien George71e9bfa2014-04-18 23:28:12 +0100309 switch (typecode) {
Damien Georgefb510b32014-06-01 13:32:54 +0100310#if MICROPY_PY_BUILTINS_FLOAT
Damien George71e9bfa2014-04-18 23:28:12 +0100311 case 'f':
Damien Georgec9f8f652014-11-21 18:16:25 +0000312 ((float*)p)[index] = mp_obj_get_float(val_in);
Damien George71e9bfa2014-04-18 23:28:12 +0100313 break;
314 case 'd':
Damien Georgec9f8f652014-11-21 18:16:25 +0000315 ((double*)p)[index] = mp_obj_get_float(val_in);
Damien George71e9bfa2014-04-18 23:28:12 +0100316 break;
317#endif
Paul Sokolovsky24c10002015-03-05 22:57:36 +0200318 // Extension to CPython: array of objects
319 case 'O':
320 ((mp_obj_t*)p)[index] = val_in;
321 break;
Damien George71e9bfa2014-04-18 23:28:12 +0100322 default:
Damien George81794fc2015-09-01 16:25:29 +0100323 #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
324 if ((typecode | 0x20) == 'q' && MP_OBJ_IS_TYPE(val_in, &mp_type_int)) {
325 mp_obj_int_to_bytes_impl(val_in, MP_ENDIANNESS_BIG,
326 sizeof(long long), (byte*)&((long long*)p)[index]);
327 return;
328 }
329 #endif
Damien George71e9bfa2014-04-18 23:28:12 +0100330 mp_binary_set_val_array_from_int(typecode, p, index, mp_obj_get_int(val_in));
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200331 }
Damien George71e9bfa2014-04-18 23:28:12 +0100332}
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200333
Damien George42f3de92014-10-03 17:44:14 +0000334void mp_binary_set_val_array_from_int(char typecode, void *p, mp_uint_t index, mp_int_t val) {
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200335 switch (typecode) {
336 case 'b':
Paul Sokolovsky91232d32015-01-24 03:18:10 +0200337 ((signed char*)p)[index] = val;
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200338 break;
339 case BYTEARRAY_TYPECODE:
340 case 'B':
Paul Sokolovsky91232d32015-01-24 03:18:10 +0200341 ((unsigned char*)p)[index] = val;
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200342 break;
343 case 'h':
Paul Sokolovsky91232d32015-01-24 03:18:10 +0200344 ((short*)p)[index] = val;
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200345 break;
346 case 'H':
Paul Sokolovsky91232d32015-01-24 03:18:10 +0200347 ((unsigned short*)p)[index] = val;
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200348 break;
349 case 'i':
Paul Sokolovsky91232d32015-01-24 03:18:10 +0200350 ((int*)p)[index] = val;
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200351 break;
352 case 'I':
Paul Sokolovsky91232d32015-01-24 03:18:10 +0200353 ((unsigned int*)p)[index] = val;
354 break;
355 case 'l':
356 ((long*)p)[index] = val;
357 break;
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200358 case 'L':
Paul Sokolovsky91232d32015-01-24 03:18:10 +0200359 ((unsigned long*)p)[index] = val;
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200360 break;
Damien George81794fc2015-09-01 16:25:29 +0100361 #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200362 case 'q':
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200363 ((long long*)p)[index] = val;
Damien George81794fc2015-09-01 16:25:29 +0100364 case 'Q':
365 ((unsigned long long*)p)[index] = val;
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200366 break;
Damien George81794fc2015-09-01 16:25:29 +0100367 #endif
Damien Georgefb510b32014-06-01 13:32:54 +0100368#if MICROPY_PY_BUILTINS_FLOAT
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200369 case 'f':
Damien George71e9bfa2014-04-18 23:28:12 +0100370 ((float*)p)[index] = val;
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200371 break;
372 case 'd':
Damien George71e9bfa2014-04-18 23:28:12 +0100373 ((double*)p)[index] = val;
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200374 break;
375#endif
Paul Sokolovsky91fc0752015-10-12 10:10:39 +0300376 // Extension to CPython: array of pointers
377 case 'P':
Damien George999cedb2015-11-27 17:01:44 +0000378 ((void**)p)[index] = (void*)(uintptr_t)val;
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200379 }
380}