diff options
Diffstat (limited to 'circuitpython/py/objint_longlong.c')
-rw-r--r-- | circuitpython/py/objint_longlong.c | 309 |
1 files changed, 309 insertions, 0 deletions
diff --git a/circuitpython/py/objint_longlong.c b/circuitpython/py/objint_longlong.c new file mode 100644 index 0000000..368c74e --- /dev/null +++ b/circuitpython/py/objint_longlong.c @@ -0,0 +1,309 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * SPDX-FileCopyrightText: Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2014 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include <stdlib.h> +#include <string.h> + +#include "py/smallint.h" +#include "py/objint.h" +#include "py/runtime.h" + +#include "supervisor/shared/translate.h" + +#if MICROPY_PY_BUILTINS_FLOAT +#include <math.h> +#endif + +#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG + +#if MICROPY_PY_SYS_MAXSIZE +// Export value for sys.maxsize +const mp_obj_int_t mp_sys_maxsize_obj = {{&mp_type_int}, MP_SSIZE_MAX}; +#endif + +mp_obj_t mp_obj_int_bit_length_impl(mp_obj_t self_in) { + assert(mp_obj_is_type(self_in, &mp_type_int)); + mp_obj_int_t *self = self_in; + long long val = self->val; + return MP_OBJ_NEW_SMALL_INT( + (val == 0) ? 0 : + (val == MP_SMALL_INT_MIN) ? 8 * sizeof(long long) : + (val < 0) ? 8 * sizeof(long long) - __builtin_clzll(-val) : + 8 * sizeof(long long) - __builtin_clzll(val)); +} + +mp_obj_t mp_obj_int_from_bytes_impl(bool big_endian, size_t len, const byte *buf) { + int delta = 1; + if (!big_endian) { + buf += len - 1; + delta = -1; + } + + mp_longint_impl_t value = 0; + for (; len--; buf += delta) { + value = (value << 8) | *buf; + } + return mp_obj_new_int_from_ll(value); +} + +void mp_obj_int_to_bytes_impl(mp_obj_t self_in, bool big_endian, size_t len, byte *buf) { + assert(mp_obj_is_type(self_in, &mp_type_int)); + mp_obj_int_t *self = self_in; + long long val = self->val; + if (big_endian) { + byte *b = buf + len; + while (b > buf) { + *--b = val; + val >>= 8; + } + } else { + for (; len > 0; --len) { + *buf++ = val; + val >>= 8; + } + } +} + +int mp_obj_int_sign(mp_obj_t self_in) { + mp_longint_impl_t val; + if (mp_obj_is_small_int(self_in)) { + val = MP_OBJ_SMALL_INT_VALUE(self_in); + } else { + mp_obj_int_t *self = self_in; + val = self->val; + } + if (val < 0) { + return -1; + } else if (val > 0) { + return 1; + } else { + return 0; + } +} + +mp_obj_t mp_obj_int_unary_op(mp_unary_op_t op, mp_obj_t o_in) { + mp_obj_int_t *o = o_in; + switch (op) { + case MP_UNARY_OP_BOOL: + return mp_obj_new_bool(o->val != 0); + + // truncate value to fit in mp_int_t, which gives the same hash as + // small int if the value fits without truncation + case MP_UNARY_OP_HASH: + return MP_OBJ_NEW_SMALL_INT((mp_int_t)o->val); + + case MP_UNARY_OP_POSITIVE: + return o_in; + case MP_UNARY_OP_NEGATIVE: + return mp_obj_new_int_from_ll(-o->val); + case MP_UNARY_OP_INVERT: + return mp_obj_new_int_from_ll(~o->val); + case MP_UNARY_OP_ABS: { + mp_obj_int_t *self = MP_OBJ_TO_PTR(o_in); + if (self->val >= 0) { + return o_in; + } + self = mp_obj_new_int_from_ll(self->val); + // TODO could overflow long long + self->val = -self->val; + return MP_OBJ_FROM_PTR(self); + } + default: + return MP_OBJ_NULL; // op not supported + } +} + +mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { + long long lhs_val; + long long rhs_val; + + if (mp_obj_is_small_int(lhs_in)) { + lhs_val = MP_OBJ_SMALL_INT_VALUE(lhs_in); + } else { + assert(mp_obj_is_type(lhs_in, &mp_type_int)); + lhs_val = ((mp_obj_int_t *)lhs_in)->val; + } + + if (mp_obj_is_small_int(rhs_in)) { + rhs_val = MP_OBJ_SMALL_INT_VALUE(rhs_in); + } else if (mp_obj_is_type(rhs_in, &mp_type_int)) { + rhs_val = ((mp_obj_int_t *)rhs_in)->val; + } else { + // delegate to generic function to check for extra cases + return mp_obj_int_binary_op_extra_cases(op, lhs_in, rhs_in); + } + + switch (op) { + case MP_BINARY_OP_ADD: + case MP_BINARY_OP_INPLACE_ADD: + return mp_obj_new_int_from_ll(lhs_val + rhs_val); + case MP_BINARY_OP_SUBTRACT: + case MP_BINARY_OP_INPLACE_SUBTRACT: + return mp_obj_new_int_from_ll(lhs_val - rhs_val); + case MP_BINARY_OP_MULTIPLY: + case MP_BINARY_OP_INPLACE_MULTIPLY: + return mp_obj_new_int_from_ll(lhs_val * rhs_val); + case MP_BINARY_OP_FLOOR_DIVIDE: + case MP_BINARY_OP_INPLACE_FLOOR_DIVIDE: + if (rhs_val == 0) { + goto zero_division; + } + return mp_obj_new_int_from_ll(lhs_val / rhs_val); + case MP_BINARY_OP_MODULO: + case MP_BINARY_OP_INPLACE_MODULO: + if (rhs_val == 0) { + goto zero_division; + } + return mp_obj_new_int_from_ll(lhs_val % rhs_val); + + case MP_BINARY_OP_AND: + case MP_BINARY_OP_INPLACE_AND: + return mp_obj_new_int_from_ll(lhs_val & rhs_val); + case MP_BINARY_OP_OR: + case MP_BINARY_OP_INPLACE_OR: + return mp_obj_new_int_from_ll(lhs_val | rhs_val); + case MP_BINARY_OP_XOR: + case MP_BINARY_OP_INPLACE_XOR: + return mp_obj_new_int_from_ll(lhs_val ^ rhs_val); + + case MP_BINARY_OP_LSHIFT: + case MP_BINARY_OP_INPLACE_LSHIFT: + return mp_obj_new_int_from_ll(lhs_val << (int)rhs_val); + case MP_BINARY_OP_RSHIFT: + case MP_BINARY_OP_INPLACE_RSHIFT: + return mp_obj_new_int_from_ll(lhs_val >> (int)rhs_val); + + case MP_BINARY_OP_POWER: + case MP_BINARY_OP_INPLACE_POWER: { + if (rhs_val < 0) { + #if MICROPY_PY_BUILTINS_FLOAT + return mp_obj_float_binary_op(op, lhs_val, rhs_in); + #else + mp_raise_ValueError(MP_ERROR_TEXT("negative power with no float support")); + #endif + } + long long ans = 1; + while (rhs_val > 0) { + if (rhs_val & 1) { + ans *= lhs_val; + } + if (rhs_val == 1) { + break; + } + rhs_val /= 2; + lhs_val *= lhs_val; + } + return mp_obj_new_int_from_ll(ans); + } + + case MP_BINARY_OP_LESS: + return mp_obj_new_bool(lhs_val < rhs_val); + case MP_BINARY_OP_MORE: + return mp_obj_new_bool(lhs_val > rhs_val); + case MP_BINARY_OP_LESS_EQUAL: + return mp_obj_new_bool(lhs_val <= rhs_val); + case MP_BINARY_OP_MORE_EQUAL: + return mp_obj_new_bool(lhs_val >= rhs_val); + case MP_BINARY_OP_EQUAL: + return mp_obj_new_bool(lhs_val == rhs_val); + + default: + return MP_OBJ_NULL; // op not supported + } + +zero_division: + mp_raise_msg(&mp_type_ZeroDivisionError, MP_ERROR_TEXT("division by zero")); +} + +mp_obj_t mp_obj_new_int(mp_int_t value) { + if (MP_SMALL_INT_FITS(value)) { + return MP_OBJ_NEW_SMALL_INT(value); + } + return mp_obj_new_int_from_ll(value); +} + +mp_obj_t mp_obj_new_int_from_uint(mp_uint_t value) { + // SMALL_INT accepts only signed numbers, so make sure the input + // value fits completely in the small-int positive range. + if ((value & ~MP_SMALL_INT_POSITIVE_MASK) == 0) { + return MP_OBJ_NEW_SMALL_INT(value); + } + return mp_obj_new_int_from_ll(value); +} + +mp_obj_t mp_obj_new_int_from_ll(long long val) { + mp_obj_int_t *o = m_new_obj(mp_obj_int_t); + o->base.type = &mp_type_int; + o->val = val; + return o; +} + +mp_obj_t mp_obj_new_int_from_ull(unsigned long long val) { + // TODO raise an exception if the unsigned long long won't fit + if (val >> (sizeof(unsigned long long) * 8 - 1) != 0) { + mp_raise_msg(&mp_type_OverflowError, MP_ERROR_TEXT("ulonglong too large")); + } + mp_obj_int_t *o = m_new_obj(mp_obj_int_t); + o->base.type = &mp_type_int; + o->val = val; + return o; +} + +mp_obj_t mp_obj_new_int_from_str_len(const char **str, size_t len, bool neg, unsigned int base) { + // TODO this does not honor the given length of the string, but it all cases it should anyway be null terminated + // TODO check overflow + mp_obj_int_t *o = m_new_obj(mp_obj_int_t); + o->base.type = &mp_type_int; + char *endptr; + o->val = strtoll(*str, &endptr, base); + *str = endptr; + return o; +} + +mp_int_t mp_obj_int_get_truncated(mp_const_obj_t self_in) { + if (mp_obj_is_small_int(self_in)) { + return MP_OBJ_SMALL_INT_VALUE(self_in); + } else { + const mp_obj_int_t *self = self_in; + return self->val; + } +} + +mp_int_t mp_obj_int_get_checked(mp_const_obj_t self_in) { + // TODO: Check overflow + return mp_obj_int_get_truncated(self_in); +} + +#if MICROPY_PY_BUILTINS_FLOAT +mp_float_t mp_obj_int_as_float_impl(mp_obj_t self_in) { + assert(mp_obj_is_type(self_in, &mp_type_int)); + mp_obj_int_t *self = self_in; + return self->val; +} +#endif + +#endif |