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 | * Copyright (c) 2014 Paul Sokolovsky |
8 | * |
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
10 | * of this software and associated documentation files (the "Software"), to deal |
11 | * in the Software without restriction, including without limitation the rights |
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
13 | * copies of the Software, and to permit persons to whom the Software is |
14 | * furnished to do so, subject to the following conditions: |
15 | * |
16 | * The above copyright notice and this permission notice shall be included in |
17 | * all copies or substantial portions of the Software. |
18 | * |
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
25 | * THE SOFTWARE. |
26 | */ |
27 | |
28 | #include <stdlib.h> |
29 | #include <string.h> |
30 | |
31 | #include "py/smallint.h" |
32 | #include "py/objint.h" |
33 | #include "py/runtime.h" |
34 | |
35 | #if MICROPY_PY_BUILTINS_FLOAT |
36 | #include <math.h> |
37 | #endif |
38 | |
39 | #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG |
40 | |
41 | #if MICROPY_PY_SYS_MAXSIZE |
42 | // Export value for sys.maxsize |
43 | const mp_obj_int_t mp_sys_maxsize_obj = {{&mp_type_int}, MP_SSIZE_MAX}; |
44 | #endif |
45 | |
46 | mp_obj_t mp_obj_int_from_bytes_impl(bool big_endian, size_t len, const byte *buf) { |
47 | int delta = 1; |
48 | if (!big_endian) { |
49 | buf += len - 1; |
50 | delta = -1; |
51 | } |
52 | |
53 | mp_longint_impl_t value = 0; |
54 | for (; len--; buf += delta) { |
55 | value = (value << 8) | *buf; |
56 | } |
57 | return mp_obj_new_int_from_ll(value); |
58 | } |
59 | |
60 | void mp_obj_int_to_bytes_impl(mp_obj_t self_in, bool big_endian, size_t len, byte *buf) { |
61 | assert(mp_obj_is_type(self_in, &mp_type_int)); |
62 | mp_obj_int_t *self = self_in; |
63 | long long val = self->val; |
64 | if (big_endian) { |
65 | byte *b = buf + len; |
66 | while (b > buf) { |
67 | *--b = val; |
68 | val >>= 8; |
69 | } |
70 | } else { |
71 | for (; len > 0; --len) { |
72 | *buf++ = val; |
73 | val >>= 8; |
74 | } |
75 | } |
76 | } |
77 | |
78 | int mp_obj_int_sign(mp_obj_t self_in) { |
79 | mp_longint_impl_t val; |
80 | if (mp_obj_is_small_int(self_in)) { |
81 | val = MP_OBJ_SMALL_INT_VALUE(self_in); |
82 | } else { |
83 | mp_obj_int_t *self = self_in; |
84 | val = self->val; |
85 | } |
86 | if (val < 0) { |
87 | return -1; |
88 | } else if (val > 0) { |
89 | return 1; |
90 | } else { |
91 | return 0; |
92 | } |
93 | } |
94 | |
95 | mp_obj_t mp_obj_int_unary_op(mp_unary_op_t op, mp_obj_t o_in) { |
96 | mp_obj_int_t *o = o_in; |
97 | switch (op) { |
98 | case MP_UNARY_OP_BOOL: |
99 | return mp_obj_new_bool(o->val != 0); |
100 | |
101 | // truncate value to fit in mp_int_t, which gives the same hash as |
102 | // small int if the value fits without truncation |
103 | case MP_UNARY_OP_HASH: |
104 | return MP_OBJ_NEW_SMALL_INT((mp_int_t)o->val); |
105 | |
106 | case MP_UNARY_OP_POSITIVE: |
107 | return o_in; |
108 | case MP_UNARY_OP_NEGATIVE: |
109 | return mp_obj_new_int_from_ll(-o->val); |
110 | case MP_UNARY_OP_INVERT: |
111 | return mp_obj_new_int_from_ll(~o->val); |
112 | case MP_UNARY_OP_ABS: { |
113 | mp_obj_int_t *self = MP_OBJ_TO_PTR(o_in); |
114 | if (self->val >= 0) { |
115 | return o_in; |
116 | } |
117 | self = mp_obj_new_int_from_ll(self->val); |
118 | // TODO could overflow long long |
119 | self->val = -self->val; |
120 | return MP_OBJ_FROM_PTR(self); |
121 | } |
122 | default: |
123 | return MP_OBJ_NULL; // op not supported |
124 | } |
125 | } |
126 | |
127 | mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { |
128 | long long lhs_val; |
129 | long long rhs_val; |
130 | |
131 | if (mp_obj_is_small_int(lhs_in)) { |
132 | lhs_val = MP_OBJ_SMALL_INT_VALUE(lhs_in); |
133 | } else { |
134 | assert(mp_obj_is_type(lhs_in, &mp_type_int)); |
135 | lhs_val = ((mp_obj_int_t *)lhs_in)->val; |
136 | } |
137 | |
138 | if (mp_obj_is_small_int(rhs_in)) { |
139 | rhs_val = MP_OBJ_SMALL_INT_VALUE(rhs_in); |
140 | } else if (mp_obj_is_type(rhs_in, &mp_type_int)) { |
141 | rhs_val = ((mp_obj_int_t *)rhs_in)->val; |
142 | } else { |
143 | // delegate to generic function to check for extra cases |
144 | return mp_obj_int_binary_op_extra_cases(op, lhs_in, rhs_in); |
145 | } |
146 | |
147 | switch (op) { |
148 | case MP_BINARY_OP_ADD: |
149 | case MP_BINARY_OP_INPLACE_ADD: |
150 | return mp_obj_new_int_from_ll(lhs_val + rhs_val); |
151 | case MP_BINARY_OP_SUBTRACT: |
152 | case MP_BINARY_OP_INPLACE_SUBTRACT: |
153 | return mp_obj_new_int_from_ll(lhs_val - rhs_val); |
154 | case MP_BINARY_OP_MULTIPLY: |
155 | case MP_BINARY_OP_INPLACE_MULTIPLY: |
156 | return mp_obj_new_int_from_ll(lhs_val * rhs_val); |
157 | case MP_BINARY_OP_FLOOR_DIVIDE: |
158 | case MP_BINARY_OP_INPLACE_FLOOR_DIVIDE: |
159 | if (rhs_val == 0) { |
160 | goto zero_division; |
161 | } |
162 | return mp_obj_new_int_from_ll(lhs_val / rhs_val); |
163 | case MP_BINARY_OP_MODULO: |
164 | case MP_BINARY_OP_INPLACE_MODULO: |
165 | if (rhs_val == 0) { |
166 | goto zero_division; |
167 | } |
168 | return mp_obj_new_int_from_ll(lhs_val % rhs_val); |
169 | |
170 | case MP_BINARY_OP_AND: |
171 | case MP_BINARY_OP_INPLACE_AND: |
172 | return mp_obj_new_int_from_ll(lhs_val & rhs_val); |
173 | case MP_BINARY_OP_OR: |
174 | case MP_BINARY_OP_INPLACE_OR: |
175 | return mp_obj_new_int_from_ll(lhs_val | rhs_val); |
176 | case MP_BINARY_OP_XOR: |
177 | case MP_BINARY_OP_INPLACE_XOR: |
178 | return mp_obj_new_int_from_ll(lhs_val ^ rhs_val); |
179 | |
180 | case MP_BINARY_OP_LSHIFT: |
181 | case MP_BINARY_OP_INPLACE_LSHIFT: |
182 | return mp_obj_new_int_from_ll(lhs_val << (int)rhs_val); |
183 | case MP_BINARY_OP_RSHIFT: |
184 | case MP_BINARY_OP_INPLACE_RSHIFT: |
185 | return mp_obj_new_int_from_ll(lhs_val >> (int)rhs_val); |
186 | |
187 | case MP_BINARY_OP_POWER: |
188 | case MP_BINARY_OP_INPLACE_POWER: { |
189 | if (rhs_val < 0) { |
190 | #if MICROPY_PY_BUILTINS_FLOAT |
191 | return mp_obj_float_binary_op(op, lhs_val, rhs_in); |
192 | #else |
193 | mp_raise_ValueError(MP_ERROR_TEXT("negative power with no float support" )); |
194 | #endif |
195 | } |
196 | long long ans = 1; |
197 | while (rhs_val > 0) { |
198 | if (rhs_val & 1) { |
199 | ans *= lhs_val; |
200 | } |
201 | if (rhs_val == 1) { |
202 | break; |
203 | } |
204 | rhs_val /= 2; |
205 | lhs_val *= lhs_val; |
206 | } |
207 | return mp_obj_new_int_from_ll(ans); |
208 | } |
209 | |
210 | case MP_BINARY_OP_LESS: |
211 | return mp_obj_new_bool(lhs_val < rhs_val); |
212 | case MP_BINARY_OP_MORE: |
213 | return mp_obj_new_bool(lhs_val > rhs_val); |
214 | case MP_BINARY_OP_LESS_EQUAL: |
215 | return mp_obj_new_bool(lhs_val <= rhs_val); |
216 | case MP_BINARY_OP_MORE_EQUAL: |
217 | return mp_obj_new_bool(lhs_val >= rhs_val); |
218 | case MP_BINARY_OP_EQUAL: |
219 | return mp_obj_new_bool(lhs_val == rhs_val); |
220 | |
221 | default: |
222 | return MP_OBJ_NULL; // op not supported |
223 | } |
224 | |
225 | zero_division: |
226 | mp_raise_msg(&mp_type_ZeroDivisionError, MP_ERROR_TEXT("divide by zero" )); |
227 | } |
228 | |
229 | mp_obj_t mp_obj_new_int(mp_int_t value) { |
230 | if (MP_SMALL_INT_FITS(value)) { |
231 | return MP_OBJ_NEW_SMALL_INT(value); |
232 | } |
233 | return mp_obj_new_int_from_ll(value); |
234 | } |
235 | |
236 | mp_obj_t mp_obj_new_int_from_uint(mp_uint_t value) { |
237 | // SMALL_INT accepts only signed numbers, so make sure the input |
238 | // value fits completely in the small-int positive range. |
239 | if ((value & ~MP_SMALL_INT_POSITIVE_MASK) == 0) { |
240 | return MP_OBJ_NEW_SMALL_INT(value); |
241 | } |
242 | return mp_obj_new_int_from_ll(value); |
243 | } |
244 | |
245 | mp_obj_t mp_obj_new_int_from_ll(long long val) { |
246 | mp_obj_int_t *o = m_new_obj(mp_obj_int_t); |
247 | o->base.type = &mp_type_int; |
248 | o->val = val; |
249 | return o; |
250 | } |
251 | |
252 | mp_obj_t mp_obj_new_int_from_ull(unsigned long long val) { |
253 | // TODO raise an exception if the unsigned long long won't fit |
254 | if (val >> (sizeof(unsigned long long) * 8 - 1) != 0) { |
255 | mp_raise_msg(&mp_type_OverflowError, MP_ERROR_TEXT("ulonglong too large" )); |
256 | } |
257 | mp_obj_int_t *o = m_new_obj(mp_obj_int_t); |
258 | o->base.type = &mp_type_int; |
259 | o->val = val; |
260 | return o; |
261 | } |
262 | |
263 | mp_obj_t mp_obj_new_int_from_str_len(const char **str, size_t len, bool neg, unsigned int base) { |
264 | // TODO this does not honor the given length of the string, but it all cases it should anyway be null terminated |
265 | // TODO check overflow |
266 | mp_obj_int_t *o = m_new_obj(mp_obj_int_t); |
267 | o->base.type = &mp_type_int; |
268 | char *endptr; |
269 | o->val = strtoll(*str, &endptr, base); |
270 | *str = endptr; |
271 | return o; |
272 | } |
273 | |
274 | mp_int_t mp_obj_int_get_truncated(mp_const_obj_t self_in) { |
275 | if (mp_obj_is_small_int(self_in)) { |
276 | return MP_OBJ_SMALL_INT_VALUE(self_in); |
277 | } else { |
278 | const mp_obj_int_t *self = self_in; |
279 | return self->val; |
280 | } |
281 | } |
282 | |
283 | mp_int_t mp_obj_int_get_checked(mp_const_obj_t self_in) { |
284 | // TODO: Check overflow |
285 | return mp_obj_int_get_truncated(self_in); |
286 | } |
287 | |
288 | #if MICROPY_PY_BUILTINS_FLOAT |
289 | mp_float_t mp_obj_int_as_float_impl(mp_obj_t self_in) { |
290 | assert(mp_obj_is_type(self_in, &mp_type_int)); |
291 | mp_obj_int_t *self = self_in; |
292 | return self->val; |
293 | } |
294 | #endif |
295 | |
296 | #endif |
297 | |