blob: 74b7564550087d365d30ef37bb02c9363f310400 [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
Damien George660aef62014-04-02 12:22:07 +010027#include <stdlib.h>
Damien George45b43c22014-01-05 01:50:45 +000028#include <stdint.h>
Damien George45b43c22014-01-05 01:50:45 +000029#include <assert.h>
Dave Hylandsc4029e52014-04-07 11:19:51 -070030#include <string.h>
Damien George45b43c22014-01-05 01:50:45 +000031
Paul Sokolovskyf54bcbf2014-05-02 17:47:01 +030032#include "mpconfig.h"
Damien George45b43c22014-01-05 01:50:45 +000033#include "nlr.h"
34#include "misc.h"
Damien George55baff42014-01-21 21:40:13 +000035#include "qstr.h"
Damien George45b43c22014-01-05 01:50:45 +000036#include "obj.h"
Damien George20773972014-02-22 18:12:43 +000037#include "parsenum.h"
Damien Georged1e355e2014-05-28 14:51:12 +010038#include "smallint.h"
Damien George438c88d2014-02-22 19:25:23 +000039#include "mpz.h"
Paul Sokolovsky76a90f22014-01-13 22:31:01 +020040#include "objint.h"
Damien George660aef62014-04-02 12:22:07 +010041#include "runtime0.h"
42#include "runtime.h"
Paul Sokolovsky48b35722014-01-12 17:30:48 +020043
Damien Georgefb510b32014-06-01 13:32:54 +010044#if MICROPY_PY_BUILTINS_FLOAT
Damien George6433bd92014-03-30 23:13:16 +010045#include <math.h>
46#endif
47
Damien Georgee8208a72014-04-04 15:08:23 +010048// This dispatcher function is expected to be independent of the implementation of long int
49STATIC mp_obj_t mp_obj_int_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
Damien Georgeee7a8802014-05-11 18:37:21 +010050 mp_arg_check_num(n_args, n_kw, 0, 2, false);
Damien George20006db2014-01-18 14:10:48 +000051
Damien George45b43c22014-01-05 01:50:45 +000052 switch (n_args) {
53 case 0:
54 return MP_OBJ_NEW_SMALL_INT(0);
55
56 case 1:
Damien George813ed3b2014-05-28 14:09:46 +010057 if (MP_OBJ_IS_INT(args[0])) {
58 // already an int (small or long), just return it
59 return args[0];
60 } else if (MP_OBJ_IS_STR(args[0])) {
Damien George5573f9f2014-01-15 22:58:39 +000061 // a string, parse it
Damien George5fa93b62014-01-22 14:35:10 +000062 uint l;
Damien George698ec212014-02-08 18:17:23 +000063 const char *s = mp_obj_str_get_data(args[0], &l);
Damien George20773972014-02-22 18:12:43 +000064 return mp_parse_num_integer(s, l, 0);
Damien Georgefb510b32014-06-01 13:32:54 +010065#if MICROPY_PY_BUILTINS_FLOAT
Damien George6433bd92014-03-30 23:13:16 +010066 } else if (MP_OBJ_IS_TYPE(args[0], &mp_type_float)) {
67 return MP_OBJ_NEW_SMALL_INT((machine_int_t)(MICROPY_FLOAT_C_FUN(trunc)(mp_obj_float_get(args[0]))));
68#endif
Damien George5573f9f2014-01-15 22:58:39 +000069 } else {
Damien George813ed3b2014-05-28 14:09:46 +010070 // try to convert to small int (eg from bool)
Damien George5573f9f2014-01-15 22:58:39 +000071 return MP_OBJ_NEW_SMALL_INT(mp_obj_get_int(args[0]));
72 }
Damien George45b43c22014-01-05 01:50:45 +000073
xybc178ea42014-01-14 21:39:05 +080074 case 2:
Damien Georgeee7a8802014-05-11 18:37:21 +010075 default: {
Damien George5573f9f2014-01-15 22:58:39 +000076 // should be a string, parse it
77 // TODO proper error checking of argument types
Damien George5fa93b62014-01-22 14:35:10 +000078 uint l;
Damien George698ec212014-02-08 18:17:23 +000079 const char *s = mp_obj_str_get_data(args[0], &l);
Damien George20773972014-02-22 18:12:43 +000080 return mp_parse_num_integer(s, l, mp_obj_get_int(args[1]));
Damien George5fa93b62014-01-22 14:35:10 +000081 }
Damien George45b43c22014-01-05 01:50:45 +000082 }
83}
84
Damien Georgee8208a72014-04-04 15:08:23 +010085void mp_obj_int_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
Dave Hylandsc4029e52014-04-07 11:19:51 -070086 // The size of this buffer is rather arbitrary. If it's not large
87 // enough, a dynamic one will be allocated.
88 char stack_buf[sizeof(machine_int_t) * 4];
89 char *buf = stack_buf;
90 int buf_size = sizeof(stack_buf);
91 int fmt_size;
92
93 char *str = mp_obj_int_formatted(&buf, &buf_size, &fmt_size, self_in, 10, NULL, '\0', '\0');
94 print(env, "%s", str);
95
96 if (buf != stack_buf) {
97 m_free(buf, buf_size);
Damien George5fa93b62014-01-22 14:35:10 +000098 }
Damien George45b43c22014-01-05 01:50:45 +000099}
Paul Sokolovsky48b35722014-01-12 17:30:48 +0200100
Dave Hylandsc4029e52014-04-07 11:19:51 -0700101#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG
Damien George88d7bba2014-04-08 23:30:46 +0100102typedef mp_longint_impl_t fmt_int_t;
Dave Hylandsc4029e52014-04-07 11:19:51 -0700103#else
Damien George88d7bba2014-04-08 23:30:46 +0100104typedef mp_small_int_t fmt_int_t;
Dave Hylandsc4029e52014-04-07 11:19:51 -0700105#endif
106
Damien George88d7bba2014-04-08 23:30:46 +0100107STATIC const uint log_base2_floor[] = {
Dave Hylandsc4029e52014-04-07 11:19:51 -0700108 0,
109 0, 1, 1, 2,
110 2, 2, 2, 3,
111 3, 3, 3, 3,
112 3, 3, 3, 4,
113 4, 4, 4, 4,
114 4, 4, 4, 4,
115 4, 4, 4, 4,
116 4, 4, 4, 5
117};
118
Damien George88d7bba2014-04-08 23:30:46 +0100119STATIC uint int_as_str_size_formatted(uint base, const char *prefix, char comma) {
Dave Hylandsc4029e52014-04-07 11:19:51 -0700120 if (base < 2 || base > 32) {
121 return 0;
122 }
123
124 uint num_digits = sizeof(fmt_int_t) * 8 / log_base2_floor[base] + 1;
125 uint num_commas = comma ? num_digits / 3: 0;
126 uint prefix_len = prefix ? strlen(prefix) : 0;
127 return num_digits + num_commas + prefix_len + 2; // +1 for sign, +1 for null byte
128}
129
130// This routine expects you to pass in a buffer and size (in *buf and buf_size).
131// If, for some reason, this buffer is too small, then it will allocate a
132// buffer and return the allocated buffer and size in *buf and *buf_size. It
133// is the callers responsibility to free this allocated buffer.
134//
135// The resulting formatted string will be returned from this function and the
136// formatted size will be in *fmt_size.
Paul Sokolovskyab7bf282014-05-17 11:08:33 +0300137char *mp_obj_int_formatted(char **buf, int *buf_size, int *fmt_size, mp_const_obj_t self_in,
Dave Hylandsc4029e52014-04-07 11:19:51 -0700138 int base, const char *prefix, char base_char, char comma) {
Damien George88d7bba2014-04-08 23:30:46 +0100139 fmt_int_t num;
140 if (MP_OBJ_IS_SMALL_INT(self_in)) {
141 // A small int; get the integer value to format.
142 num = mp_obj_get_int(self_in);
143#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
144 } else if (MP_OBJ_IS_TYPE(self_in, &mp_type_int)) {
145 // Not a small int.
146#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG
Damien George503d6112014-05-28 14:07:21 +0100147 const mp_obj_int_t *self = self_in;
Damien George88d7bba2014-04-08 23:30:46 +0100148 // Get the value to format; mp_obj_get_int truncates to machine_int_t.
149 num = self->val;
150#else
151 // Delegate to the implementation for the long int.
152 return mp_obj_int_formatted_impl(buf, buf_size, fmt_size, self_in, base, prefix, base_char, comma);
153#endif
154#endif
155 } else {
156 // Not an int.
Dave Hylandsc4029e52014-04-07 11:19:51 -0700157 buf[0] = '\0';
158 *fmt_size = 0;
159 return *buf;
160 }
Damien George88d7bba2014-04-08 23:30:46 +0100161
Dave Hylandsc4029e52014-04-07 11:19:51 -0700162 char sign = '\0';
163 if (num < 0) {
164 num = -num;
165 sign = '-';
166 }
167
168 uint needed_size = int_as_str_size_formatted(base, prefix, comma);
169 if (needed_size > *buf_size) {
170 *buf = m_new(char, needed_size);
171 *buf_size = needed_size;
172 }
173 char *str = *buf;
174
175 char *b = str + needed_size;
176 *(--b) = '\0';
177 char *last_comma = b;
178
179 if (num == 0) {
180 *(--b) = '0';
181 } else {
182 do {
183 int c = num % base;
184 num /= base;
185 if (c >= 10) {
186 c += base_char - 10;
187 } else {
188 c += '0';
189 }
190 *(--b) = c;
191 if (comma && num != 0 && b > str && (last_comma - b) == 3) {
192 *(--b) = comma;
193 last_comma = b;
194 }
195 }
196 while (b > str && num != 0);
197 }
198 if (prefix) {
199 size_t prefix_len = strlen(prefix);
200 char *p = b - prefix_len;
201 if (p > str) {
202 b = p;
203 while (*prefix) {
204 *p++ = *prefix++;
205 }
206 }
207 }
208 if (sign && b > str) {
209 *(--b) = sign;
210 }
211 *fmt_size = *buf + needed_size - b - 1;
212
213 return b;
214}
215
Damien George88d7bba2014-04-08 23:30:46 +0100216#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE
217
Dave Hylandsc4029e52014-04-07 11:19:51 -0700218bool mp_obj_int_is_positive(mp_obj_t self_in) {
219 return mp_obj_get_int(self_in) >= 0;
220}
Dave Hylandsc4029e52014-04-07 11:19:51 -0700221
Damien George660aef62014-04-02 12:22:07 +0100222// This is called for operations on SMALL_INT that are not handled by mp_unary_op
Damien Georgee8208a72014-04-04 15:08:23 +0100223mp_obj_t mp_obj_int_unary_op(int op, mp_obj_t o_in) {
Damien George6ac5dce2014-05-21 19:42:43 +0100224 return MP_OBJ_NULL; // op not supported
Paul Sokolovsky9b00dad2014-01-27 09:05:50 +0200225}
226
Damien George660aef62014-04-02 12:22:07 +0100227// This is called for operations on SMALL_INT that are not handled by mp_binary_op
Damien Georgee8208a72014-04-04 15:08:23 +0100228mp_obj_t mp_obj_int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
229 return mp_obj_int_binary_op_extra_cases(op, lhs_in, rhs_in);
Paul Sokolovsky48b35722014-01-12 17:30:48 +0200230}
231
232// This is called only with strings whose value doesn't fit in SMALL_INT
Damien George503d6112014-05-28 14:07:21 +0100233mp_obj_t mp_obj_new_int_from_str_len(const char **str, uint len, bool neg, uint base) {
Damien Georgeea13f402014-04-05 18:32:08 +0100234 nlr_raise(mp_obj_new_exception_msg(&mp_type_OverflowError, "long int not supported in this build"));
Damien George23005372014-01-13 19:39:01 +0000235 return mp_const_none;
Paul Sokolovsky48b35722014-01-12 17:30:48 +0200236}
237
Damien George9d68e9c2014-03-12 15:38:15 +0000238// This is called when an integer larger than a SMALL_INT is needed (although val might still fit in a SMALL_INT)
239mp_obj_t mp_obj_new_int_from_ll(long long val) {
Damien Georgeea13f402014-04-05 18:32:08 +0100240 nlr_raise(mp_obj_new_exception_msg(&mp_type_OverflowError, "small int overflow"));
Damien George9d68e9c2014-03-12 15:38:15 +0000241 return mp_const_none;
242}
243
Paul Sokolovsky48b35722014-01-12 17:30:48 +0200244mp_obj_t mp_obj_new_int_from_uint(machine_uint_t value) {
245 // SMALL_INT accepts only signed numbers, of one bit less size
246 // then word size, which totals 2 bits less for unsigned numbers.
247 if ((value & (WORD_MSBIT_HIGH | (WORD_MSBIT_HIGH >> 1))) == 0) {
248 return MP_OBJ_NEW_SMALL_INT(value);
249 }
Damien Georgeea13f402014-04-05 18:32:08 +0100250 nlr_raise(mp_obj_new_exception_msg(&mp_type_OverflowError, "small int overflow"));
Damien George23005372014-01-13 19:39:01 +0000251 return mp_const_none;
Paul Sokolovsky48b35722014-01-12 17:30:48 +0200252}
253
254mp_obj_t mp_obj_new_int(machine_int_t value) {
Damien Georged1e355e2014-05-28 14:51:12 +0100255 if (MP_SMALL_INT_FITS(value)) {
Paul Sokolovsky48b35722014-01-12 17:30:48 +0200256 return MP_OBJ_NEW_SMALL_INT(value);
257 }
Damien Georgeea13f402014-04-05 18:32:08 +0100258 nlr_raise(mp_obj_new_exception_msg(&mp_type_OverflowError, "small int overflow"));
Damien George23005372014-01-13 19:39:01 +0000259 return mp_const_none;
Paul Sokolovsky48b35722014-01-12 17:30:48 +0200260}
Paul Sokolovskyd26b3792014-01-18 16:07:16 +0200261
Damien George503d6112014-05-28 14:07:21 +0100262machine_int_t mp_obj_int_get(mp_const_obj_t self_in) {
Paul Sokolovskyd26b3792014-01-18 16:07:16 +0200263 return MP_OBJ_SMALL_INT_VALUE(self_in);
264}
265
Sven Wegener7ba0fed2014-05-17 11:17:48 +0200266machine_int_t mp_obj_int_get_checked(mp_const_obj_t self_in) {
Paul Sokolovskyd26b3792014-01-18 16:07:16 +0200267 return MP_OBJ_SMALL_INT_VALUE(self_in);
268}
269
Damien Georgefb510b32014-06-01 13:32:54 +0100270#if MICROPY_PY_BUILTINS_FLOAT
Damien Georgeeabdf672014-03-22 20:54:01 +0000271mp_float_t mp_obj_int_as_float(mp_obj_t self_in) {
272 return MP_OBJ_SMALL_INT_VALUE(self_in);
273}
274#endif
275
Damien George5fa93b62014-01-22 14:35:10 +0000276#endif // MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE
277
Damien Georgee8208a72014-04-04 15:08:23 +0100278// This dispatcher function is expected to be independent of the implementation of long int
279// It handles the extra cases for integer-like arithmetic
280mp_obj_t mp_obj_int_binary_op_extra_cases(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
281 if (rhs_in == mp_const_false) {
282 // false acts as 0
283 return mp_binary_op(op, lhs_in, MP_OBJ_NEW_SMALL_INT(0));
284 } else if (rhs_in == mp_const_true) {
285 // true acts as 0
286 return mp_binary_op(op, lhs_in, MP_OBJ_NEW_SMALL_INT(1));
287 } else if (op == MP_BINARY_OP_MULTIPLY) {
288 if (MP_OBJ_IS_STR(rhs_in) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_tuple) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_list)) {
289 // multiply is commutative for these types, so delegate to them
290 return mp_binary_op(op, rhs_in, lhs_in);
291 }
292 }
Damien George6ac5dce2014-05-21 19:42:43 +0100293 return MP_OBJ_NULL; // op not supported
Damien Georgee8208a72014-04-04 15:08:23 +0100294}
295
Damien George5213eb32014-04-13 12:24:13 +0100296// this is a classmethod
Paul Sokolovskya985b452014-04-09 00:40:58 +0300297STATIC mp_obj_t int_from_bytes(uint n_args, const mp_obj_t *args) {
Paul Sokolovskya985b452014-04-09 00:40:58 +0300298 // TODO: Support long ints
Damien George5213eb32014-04-13 12:24:13 +0100299 // TODO: Support byteorder param (assumes 'little' at the moment)
300 // TODO: Support signed param (assumes signed=False at the moment)
301
302 // get the buffer info
Damien George57a4b4f2014-04-18 22:29:21 +0100303 mp_buffer_info_t bufinfo;
Damien Georgeb11b85a2014-04-18 22:59:24 +0100304 mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ);
Damien George5213eb32014-04-13 12:24:13 +0100305
306 // convert the bytes to an integer
307 machine_uint_t value = 0;
stijn01d6be42014-05-05 12:18:27 +0200308 for (const byte* buf = (const byte*)bufinfo.buf + bufinfo.len - 1; buf >= (byte*)bufinfo.buf; buf--) {
Damien Georgeb9e7ed42014-04-13 12:40:50 +0100309 value = (value << 8) | *buf;
Damien George5213eb32014-04-13 12:24:13 +0100310 }
311
312 return mp_obj_new_int_from_uint(value);
Paul Sokolovskya985b452014-04-09 00:40:58 +0300313}
314
Damien George5213eb32014-04-13 12:24:13 +0100315STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(int_from_bytes_fun_obj, 2, 3, int_from_bytes);
316STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(int_from_bytes_obj, (const mp_obj_t)&int_from_bytes_fun_obj);
Paul Sokolovskya985b452014-04-09 00:40:58 +0300317
318STATIC mp_obj_t int_to_bytes(uint n_args, const mp_obj_t *args) {
319 machine_int_t val = mp_obj_int_get_checked(args[0]);
320
321 uint len = MP_OBJ_SMALL_INT_VALUE(args[1]);
322 byte *data;
323
324 // TODO: Support long ints
325 // TODO: Support byteorder param
326 // TODO: Support signed param
327 mp_obj_t o = mp_obj_str_builder_start(&mp_type_bytes, len, &data);
328 memset(data, 0, len);
329 memcpy(data, &val, len < sizeof(machine_int_t) ? len : sizeof(machine_int_t));
330 return mp_obj_str_builder_end(o);
331}
332
333STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(int_to_bytes_obj, 2, 4, int_to_bytes);
334
335STATIC const mp_map_elem_t int_locals_dict_table[] = {
336 { MP_OBJ_NEW_QSTR(MP_QSTR_from_bytes), (mp_obj_t)&int_from_bytes_obj },
337 { MP_OBJ_NEW_QSTR(MP_QSTR_to_bytes), (mp_obj_t)&int_to_bytes_obj },
338};
339
340STATIC MP_DEFINE_CONST_DICT(int_locals_dict, int_locals_dict_table);
341
Damien George3e1a5c12014-03-29 13:43:38 +0000342const mp_obj_type_t mp_type_int = {
Damien Georgec5966122014-02-15 16:10:44 +0000343 { &mp_type_type },
Damien Georgea71c83a2014-02-15 11:34:50 +0000344 .name = MP_QSTR_int,
Damien Georgee8208a72014-04-04 15:08:23 +0100345 .print = mp_obj_int_print,
346 .make_new = mp_obj_int_make_new,
347 .unary_op = mp_obj_int_unary_op,
348 .binary_op = mp_obj_int_binary_op,
Paul Sokolovskya985b452014-04-09 00:40:58 +0300349 .locals_dict = (mp_obj_t)&int_locals_dict,
Damien George5fa93b62014-01-22 14:35:10 +0000350};