blob: 8bec4a3e3f2ce70418689dea6b932ee48c37b8d0 [file] [log] [blame]
Damien George660aef62014-04-02 12:22:07 +01001#include <stdlib.h>
Damien George45b43c22014-01-05 01:50:45 +00002#include <stdint.h>
Damien George45b43c22014-01-05 01:50:45 +00003#include <assert.h>
Dave Hylandsc4029e52014-04-07 11:19:51 -07004#include <string.h>
Damien George45b43c22014-01-05 01:50:45 +00005
6#include "nlr.h"
7#include "misc.h"
8#include "mpconfig.h"
Damien George55baff42014-01-21 21:40:13 +00009#include "qstr.h"
Damien George45b43c22014-01-05 01:50:45 +000010#include "obj.h"
Damien George20773972014-02-22 18:12:43 +000011#include "parsenum.h"
Damien George438c88d2014-02-22 19:25:23 +000012#include "mpz.h"
Paul Sokolovsky76a90f22014-01-13 22:31:01 +020013#include "objint.h"
Damien George660aef62014-04-02 12:22:07 +010014#include "runtime0.h"
15#include "runtime.h"
Paul Sokolovsky48b35722014-01-12 17:30:48 +020016
Damien George6433bd92014-03-30 23:13:16 +010017#if MICROPY_ENABLE_FLOAT
18#include <math.h>
19#endif
20
Damien Georgee8208a72014-04-04 15:08:23 +010021// This dispatcher function is expected to be independent of the implementation of long int
22STATIC 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 +000023 // TODO check n_kw == 0
24
Damien George45b43c22014-01-05 01:50:45 +000025 switch (n_args) {
26 case 0:
27 return MP_OBJ_NEW_SMALL_INT(0);
28
29 case 1:
Damien George5fa93b62014-01-22 14:35:10 +000030 if (MP_OBJ_IS_STR(args[0])) {
Damien George5573f9f2014-01-15 22:58:39 +000031 // a string, parse it
Damien George5fa93b62014-01-22 14:35:10 +000032 uint l;
Damien George698ec212014-02-08 18:17:23 +000033 const char *s = mp_obj_str_get_data(args[0], &l);
Damien George20773972014-02-22 18:12:43 +000034 return mp_parse_num_integer(s, l, 0);
Damien George6433bd92014-03-30 23:13:16 +010035#if MICROPY_ENABLE_FLOAT
36 } else if (MP_OBJ_IS_TYPE(args[0], &mp_type_float)) {
37 return MP_OBJ_NEW_SMALL_INT((machine_int_t)(MICROPY_FLOAT_C_FUN(trunc)(mp_obj_float_get(args[0]))));
38#endif
Damien George5573f9f2014-01-15 22:58:39 +000039 } else {
40 return MP_OBJ_NEW_SMALL_INT(mp_obj_get_int(args[0]));
41 }
Damien George45b43c22014-01-05 01:50:45 +000042
xybc178ea42014-01-14 21:39:05 +080043 case 2:
Damien George5fa93b62014-01-22 14:35:10 +000044 {
Damien George5573f9f2014-01-15 22:58:39 +000045 // should be a string, parse it
46 // TODO proper error checking of argument types
Damien George5fa93b62014-01-22 14:35:10 +000047 uint l;
Damien George698ec212014-02-08 18:17:23 +000048 const char *s = mp_obj_str_get_data(args[0], &l);
Damien George20773972014-02-22 18:12:43 +000049 return mp_parse_num_integer(s, l, mp_obj_get_int(args[1]));
Damien George5fa93b62014-01-22 14:35:10 +000050 }
Damien George45b43c22014-01-05 01:50:45 +000051
52 default:
Damien Georgeea13f402014-04-05 18:32:08 +010053 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 +000054 }
55}
56
Damien Georgee8208a72014-04-04 15:08:23 +010057void 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 -070058 // The size of this buffer is rather arbitrary. If it's not large
59 // enough, a dynamic one will be allocated.
60 char stack_buf[sizeof(machine_int_t) * 4];
61 char *buf = stack_buf;
62 int buf_size = sizeof(stack_buf);
63 int fmt_size;
64
65 char *str = mp_obj_int_formatted(&buf, &buf_size, &fmt_size, self_in, 10, NULL, '\0', '\0');
66 print(env, "%s", str);
67
68 if (buf != stack_buf) {
69 m_free(buf, buf_size);
Damien George5fa93b62014-01-22 14:35:10 +000070 }
Damien George45b43c22014-01-05 01:50:45 +000071}
Paul Sokolovsky48b35722014-01-12 17:30:48 +020072
Dave Hylandsc4029e52014-04-07 11:19:51 -070073#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG
Damien George88d7bba2014-04-08 23:30:46 +010074typedef mp_longint_impl_t fmt_int_t;
Dave Hylandsc4029e52014-04-07 11:19:51 -070075#else
Damien George88d7bba2014-04-08 23:30:46 +010076typedef mp_small_int_t fmt_int_t;
Dave Hylandsc4029e52014-04-07 11:19:51 -070077#endif
78
Damien George88d7bba2014-04-08 23:30:46 +010079STATIC const uint log_base2_floor[] = {
Dave Hylandsc4029e52014-04-07 11:19:51 -070080 0,
81 0, 1, 1, 2,
82 2, 2, 2, 3,
83 3, 3, 3, 3,
84 3, 3, 3, 4,
85 4, 4, 4, 4,
86 4, 4, 4, 4,
87 4, 4, 4, 4,
88 4, 4, 4, 5
89};
90
Damien George88d7bba2014-04-08 23:30:46 +010091STATIC uint int_as_str_size_formatted(uint base, const char *prefix, char comma) {
Dave Hylandsc4029e52014-04-07 11:19:51 -070092 if (base < 2 || base > 32) {
93 return 0;
94 }
95
96 uint num_digits = sizeof(fmt_int_t) * 8 / log_base2_floor[base] + 1;
97 uint num_commas = comma ? num_digits / 3: 0;
98 uint prefix_len = prefix ? strlen(prefix) : 0;
99 return num_digits + num_commas + prefix_len + 2; // +1 for sign, +1 for null byte
100}
101
102// This routine expects you to pass in a buffer and size (in *buf and buf_size).
103// If, for some reason, this buffer is too small, then it will allocate a
104// buffer and return the allocated buffer and size in *buf and *buf_size. It
105// is the callers responsibility to free this allocated buffer.
106//
107// The resulting formatted string will be returned from this function and the
108// formatted size will be in *fmt_size.
109char *mp_obj_int_formatted(char **buf, int *buf_size, int *fmt_size, mp_obj_t self_in,
110 int base, const char *prefix, char base_char, char comma) {
Damien George88d7bba2014-04-08 23:30:46 +0100111 fmt_int_t num;
112 if (MP_OBJ_IS_SMALL_INT(self_in)) {
113 // A small int; get the integer value to format.
114 num = mp_obj_get_int(self_in);
115#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
116 } else if (MP_OBJ_IS_TYPE(self_in, &mp_type_int)) {
117 // Not a small int.
118#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG
119 mp_obj_int_t *self = self_in;
120 // Get the value to format; mp_obj_get_int truncates to machine_int_t.
121 num = self->val;
122#else
123 // Delegate to the implementation for the long int.
124 return mp_obj_int_formatted_impl(buf, buf_size, fmt_size, self_in, base, prefix, base_char, comma);
125#endif
126#endif
127 } else {
128 // Not an int.
Dave Hylandsc4029e52014-04-07 11:19:51 -0700129 buf[0] = '\0';
130 *fmt_size = 0;
131 return *buf;
132 }
Damien George88d7bba2014-04-08 23:30:46 +0100133
Dave Hylandsc4029e52014-04-07 11:19:51 -0700134 char sign = '\0';
135 if (num < 0) {
136 num = -num;
137 sign = '-';
138 }
139
140 uint needed_size = int_as_str_size_formatted(base, prefix, comma);
141 if (needed_size > *buf_size) {
142 *buf = m_new(char, needed_size);
143 *buf_size = needed_size;
144 }
145 char *str = *buf;
146
147 char *b = str + needed_size;
148 *(--b) = '\0';
149 char *last_comma = b;
150
151 if (num == 0) {
152 *(--b) = '0';
153 } else {
154 do {
155 int c = num % base;
156 num /= base;
157 if (c >= 10) {
158 c += base_char - 10;
159 } else {
160 c += '0';
161 }
162 *(--b) = c;
163 if (comma && num != 0 && b > str && (last_comma - b) == 3) {
164 *(--b) = comma;
165 last_comma = b;
166 }
167 }
168 while (b > str && num != 0);
169 }
170 if (prefix) {
171 size_t prefix_len = strlen(prefix);
172 char *p = b - prefix_len;
173 if (p > str) {
174 b = p;
175 while (*prefix) {
176 *p++ = *prefix++;
177 }
178 }
179 }
180 if (sign && b > str) {
181 *(--b) = sign;
182 }
183 *fmt_size = *buf + needed_size - b - 1;
184
185 return b;
186}
187
Damien George88d7bba2014-04-08 23:30:46 +0100188#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE
189
Dave Hylandsc4029e52014-04-07 11:19:51 -0700190bool mp_obj_int_is_positive(mp_obj_t self_in) {
191 return mp_obj_get_int(self_in) >= 0;
192}
Dave Hylandsc4029e52014-04-07 11:19:51 -0700193
Damien George660aef62014-04-02 12:22:07 +0100194// This is called for operations on SMALL_INT that are not handled by mp_unary_op
Damien Georgee8208a72014-04-04 15:08:23 +0100195mp_obj_t mp_obj_int_unary_op(int op, mp_obj_t o_in) {
Damien Georgeea8d06c2014-04-17 23:19:36 +0100196 return MP_OBJ_NOT_SUPPORTED;
Paul Sokolovsky9b00dad2014-01-27 09:05:50 +0200197}
198
Damien George660aef62014-04-02 12:22:07 +0100199// This is called for operations on SMALL_INT that are not handled by mp_binary_op
Damien Georgee8208a72014-04-04 15:08:23 +0100200mp_obj_t mp_obj_int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
201 return mp_obj_int_binary_op_extra_cases(op, lhs_in, rhs_in);
Paul Sokolovsky48b35722014-01-12 17:30:48 +0200202}
203
204// This is called only with strings whose value doesn't fit in SMALL_INT
205mp_obj_t mp_obj_new_int_from_long_str(const char *s) {
Damien Georgeea13f402014-04-05 18:32:08 +0100206 nlr_raise(mp_obj_new_exception_msg(&mp_type_OverflowError, "long int not supported in this build"));
Damien George23005372014-01-13 19:39:01 +0000207 return mp_const_none;
Paul Sokolovsky48b35722014-01-12 17:30:48 +0200208}
209
Damien George9d68e9c2014-03-12 15:38:15 +0000210// This is called when an integer larger than a SMALL_INT is needed (although val might still fit in a SMALL_INT)
211mp_obj_t mp_obj_new_int_from_ll(long long val) {
Damien Georgeea13f402014-04-05 18:32:08 +0100212 nlr_raise(mp_obj_new_exception_msg(&mp_type_OverflowError, "small int overflow"));
Damien George9d68e9c2014-03-12 15:38:15 +0000213 return mp_const_none;
214}
215
Paul Sokolovsky48b35722014-01-12 17:30:48 +0200216mp_obj_t mp_obj_new_int_from_uint(machine_uint_t value) {
217 // SMALL_INT accepts only signed numbers, of one bit less size
218 // then word size, which totals 2 bits less for unsigned numbers.
219 if ((value & (WORD_MSBIT_HIGH | (WORD_MSBIT_HIGH >> 1))) == 0) {
220 return MP_OBJ_NEW_SMALL_INT(value);
221 }
Damien Georgeea13f402014-04-05 18:32:08 +0100222 nlr_raise(mp_obj_new_exception_msg(&mp_type_OverflowError, "small int overflow"));
Damien George23005372014-01-13 19:39:01 +0000223 return mp_const_none;
Paul Sokolovsky48b35722014-01-12 17:30:48 +0200224}
225
226mp_obj_t mp_obj_new_int(machine_int_t value) {
227 if (MP_OBJ_FITS_SMALL_INT(value)) {
228 return MP_OBJ_NEW_SMALL_INT(value);
229 }
Damien Georgeea13f402014-04-05 18:32:08 +0100230 nlr_raise(mp_obj_new_exception_msg(&mp_type_OverflowError, "small int overflow"));
Damien George23005372014-01-13 19:39:01 +0000231 return mp_const_none;
Paul Sokolovsky48b35722014-01-12 17:30:48 +0200232}
Paul Sokolovskyd26b3792014-01-18 16:07:16 +0200233
234machine_int_t mp_obj_int_get(mp_obj_t self_in) {
235 return MP_OBJ_SMALL_INT_VALUE(self_in);
236}
237
238machine_int_t mp_obj_int_get_checked(mp_obj_t self_in) {
239 return MP_OBJ_SMALL_INT_VALUE(self_in);
240}
241
Damien Georgeeabdf672014-03-22 20:54:01 +0000242#if MICROPY_ENABLE_FLOAT
243mp_float_t mp_obj_int_as_float(mp_obj_t self_in) {
244 return MP_OBJ_SMALL_INT_VALUE(self_in);
245}
246#endif
247
Damien George5fa93b62014-01-22 14:35:10 +0000248#endif // MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE
249
Damien Georgee8208a72014-04-04 15:08:23 +0100250// This dispatcher function is expected to be independent of the implementation of long int
251// It handles the extra cases for integer-like arithmetic
252mp_obj_t mp_obj_int_binary_op_extra_cases(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
253 if (rhs_in == mp_const_false) {
254 // false acts as 0
255 return mp_binary_op(op, lhs_in, MP_OBJ_NEW_SMALL_INT(0));
256 } else if (rhs_in == mp_const_true) {
257 // true acts as 0
258 return mp_binary_op(op, lhs_in, MP_OBJ_NEW_SMALL_INT(1));
259 } else if (op == MP_BINARY_OP_MULTIPLY) {
260 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)) {
261 // multiply is commutative for these types, so delegate to them
262 return mp_binary_op(op, rhs_in, lhs_in);
263 }
264 }
Damien Georgeea8d06c2014-04-17 23:19:36 +0100265 return MP_OBJ_NOT_SUPPORTED;
Damien Georgee8208a72014-04-04 15:08:23 +0100266}
267
Damien George5213eb32014-04-13 12:24:13 +0100268// this is a classmethod
Paul Sokolovskya985b452014-04-09 00:40:58 +0300269STATIC mp_obj_t int_from_bytes(uint n_args, const mp_obj_t *args) {
Paul Sokolovskya985b452014-04-09 00:40:58 +0300270 // TODO: Support long ints
Damien George5213eb32014-04-13 12:24:13 +0100271 // TODO: Support byteorder param (assumes 'little' at the moment)
272 // TODO: Support signed param (assumes signed=False at the moment)
273
274 // get the buffer info
Damien George57a4b4f2014-04-18 22:29:21 +0100275 mp_buffer_info_t bufinfo;
Damien George5213eb32014-04-13 12:24:13 +0100276 mp_get_buffer_raise(args[1], &bufinfo);
277
278 // convert the bytes to an integer
279 machine_uint_t value = 0;
Damien Georgeb9e7ed42014-04-13 12:40:50 +0100280 for (const byte* buf = bufinfo.buf + bufinfo.len - 1; buf >= (byte*)bufinfo.buf; buf--) {
281 value = (value << 8) | *buf;
Damien George5213eb32014-04-13 12:24:13 +0100282 }
283
284 return mp_obj_new_int_from_uint(value);
Paul Sokolovskya985b452014-04-09 00:40:58 +0300285}
286
Damien George5213eb32014-04-13 12:24:13 +0100287STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(int_from_bytes_fun_obj, 2, 3, int_from_bytes);
288STATIC 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 +0300289
290STATIC mp_obj_t int_to_bytes(uint n_args, const mp_obj_t *args) {
291 machine_int_t val = mp_obj_int_get_checked(args[0]);
292
293 uint len = MP_OBJ_SMALL_INT_VALUE(args[1]);
294 byte *data;
295
296 // TODO: Support long ints
297 // TODO: Support byteorder param
298 // TODO: Support signed param
299 mp_obj_t o = mp_obj_str_builder_start(&mp_type_bytes, len, &data);
300 memset(data, 0, len);
301 memcpy(data, &val, len < sizeof(machine_int_t) ? len : sizeof(machine_int_t));
302 return mp_obj_str_builder_end(o);
303}
304
305STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(int_to_bytes_obj, 2, 4, int_to_bytes);
306
307STATIC const mp_map_elem_t int_locals_dict_table[] = {
308 { MP_OBJ_NEW_QSTR(MP_QSTR_from_bytes), (mp_obj_t)&int_from_bytes_obj },
309 { MP_OBJ_NEW_QSTR(MP_QSTR_to_bytes), (mp_obj_t)&int_to_bytes_obj },
310};
311
312STATIC MP_DEFINE_CONST_DICT(int_locals_dict, int_locals_dict_table);
313
Damien George3e1a5c12014-03-29 13:43:38 +0000314const mp_obj_type_t mp_type_int = {
Damien Georgec5966122014-02-15 16:10:44 +0000315 { &mp_type_type },
Damien Georgea71c83a2014-02-15 11:34:50 +0000316 .name = MP_QSTR_int,
Damien Georgee8208a72014-04-04 15:08:23 +0100317 .print = mp_obj_int_print,
318 .make_new = mp_obj_int_make_new,
319 .unary_op = mp_obj_int_unary_op,
320 .binary_op = mp_obj_int_binary_op,
Paul Sokolovskya985b452014-04-09 00:40:58 +0300321 .locals_dict = (mp_obj_t)&int_locals_dict,
Damien George5fa93b62014-01-22 14:35:10 +0000322};