blob: c8bcb6080cb276033bf2a4044734265901e7a89b [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 George438c88d2014-02-22 19:25:23 +000038#include "mpz.h"
Paul Sokolovsky76a90f22014-01-13 22:31:01 +020039#include "objint.h"
Damien George660aef62014-04-02 12:22:07 +010040#include "runtime0.h"
41#include "runtime.h"
Paul Sokolovsky48b35722014-01-12 17:30:48 +020042
Damien George6433bd92014-03-30 23:13:16 +010043#if MICROPY_ENABLE_FLOAT
44#include <math.h>
45#endif
46
Damien Georgee8208a72014-04-04 15:08:23 +010047// This dispatcher function is expected to be independent of the implementation of long int
48STATIC 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 George20006db2014-01-18 14:10:48 +000049 // TODO check n_kw == 0
50
Damien George45b43c22014-01-05 01:50:45 +000051 switch (n_args) {
52 case 0:
53 return MP_OBJ_NEW_SMALL_INT(0);
54
55 case 1:
Damien George5fa93b62014-01-22 14:35:10 +000056 if (MP_OBJ_IS_STR(args[0])) {
Damien George5573f9f2014-01-15 22:58:39 +000057 // a string, parse it
Damien George5fa93b62014-01-22 14:35:10 +000058 uint l;
Damien George698ec212014-02-08 18:17:23 +000059 const char *s = mp_obj_str_get_data(args[0], &l);
Damien George20773972014-02-22 18:12:43 +000060 return mp_parse_num_integer(s, l, 0);
Damien George6433bd92014-03-30 23:13:16 +010061#if MICROPY_ENABLE_FLOAT
62 } else if (MP_OBJ_IS_TYPE(args[0], &mp_type_float)) {
63 return MP_OBJ_NEW_SMALL_INT((machine_int_t)(MICROPY_FLOAT_C_FUN(trunc)(mp_obj_float_get(args[0]))));
64#endif
Damien George5573f9f2014-01-15 22:58:39 +000065 } else {
66 return MP_OBJ_NEW_SMALL_INT(mp_obj_get_int(args[0]));
67 }
Damien George45b43c22014-01-05 01:50:45 +000068
xybc178ea42014-01-14 21:39:05 +080069 case 2:
Damien George5fa93b62014-01-22 14:35:10 +000070 {
Damien George5573f9f2014-01-15 22:58:39 +000071 // should be a string, parse it
72 // TODO proper error checking of argument types
Damien George5fa93b62014-01-22 14:35:10 +000073 uint l;
Damien George698ec212014-02-08 18:17:23 +000074 const char *s = mp_obj_str_get_data(args[0], &l);
Damien George20773972014-02-22 18:12:43 +000075 return mp_parse_num_integer(s, l, mp_obj_get_int(args[1]));
Damien George5fa93b62014-01-22 14:35:10 +000076 }
Damien George45b43c22014-01-05 01:50:45 +000077
78 default:
Damien Georgeea13f402014-04-05 18:32:08 +010079 nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "int takes at most 2 arguments, %d given", n_args));
Damien George45b43c22014-01-05 01:50:45 +000080 }
81}
82
Damien Georgee8208a72014-04-04 15:08:23 +010083void 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 -070084 // The size of this buffer is rather arbitrary. If it's not large
85 // enough, a dynamic one will be allocated.
86 char stack_buf[sizeof(machine_int_t) * 4];
87 char *buf = stack_buf;
88 int buf_size = sizeof(stack_buf);
89 int fmt_size;
90
91 char *str = mp_obj_int_formatted(&buf, &buf_size, &fmt_size, self_in, 10, NULL, '\0', '\0');
92 print(env, "%s", str);
93
94 if (buf != stack_buf) {
95 m_free(buf, buf_size);
Damien George5fa93b62014-01-22 14:35:10 +000096 }
Damien George45b43c22014-01-05 01:50:45 +000097}
Paul Sokolovsky48b35722014-01-12 17:30:48 +020098
Dave Hylandsc4029e52014-04-07 11:19:51 -070099#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG
Damien George88d7bba2014-04-08 23:30:46 +0100100typedef mp_longint_impl_t fmt_int_t;
Dave Hylandsc4029e52014-04-07 11:19:51 -0700101#else
Damien George88d7bba2014-04-08 23:30:46 +0100102typedef mp_small_int_t fmt_int_t;
Dave Hylandsc4029e52014-04-07 11:19:51 -0700103#endif
104
Damien George88d7bba2014-04-08 23:30:46 +0100105STATIC const uint log_base2_floor[] = {
Dave Hylandsc4029e52014-04-07 11:19:51 -0700106 0,
107 0, 1, 1, 2,
108 2, 2, 2, 3,
109 3, 3, 3, 3,
110 3, 3, 3, 4,
111 4, 4, 4, 4,
112 4, 4, 4, 4,
113 4, 4, 4, 4,
114 4, 4, 4, 5
115};
116
Damien George88d7bba2014-04-08 23:30:46 +0100117STATIC uint int_as_str_size_formatted(uint base, const char *prefix, char comma) {
Dave Hylandsc4029e52014-04-07 11:19:51 -0700118 if (base < 2 || base > 32) {
119 return 0;
120 }
121
122 uint num_digits = sizeof(fmt_int_t) * 8 / log_base2_floor[base] + 1;
123 uint num_commas = comma ? num_digits / 3: 0;
124 uint prefix_len = prefix ? strlen(prefix) : 0;
125 return num_digits + num_commas + prefix_len + 2; // +1 for sign, +1 for null byte
126}
127
128// This routine expects you to pass in a buffer and size (in *buf and buf_size).
129// If, for some reason, this buffer is too small, then it will allocate a
130// buffer and return the allocated buffer and size in *buf and *buf_size. It
131// is the callers responsibility to free this allocated buffer.
132//
133// The resulting formatted string will be returned from this function and the
134// formatted size will be in *fmt_size.
135char *mp_obj_int_formatted(char **buf, int *buf_size, int *fmt_size, mp_obj_t self_in,
136 int base, const char *prefix, char base_char, char comma) {
Damien George88d7bba2014-04-08 23:30:46 +0100137 fmt_int_t num;
138 if (MP_OBJ_IS_SMALL_INT(self_in)) {
139 // A small int; get the integer value to format.
140 num = mp_obj_get_int(self_in);
141#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
142 } else if (MP_OBJ_IS_TYPE(self_in, &mp_type_int)) {
143 // Not a small int.
144#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG
145 mp_obj_int_t *self = self_in;
146 // Get the value to format; mp_obj_get_int truncates to machine_int_t.
147 num = self->val;
148#else
149 // Delegate to the implementation for the long int.
150 return mp_obj_int_formatted_impl(buf, buf_size, fmt_size, self_in, base, prefix, base_char, comma);
151#endif
152#endif
153 } else {
154 // Not an int.
Dave Hylandsc4029e52014-04-07 11:19:51 -0700155 buf[0] = '\0';
156 *fmt_size = 0;
157 return *buf;
158 }
Damien George88d7bba2014-04-08 23:30:46 +0100159
Dave Hylandsc4029e52014-04-07 11:19:51 -0700160 char sign = '\0';
161 if (num < 0) {
162 num = -num;
163 sign = '-';
164 }
165
166 uint needed_size = int_as_str_size_formatted(base, prefix, comma);
167 if (needed_size > *buf_size) {
168 *buf = m_new(char, needed_size);
169 *buf_size = needed_size;
170 }
171 char *str = *buf;
172
173 char *b = str + needed_size;
174 *(--b) = '\0';
175 char *last_comma = b;
176
177 if (num == 0) {
178 *(--b) = '0';
179 } else {
180 do {
181 int c = num % base;
182 num /= base;
183 if (c >= 10) {
184 c += base_char - 10;
185 } else {
186 c += '0';
187 }
188 *(--b) = c;
189 if (comma && num != 0 && b > str && (last_comma - b) == 3) {
190 *(--b) = comma;
191 last_comma = b;
192 }
193 }
194 while (b > str && num != 0);
195 }
196 if (prefix) {
197 size_t prefix_len = strlen(prefix);
198 char *p = b - prefix_len;
199 if (p > str) {
200 b = p;
201 while (*prefix) {
202 *p++ = *prefix++;
203 }
204 }
205 }
206 if (sign && b > str) {
207 *(--b) = sign;
208 }
209 *fmt_size = *buf + needed_size - b - 1;
210
211 return b;
212}
213
Damien George88d7bba2014-04-08 23:30:46 +0100214#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE
215
Dave Hylandsc4029e52014-04-07 11:19:51 -0700216bool mp_obj_int_is_positive(mp_obj_t self_in) {
217 return mp_obj_get_int(self_in) >= 0;
218}
Dave Hylandsc4029e52014-04-07 11:19:51 -0700219
Damien George660aef62014-04-02 12:22:07 +0100220// This is called for operations on SMALL_INT that are not handled by mp_unary_op
Damien Georgee8208a72014-04-04 15:08:23 +0100221mp_obj_t mp_obj_int_unary_op(int op, mp_obj_t o_in) {
Damien Georgeea8d06c2014-04-17 23:19:36 +0100222 return MP_OBJ_NOT_SUPPORTED;
Paul Sokolovsky9b00dad2014-01-27 09:05:50 +0200223}
224
Damien George660aef62014-04-02 12:22:07 +0100225// This is called for operations on SMALL_INT that are not handled by mp_binary_op
Damien Georgee8208a72014-04-04 15:08:23 +0100226mp_obj_t mp_obj_int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
227 return mp_obj_int_binary_op_extra_cases(op, lhs_in, rhs_in);
Paul Sokolovsky48b35722014-01-12 17:30:48 +0200228}
229
230// This is called only with strings whose value doesn't fit in SMALL_INT
Damien Georgea32c1e42014-05-07 18:30:52 +0100231mp_obj_t mp_obj_new_int_from_qstr(qstr qst) {
Damien Georgeea13f402014-04-05 18:32:08 +0100232 nlr_raise(mp_obj_new_exception_msg(&mp_type_OverflowError, "long int not supported in this build"));
Damien George23005372014-01-13 19:39:01 +0000233 return mp_const_none;
Paul Sokolovsky48b35722014-01-12 17:30:48 +0200234}
235
Damien George9d68e9c2014-03-12 15:38:15 +0000236// This is called when an integer larger than a SMALL_INT is needed (although val might still fit in a SMALL_INT)
237mp_obj_t mp_obj_new_int_from_ll(long long val) {
Damien Georgeea13f402014-04-05 18:32:08 +0100238 nlr_raise(mp_obj_new_exception_msg(&mp_type_OverflowError, "small int overflow"));
Damien George9d68e9c2014-03-12 15:38:15 +0000239 return mp_const_none;
240}
241
Paul Sokolovsky48b35722014-01-12 17:30:48 +0200242mp_obj_t mp_obj_new_int_from_uint(machine_uint_t value) {
243 // SMALL_INT accepts only signed numbers, of one bit less size
244 // then word size, which totals 2 bits less for unsigned numbers.
245 if ((value & (WORD_MSBIT_HIGH | (WORD_MSBIT_HIGH >> 1))) == 0) {
246 return MP_OBJ_NEW_SMALL_INT(value);
247 }
Damien Georgeea13f402014-04-05 18:32:08 +0100248 nlr_raise(mp_obj_new_exception_msg(&mp_type_OverflowError, "small int overflow"));
Damien George23005372014-01-13 19:39:01 +0000249 return mp_const_none;
Paul Sokolovsky48b35722014-01-12 17:30:48 +0200250}
251
252mp_obj_t mp_obj_new_int(machine_int_t value) {
253 if (MP_OBJ_FITS_SMALL_INT(value)) {
254 return MP_OBJ_NEW_SMALL_INT(value);
255 }
Damien Georgeea13f402014-04-05 18:32:08 +0100256 nlr_raise(mp_obj_new_exception_msg(&mp_type_OverflowError, "small int overflow"));
Damien George23005372014-01-13 19:39:01 +0000257 return mp_const_none;
Paul Sokolovsky48b35722014-01-12 17:30:48 +0200258}
Paul Sokolovskyd26b3792014-01-18 16:07:16 +0200259
260machine_int_t mp_obj_int_get(mp_obj_t self_in) {
261 return MP_OBJ_SMALL_INT_VALUE(self_in);
262}
263
264machine_int_t mp_obj_int_get_checked(mp_obj_t self_in) {
265 return MP_OBJ_SMALL_INT_VALUE(self_in);
266}
267
Damien Georgeeabdf672014-03-22 20:54:01 +0000268#if MICROPY_ENABLE_FLOAT
269mp_float_t mp_obj_int_as_float(mp_obj_t self_in) {
270 return MP_OBJ_SMALL_INT_VALUE(self_in);
271}
272#endif
273
Damien George5fa93b62014-01-22 14:35:10 +0000274#endif // MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE
275
Damien Georgee8208a72014-04-04 15:08:23 +0100276// This dispatcher function is expected to be independent of the implementation of long int
277// It handles the extra cases for integer-like arithmetic
278mp_obj_t mp_obj_int_binary_op_extra_cases(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
279 if (rhs_in == mp_const_false) {
280 // false acts as 0
281 return mp_binary_op(op, lhs_in, MP_OBJ_NEW_SMALL_INT(0));
282 } else if (rhs_in == mp_const_true) {
283 // true acts as 0
284 return mp_binary_op(op, lhs_in, MP_OBJ_NEW_SMALL_INT(1));
285 } else if (op == MP_BINARY_OP_MULTIPLY) {
286 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)) {
287 // multiply is commutative for these types, so delegate to them
288 return mp_binary_op(op, rhs_in, lhs_in);
289 }
290 }
Damien Georgeea8d06c2014-04-17 23:19:36 +0100291 return MP_OBJ_NOT_SUPPORTED;
Damien Georgee8208a72014-04-04 15:08:23 +0100292}
293
Damien George5213eb32014-04-13 12:24:13 +0100294// this is a classmethod
Paul Sokolovskya985b452014-04-09 00:40:58 +0300295STATIC mp_obj_t int_from_bytes(uint n_args, const mp_obj_t *args) {
Paul Sokolovskya985b452014-04-09 00:40:58 +0300296 // TODO: Support long ints
Damien George5213eb32014-04-13 12:24:13 +0100297 // TODO: Support byteorder param (assumes 'little' at the moment)
298 // TODO: Support signed param (assumes signed=False at the moment)
299
300 // get the buffer info
Damien George57a4b4f2014-04-18 22:29:21 +0100301 mp_buffer_info_t bufinfo;
Damien Georgeb11b85a2014-04-18 22:59:24 +0100302 mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ);
Damien George5213eb32014-04-13 12:24:13 +0100303
304 // convert the bytes to an integer
305 machine_uint_t value = 0;
Damien Georgeb9e7ed42014-04-13 12:40:50 +0100306 for (const byte* buf = bufinfo.buf + bufinfo.len - 1; buf >= (byte*)bufinfo.buf; buf--) {
307 value = (value << 8) | *buf;
Damien George5213eb32014-04-13 12:24:13 +0100308 }
309
310 return mp_obj_new_int_from_uint(value);
Paul Sokolovskya985b452014-04-09 00:40:58 +0300311}
312
Damien George5213eb32014-04-13 12:24:13 +0100313STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(int_from_bytes_fun_obj, 2, 3, int_from_bytes);
314STATIC 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 +0300315
316STATIC mp_obj_t int_to_bytes(uint n_args, const mp_obj_t *args) {
317 machine_int_t val = mp_obj_int_get_checked(args[0]);
318
319 uint len = MP_OBJ_SMALL_INT_VALUE(args[1]);
320 byte *data;
321
322 // TODO: Support long ints
323 // TODO: Support byteorder param
324 // TODO: Support signed param
325 mp_obj_t o = mp_obj_str_builder_start(&mp_type_bytes, len, &data);
326 memset(data, 0, len);
327 memcpy(data, &val, len < sizeof(machine_int_t) ? len : sizeof(machine_int_t));
328 return mp_obj_str_builder_end(o);
329}
330
331STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(int_to_bytes_obj, 2, 4, int_to_bytes);
332
333STATIC const mp_map_elem_t int_locals_dict_table[] = {
334 { MP_OBJ_NEW_QSTR(MP_QSTR_from_bytes), (mp_obj_t)&int_from_bytes_obj },
335 { MP_OBJ_NEW_QSTR(MP_QSTR_to_bytes), (mp_obj_t)&int_to_bytes_obj },
336};
337
338STATIC MP_DEFINE_CONST_DICT(int_locals_dict, int_locals_dict_table);
339
Damien George3e1a5c12014-03-29 13:43:38 +0000340const mp_obj_type_t mp_type_int = {
Damien Georgec5966122014-02-15 16:10:44 +0000341 { &mp_type_type },
Damien Georgea71c83a2014-02-15 11:34:50 +0000342 .name = MP_QSTR_int,
Damien Georgee8208a72014-04-04 15:08:23 +0100343 .print = mp_obj_int_print,
344 .make_new = mp_obj_int_make_new,
345 .unary_op = mp_obj_int_unary_op,
346 .binary_op = mp_obj_int_binary_op,
Paul Sokolovskya985b452014-04-09 00:40:58 +0300347 .locals_dict = (mp_obj_t)&int_locals_dict,
Damien George5fa93b62014-01-22 14:35:10 +0000348};