|
1 | 1 | #include <stdlib.h> |
2 | 2 | #include <stdint.h> |
3 | 3 | #include <assert.h> |
| 4 | +#include <string.h> |
4 | 5 |
|
5 | 6 | #include "nlr.h" |
6 | 7 | #include "misc.h" |
@@ -53,14 +54,129 @@ STATIC mp_obj_t mp_obj_int_make_new(mp_obj_t type_in, uint n_args, uint n_kw, co |
53 | 54 | } |
54 | 55 | } |
55 | 56 |
|
56 | | -#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE |
57 | | - |
58 | 57 | void mp_obj_int_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { |
59 | | - if (MP_OBJ_IS_SMALL_INT(self_in)) { |
60 | | - print(env, INT_FMT, MP_OBJ_SMALL_INT_VALUE(self_in)); |
| 58 | + // 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); |
| 70 | + } |
| 71 | +} |
| 72 | + |
| 73 | +#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE || MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG |
| 74 | + |
| 75 | +#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG |
| 76 | +typedef mp_longint_impl_t fmt_int_t; |
| 77 | +#else |
| 78 | +typedef mp_small_int_t fmt_int_t; |
| 79 | +#endif |
| 80 | + |
| 81 | +static const uint log_base2_floor[] = { |
| 82 | + 0, |
| 83 | + 0, 1, 1, 2, |
| 84 | + 2, 2, 2, 3, |
| 85 | + 3, 3, 3, 3, |
| 86 | + 3, 3, 3, 4, |
| 87 | + 4, 4, 4, 4, |
| 88 | + 4, 4, 4, 4, |
| 89 | + 4, 4, 4, 4, |
| 90 | + 4, 4, 4, 5 |
| 91 | +}; |
| 92 | + |
| 93 | +uint int_as_str_size_formatted(uint base, const char *prefix, char comma) { |
| 94 | + if (base < 2 || base > 32) { |
| 95 | + return 0; |
61 | 96 | } |
| 97 | + |
| 98 | + uint num_digits = sizeof(fmt_int_t) * 8 / log_base2_floor[base] + 1; |
| 99 | + uint num_commas = comma ? num_digits / 3: 0; |
| 100 | + uint prefix_len = prefix ? strlen(prefix) : 0; |
| 101 | + return num_digits + num_commas + prefix_len + 2; // +1 for sign, +1 for null byte |
62 | 102 | } |
63 | 103 |
|
| 104 | +// This routine expects you to pass in a buffer and size (in *buf and buf_size). |
| 105 | +// If, for some reason, this buffer is too small, then it will allocate a |
| 106 | +// buffer and return the allocated buffer and size in *buf and *buf_size. It |
| 107 | +// is the callers responsibility to free this allocated buffer. |
| 108 | +// |
| 109 | +// The resulting formatted string will be returned from this function and the |
| 110 | +// formatted size will be in *fmt_size. |
| 111 | +char *mp_obj_int_formatted(char **buf, int *buf_size, int *fmt_size, mp_obj_t self_in, |
| 112 | + int base, const char *prefix, char base_char, char comma) { |
| 113 | + if (!MP_OBJ_IS_INT(self_in)) { |
| 114 | + buf[0] = '\0'; |
| 115 | + *fmt_size = 0; |
| 116 | + return *buf; |
| 117 | + } |
| 118 | + fmt_int_t num = mp_obj_get_int(self_in); |
| 119 | + char sign = '\0'; |
| 120 | + if (num < 0) { |
| 121 | + num = -num; |
| 122 | + sign = '-'; |
| 123 | + } |
| 124 | + |
| 125 | + uint needed_size = int_as_str_size_formatted(base, prefix, comma); |
| 126 | + if (needed_size > *buf_size) { |
| 127 | + *buf = m_new(char, needed_size); |
| 128 | + *buf_size = needed_size; |
| 129 | + } |
| 130 | + char *str = *buf; |
| 131 | + |
| 132 | + char *b = str + needed_size; |
| 133 | + *(--b) = '\0'; |
| 134 | + char *last_comma = b; |
| 135 | + |
| 136 | + if (num == 0) { |
| 137 | + *(--b) = '0'; |
| 138 | + } else { |
| 139 | + do { |
| 140 | + int c = num % base; |
| 141 | + num /= base; |
| 142 | + if (c >= 10) { |
| 143 | + c += base_char - 10; |
| 144 | + } else { |
| 145 | + c += '0'; |
| 146 | + } |
| 147 | + *(--b) = c; |
| 148 | + if (comma && num != 0 && b > str && (last_comma - b) == 3) { |
| 149 | + *(--b) = comma; |
| 150 | + last_comma = b; |
| 151 | + } |
| 152 | + } |
| 153 | + while (b > str && num != 0); |
| 154 | + } |
| 155 | + if (prefix) { |
| 156 | + size_t prefix_len = strlen(prefix); |
| 157 | + char *p = b - prefix_len; |
| 158 | + if (p > str) { |
| 159 | + b = p; |
| 160 | + while (*prefix) { |
| 161 | + *p++ = *prefix++; |
| 162 | + } |
| 163 | + } |
| 164 | + } |
| 165 | + if (sign && b > str) { |
| 166 | + *(--b) = sign; |
| 167 | + } |
| 168 | + *fmt_size = *buf + needed_size - b - 1; |
| 169 | + |
| 170 | + return b; |
| 171 | +} |
| 172 | + |
| 173 | +bool mp_obj_int_is_positive(mp_obj_t self_in) { |
| 174 | + return mp_obj_get_int(self_in) >= 0; |
| 175 | +} |
| 176 | +#endif // LONGLONG or NONE |
| 177 | + |
| 178 | +#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE |
| 179 | + |
64 | 180 | // This is called for operations on SMALL_INT that are not handled by mp_unary_op |
65 | 181 | mp_obj_t mp_obj_int_unary_op(int op, mp_obj_t o_in) { |
66 | 182 | return MP_OBJ_NULL; |
|
0 commit comments