py: Make it so that printing a small int does not allocate heap memory.
With the implementation of proper string formatting, code to print a small int was delegated to mpz_as_str_inpl (after first converting the small int to an mpz using stack memory). But mpz_as_str_inpl allocates heap memory to do the conversion, so small ints needed heap memory just to be printed. This fix has a separate function to print small ints, which does not allocate heap, and allocates less stack. String formatting, printf and pfenv are now large beasts, with some semi-duplicated code.
This commit is contained in:
parent
803b9263ab
commit
88d7bba961
46
py/objint.c
46
py/objint.c
|
@ -70,15 +70,13 @@ void mp_obj_int_print(void (*print)(void *env, const char *fmt, ...), void *env,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE || MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG
|
|
||||||
|
|
||||||
#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG
|
#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG
|
||||||
typedef mp_longint_impl_t fmt_int_t;
|
typedef mp_longint_impl_t fmt_int_t;
|
||||||
#else
|
#else
|
||||||
typedef mp_small_int_t fmt_int_t;
|
typedef mp_small_int_t fmt_int_t;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static const uint log_base2_floor[] = {
|
STATIC const uint log_base2_floor[] = {
|
||||||
0,
|
0,
|
||||||
0, 1, 1, 2,
|
0, 1, 1, 2,
|
||||||
2, 2, 2, 3,
|
2, 2, 2, 3,
|
||||||
|
@ -90,7 +88,7 @@ static const uint log_base2_floor[] = {
|
||||||
4, 4, 4, 5
|
4, 4, 4, 5
|
||||||
};
|
};
|
||||||
|
|
||||||
uint int_as_str_size_formatted(uint base, const char *prefix, char comma) {
|
STATIC uint int_as_str_size_formatted(uint base, const char *prefix, char comma) {
|
||||||
if (base < 2 || base > 32) {
|
if (base < 2 || base > 32) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -110,22 +108,29 @@ uint int_as_str_size_formatted(uint base, const char *prefix, char comma) {
|
||||||
// formatted size will be in *fmt_size.
|
// formatted size will be in *fmt_size.
|
||||||
char *mp_obj_int_formatted(char **buf, int *buf_size, int *fmt_size, mp_obj_t self_in,
|
char *mp_obj_int_formatted(char **buf, int *buf_size, int *fmt_size, mp_obj_t self_in,
|
||||||
int base, const char *prefix, char base_char, char comma) {
|
int base, const char *prefix, char base_char, char comma) {
|
||||||
if (!MP_OBJ_IS_INT(self_in)) {
|
fmt_int_t num;
|
||||||
|
if (MP_OBJ_IS_SMALL_INT(self_in)) {
|
||||||
|
// A small int; get the integer value to format.
|
||||||
|
num = mp_obj_get_int(self_in);
|
||||||
|
#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
|
||||||
|
} else if (MP_OBJ_IS_TYPE(self_in, &mp_type_int)) {
|
||||||
|
// Not a small int.
|
||||||
|
#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG
|
||||||
|
mp_obj_int_t *self = self_in;
|
||||||
|
// Get the value to format; mp_obj_get_int truncates to machine_int_t.
|
||||||
|
num = self->val;
|
||||||
|
#else
|
||||||
|
// Delegate to the implementation for the long int.
|
||||||
|
return mp_obj_int_formatted_impl(buf, buf_size, fmt_size, self_in, base, prefix, base_char, comma);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
// Not an int.
|
||||||
buf[0] = '\0';
|
buf[0] = '\0';
|
||||||
*fmt_size = 0;
|
*fmt_size = 0;
|
||||||
return *buf;
|
return *buf;
|
||||||
}
|
}
|
||||||
fmt_int_t num;
|
|
||||||
#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG
|
|
||||||
mp_obj_int_t *self = self_in;
|
|
||||||
if (MP_OBJ_IS_TYPE(self_in, &mp_type_int)) {
|
|
||||||
// mp_obj_get_int truncates to machine_int_t
|
|
||||||
num = self->val;
|
|
||||||
} else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
num = mp_obj_get_int(self_in);
|
|
||||||
}
|
|
||||||
char sign = '\0';
|
char sign = '\0';
|
||||||
if (num < 0) {
|
if (num < 0) {
|
||||||
num = -num;
|
num = -num;
|
||||||
|
@ -180,12 +185,11 @@ char *mp_obj_int_formatted(char **buf, int *buf_size, int *fmt_size, mp_obj_t se
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE
|
||||||
|
|
||||||
bool mp_obj_int_is_positive(mp_obj_t self_in) {
|
bool mp_obj_int_is_positive(mp_obj_t self_in) {
|
||||||
return mp_obj_get_int(self_in) >= 0;
|
return mp_obj_get_int(self_in) >= 0;
|
||||||
}
|
}
|
||||||
#endif // LONGLONG or NONE
|
|
||||||
|
|
||||||
#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE
|
|
||||||
|
|
||||||
// This is called for operations on SMALL_INT that are not handled by mp_unary_op
|
// This is called for operations on SMALL_INT that are not handled by mp_unary_op
|
||||||
mp_obj_t mp_obj_int_unary_op(int op, mp_obj_t o_in) {
|
mp_obj_t mp_obj_int_unary_op(int op, mp_obj_t o_in) {
|
||||||
|
|
|
@ -10,6 +10,8 @@ typedef struct _mp_obj_int_t {
|
||||||
void mp_obj_int_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind);
|
void mp_obj_int_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind);
|
||||||
char *mp_obj_int_formatted(char **buf, int *buf_size, int *fmt_size, mp_obj_t self_in,
|
char *mp_obj_int_formatted(char **buf, int *buf_size, int *fmt_size, mp_obj_t self_in,
|
||||||
int base, const char *prefix, char base_char, char comma);
|
int base, const char *prefix, char base_char, char comma);
|
||||||
|
char *mp_obj_int_formatted_impl(char **buf, int *buf_size, int *fmt_size, mp_obj_t self_in,
|
||||||
|
int base, const char *prefix, char base_char, char comma);
|
||||||
bool mp_obj_int_is_positive(mp_obj_t self_in);
|
bool mp_obj_int_is_positive(mp_obj_t self_in);
|
||||||
mp_obj_t mp_obj_int_unary_op(int op, mp_obj_t o_in);
|
mp_obj_t mp_obj_int_unary_op(int op, mp_obj_t o_in);
|
||||||
mp_obj_t mp_obj_int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in);
|
mp_obj_t mp_obj_int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in);
|
||||||
|
|
|
@ -22,6 +22,14 @@
|
||||||
#define SUFFIX ""
|
#define SUFFIX ""
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
bool mp_obj_int_is_positive(mp_obj_t self_in) {
|
||||||
|
if (MP_OBJ_IS_SMALL_INT(self_in)) {
|
||||||
|
return MP_OBJ_SMALL_INT_VALUE(self_in) >= 0;
|
||||||
|
}
|
||||||
|
mp_obj_int_t *self = self_in;
|
||||||
|
return self->val >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
mp_obj_t mp_obj_int_unary_op(int op, mp_obj_t o_in) {
|
mp_obj_t mp_obj_int_unary_op(int op, mp_obj_t o_in) {
|
||||||
mp_obj_int_t *o = o_in;
|
mp_obj_int_t *o = o_in;
|
||||||
switch (op) {
|
switch (op) {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
#include "nlr.h"
|
#include "nlr.h"
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
|
@ -29,30 +30,21 @@ STATIC mp_obj_int_t *mp_obj_int_new_mpz(void) {
|
||||||
//
|
//
|
||||||
// The resulting formatted string will be returned from this function and the
|
// The resulting formatted string will be returned from this function and the
|
||||||
// formatted size will be in *fmt_size.
|
// formatted size will be in *fmt_size.
|
||||||
char *mp_obj_int_formatted(char **buf, int *buf_size, int *fmt_size, mp_obj_t self_in,
|
//
|
||||||
int base, const char *prefix, char base_char, char comma) {
|
// This particular routine should only be called for the mpz representation of the int.
|
||||||
mpz_t small_mpz;
|
char *mp_obj_int_formatted_impl(char **buf, int *buf_size, int *fmt_size, mp_obj_t self_in,
|
||||||
mpz_t *mpz;
|
int base, const char *prefix, char base_char, char comma) {
|
||||||
mpz_dig_t small_dig[(sizeof(mp_small_int_t) * 8 + MPZ_DIG_SIZE - 1) / MPZ_DIG_SIZE];
|
assert(MP_OBJ_IS_TYPE(self_in, &mp_type_int));
|
||||||
|
mp_obj_int_t *self = self_in;
|
||||||
|
|
||||||
if (MP_OBJ_IS_SMALL_INT(self_in)) {
|
uint needed_size = mpz_as_str_size_formatted(&self->mpz, base, prefix, comma);
|
||||||
mpz_init_fixed_from_int(&small_mpz, small_dig,
|
|
||||||
sizeof(small_dig) / sizeof(small_dig[0]),
|
|
||||||
MP_OBJ_SMALL_INT_VALUE(self_in));
|
|
||||||
mpz = &small_mpz;
|
|
||||||
} else {
|
|
||||||
mp_obj_int_t *self = self_in;
|
|
||||||
mpz = &self->mpz;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint needed_size = mpz_as_str_size_formatted(mpz, base, prefix, comma);
|
|
||||||
if (needed_size > *buf_size) {
|
if (needed_size > *buf_size) {
|
||||||
*buf = m_new(char, needed_size);
|
*buf = m_new(char, needed_size);
|
||||||
*buf_size = needed_size;
|
*buf_size = needed_size;
|
||||||
}
|
}
|
||||||
char *str = *buf;
|
char *str = *buf;
|
||||||
|
|
||||||
*fmt_size = mpz_as_str_inpl(mpz, base, prefix, base_char, comma, str);
|
*fmt_size = mpz_as_str_inpl(&self->mpz, base, prefix, base_char, comma, str);
|
||||||
|
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue