Skip to content

Commit ffe911d

Browse files
committed
py: Make long ints hashable.
Addresses issue adafruit#765.
1 parent 4ecb700 commit ffe911d

File tree

7 files changed

+45
-0
lines changed

7 files changed

+45
-0
lines changed

py/mpz.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1213,6 +1213,22 @@ mpz_t *mpz_mod(const mpz_t *lhs, const mpz_t *rhs) {
12131213
}
12141214
#endif
12151215

1216+
// must return actual int value if it fits in mp_int_t
1217+
mp_int_t mpz_hash(const mpz_t *z) {
1218+
mp_int_t val = 0;
1219+
mpz_dig_t *d = z->dig + z->len;
1220+
1221+
while (--d >= z->dig) {
1222+
val = (val << DIG_SIZE) | *d;
1223+
}
1224+
1225+
if (z->neg != 0) {
1226+
val = -val;
1227+
}
1228+
1229+
return val;
1230+
}
1231+
12161232
// TODO check that this correctly handles overflow in all cases
12171233
mp_int_t mpz_as_int(const mpz_t *i) {
12181234
mp_int_t val = 0;

py/mpz.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ void mpz_divmod_inpl(mpz_t *dest_quo, mpz_t *dest_rem, const mpz_t *lhs, const m
9696
mpz_t *mpz_div(const mpz_t *lhs, const mpz_t *rhs);
9797
mpz_t *mpz_mod(const mpz_t *lhs, const mpz_t *rhs);
9898

99+
mp_int_t mpz_hash(const mpz_t *z);
99100
mp_int_t mpz_as_int(const mpz_t *z);
100101
bool mpz_as_int_checked(const mpz_t *z, mp_int_t *value);
101102
#if MICROPY_PY_BUILTINS_FLOAT

py/obj.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
* THE SOFTWARE.
2525
*/
2626

27+
#include <stdint.h>
2728
#include <stdio.h>
2829
#include <stdarg.h>
2930
#include <assert.h>
@@ -33,6 +34,8 @@
3334
#include "misc.h"
3435
#include "qstr.h"
3536
#include "obj.h"
37+
#include "mpz.h"
38+
#include "objint.h"
3639
#include "runtime0.h"
3740
#include "runtime.h"
3841
#include "stackctrl.h"
@@ -152,6 +155,8 @@ mp_int_t mp_obj_hash(mp_obj_t o_in) {
152155
return 1; // needs to hash to same as the integer 1, since True==1
153156
} else if (MP_OBJ_IS_SMALL_INT(o_in)) {
154157
return MP_OBJ_SMALL_INT_VALUE(o_in);
158+
} else if (MP_OBJ_IS_TYPE(o_in, &mp_type_int)) {
159+
return mp_obj_int_hash(o_in);
155160
} else if (MP_OBJ_IS_STR(o_in) || MP_OBJ_IS_TYPE(o_in, &mp_type_bytes)) {
156161
return mp_obj_str_get_hash(o_in);
157162
} else if (MP_OBJ_IS_TYPE(o_in, &mp_type_NoneType)) {

py/objint.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,10 @@ char *mp_obj_int_formatted(char **buf, int *buf_size, int *fmt_size, mp_const_ob
215215

216216
#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE
217217

218+
mp_int_t mp_obj_int_hash(mp_obj_t self_in) {
219+
return MP_OBJ_SMALL_INT_VALUE(self_in);
220+
}
221+
218222
bool mp_obj_int_is_positive(mp_obj_t self_in) {
219223
return mp_obj_get_int(self_in) >= 0;
220224
}

py/objint.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ char *mp_obj_int_formatted(char **buf, int *buf_size, int *fmt_size, mp_const_ob
3838
int base, const char *prefix, char base_char, char comma);
3939
char *mp_obj_int_formatted_impl(char **buf, int *buf_size, int *fmt_size, mp_const_obj_t self_in,
4040
int base, const char *prefix, char base_char, char comma);
41+
mp_int_t mp_obj_int_hash(mp_obj_t self_in);
4142
bool mp_obj_int_is_positive(mp_obj_t self_in);
4243
mp_obj_t mp_obj_int_unary_op(int op, mp_obj_t o_in);
4344
mp_obj_t mp_obj_int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in);

py/objint_longlong.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,16 @@
5555
const mp_obj_int_t mp_maxsize_obj = {{&mp_type_int}, INT_MAX};
5656
#endif
5757

58+
mp_int_t mp_obj_int_hash(mp_obj_t self_in) {
59+
if (MP_OBJ_IS_SMALL_INT(self_in)) {
60+
return MP_OBJ_SMALL_INT_VALUE(self_in);
61+
}
62+
mp_obj_int_t *self = self_in;
63+
// truncate value to fit in mp_int_t, which gives the same hash as
64+
// small int if the value fits without truncation
65+
return self->val;
66+
}
67+
5868
bool mp_obj_int_is_positive(mp_obj_t self_in) {
5969
if (MP_OBJ_IS_SMALL_INT(self_in)) {
6070
return MP_OBJ_SMALL_INT_VALUE(self_in) >= 0;

py/objint_mpz.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,14 @@ char *mp_obj_int_formatted_impl(char **buf, int *buf_size, int *fmt_size, mp_con
9696
return str;
9797
}
9898

99+
mp_int_t mp_obj_int_hash(mp_obj_t self_in) {
100+
if (MP_OBJ_IS_SMALL_INT(self_in)) {
101+
return MP_OBJ_SMALL_INT_VALUE(self_in);
102+
}
103+
mp_obj_int_t *self = self_in;
104+
return mpz_hash(&self->mpz);
105+
}
106+
99107
bool mp_obj_int_is_positive(mp_obj_t self_in) {
100108
if (MP_OBJ_IS_SMALL_INT(self_in)) {
101109
return MP_OBJ_SMALL_INT_VALUE(self_in) >= 0;

0 commit comments

Comments
 (0)