From 009a79b5c94930e4f7b664dc47716cbe88baa6b1 Mon Sep 17 00:00:00 2001 From: dearblue Date: Thu, 26 Sep 2024 21:49:05 +0900 Subject: [PATCH 1/2] Embedding in `RBigint` objects Integers up to 3 words long will no longer allocate heap space. --- mrbgems/mruby-bigint/core/bigint.c | 826 ++++++++++++++++------------- mrbgems/mruby-bigint/core/bigint.h | 76 ++- 2 files changed, 547 insertions(+), 355 deletions(-) diff --git a/mrbgems/mruby-bigint/core/bigint.c b/mrbgems/mruby-bigint/core/bigint.c index ee87eedfc..bd9256931 100644 --- a/mrbgems/mruby-bigint/core/bigint.c +++ b/mrbgems/mruby-bigint/core/bigint.c @@ -22,95 +22,124 @@ #define iabs(x) (((x)>0)?(x):(-x)) #define imax(x,y) (((x)>(y))?(x):(y)) #define imin(x,y) (((x)<(y))?(x):(y)) -#define dg(x,i) (((size_t)i < (x)->sz)?(x)->p[i]:0) +#define dg(x,i) (((size_t)i < RBIGINT_SIZE(x))?RBIGINT_ARY(x)[i]:0) + +#define LIMB_COPY(x, y, num) do { \ + mp_limb *_x = (x); \ + const mp_limb *_y = (y); \ + for (size_t _num = (num); _num > 0; _num--) { \ + *_x++ = *_y++; \ + } \ +} while (0) +#define LIMB_ZERO(x, num) do { \ + mp_limb *_x = (x); \ + for (size_t _num = (num); _num > 0; _num--) { \ + *_x++ = 0; \ + } \ +} while (0) static void -mpz_init(mrb_state *mrb, mpz_t *s) +mpz_init(mrb_state *mrb, struct RBigint *s) { - s->p = NULL; - s->sn=0; - s->sz=0; + LIMB_ZERO(s->as.ary, RBIGINT_EMBED_SIZE_MAX); + RBIGINT_SET_EMBED_SIGN(s, 0); + RBIGINT_SET_EMBED_ZERO(s); } static void -mpz_realloc(mrb_state *mrb, mpz_t *x, size_t size) +mpz_realloc(mrb_state *mrb, struct RBigint *x, size_t size) { - if (x->sz < size) { - x->p=(mp_limb*)mrb_realloc(mrb, x->p, size*sizeof(mp_limb)); - for (size_t i=x->sz; ip[i] = 0; - x->sz = size; + if (RBIGINT_SIZE(x) < size) { + if (RBIGINT_EMBED_P(x)) { + if (size <= RBIGINT_EMBED_SIZE_MAX) { + LIMB_ZERO(RBIGINT_EMBED_ARY(x) + RBIGINT_EMBED_SIZE(x), size - RBIGINT_EMBED_SIZE(x)); + RBIGINT_SET_EMBED_SIZE(x, size); + return; + } + + mp_limb *p = (mp_limb*)mrb_malloc(mrb, size*sizeof(mp_limb)); + LIMB_COPY(p, RBIGINT_EMBED_ARY(x), RBIGINT_EMBED_SIZE(x)); + x->as.heap.p = p; + x->as.heap.sn = RBIGINT_EMBED_SIGN(x); + x->as.heap.sz = RBIGINT_EMBED_SIZE(x); + RBIGINT_SET_HEAP(x); + } + else { + x->as.heap.p = (mp_limb*)mrb_realloc(mrb, x->as.heap.p, size*sizeof(mp_limb)); + } + + LIMB_ZERO(x->as.heap.p + x->as.heap.sz, size - x->as.heap.sz); + x->as.heap.sz = size; } } static void -mpz_set(mrb_state *mrb, mpz_t *y, mpz_t *x) +mpz_set(mrb_state *mrb, struct RBigint *y, struct RBigint *x) { - size_t i, k = x->sz; + size_t k = RBIGINT_SIZE(x); mpz_realloc(mrb, y, k); - for (i=0;i < k; i++) - y->p[i] = x->p[i]; - - y->sz = k; - y->sn = x->sn; + LIMB_COPY(RBIGINT_ARY(y), RBIGINT_ARY(x), k); + RBIGINT_SET_SIZE(y, k); + RBIGINT_SET_SIGN(y, RBIGINT_SIGN(x)); } static void -mpz_init_set(mrb_state *mrb, mpz_t *s, mpz_t *t) +mpz_init_set(mrb_state *mrb, struct RBigint *s, struct RBigint *t) { mpz_init(mrb, s); mpz_set(mrb, s, t); } static void -mpz_set_int(mrb_state *mrb, mpz_t *y, mrb_int v) +mpz_set_int(mrb_state *mrb, struct RBigint *y, mrb_int v) { mrb_uint u; if (v == 0) { - y->sn=0; + RBIGINT_SET_SIGN(y, 0); u = 0; } else if (v > 0) { - y->sn = 1; + RBIGINT_SET_SIGN(y, 1); u = v; } else /* if (v < 0) */ { - y->sn = -1; + RBIGINT_SET_SIGN(y, -1); if (v == MRB_INT_MIN) u = v; else u = -v; } #if MRB_INT_BIT > DIG_SIZE if ((u & ~DIG_MASK) != 0) { mpz_realloc(mrb, y, 2); - y->p[1] = (mp_limb)HIGH(u); - y->p[0] = (mp_limb)LOW(u); + y->as.ary[1] = (mp_limb)HIGH(u); + y->as.ary[0] = (mp_limb)LOW(u); } else #endif { mpz_realloc(mrb, y, 1); - y->p[0] = (mp_limb)u; + y->as.ary[0] = (mp_limb)u; } } static void -mpz_set_uint64(mrb_state *mrb, mpz_t *y, uint64_t u) +mpz_set_uint64(mrb_state *mrb, struct RBigint *y, uint64_t u) { const size_t len = sizeof(uint64_t) / sizeof(mp_limb); - y->sn = (u != 0); mpz_realloc(mrb, y, len); + mrb_assert(RBIGINT_EMBED_P(y)); + RBIGINT_SET_EMBED_SIGN(y, (u != 0 ? 1 : 0)); for (size_t i=0; ip[i++] = (mp_limb)LOW(u); + y->as.ary[i++] = (mp_limb)LOW(u); u >>= DIG_SIZE; } } #ifdef MRB_INT32 static void -mpz_set_int64(mrb_state *mrb, mpz_t *y, int64_t v) +mpz_set_int64(mrb_state *mrb, struct RBigint *y, int64_t v) { uint64_t u; @@ -123,118 +152,149 @@ mpz_set_int64(mrb_state *mrb, mpz_t *y, int64_t v) } mpz_set_uint64(mrb, y, u); if (v < 0) { - y->sn = -1; + RBIGINT_SET_EMBED_SIGN(y, -1); } } #endif static void -mpz_init_set_int(mrb_state *mrb, mpz_t *y, mrb_int v) +mpz_init_set_int(mrb_state *mrb, struct RBigint *y, mrb_int v) { mpz_init(mrb, y); mpz_set_int(mrb, y, v); } static void -mpz_clear(mrb_state *mrb, mpz_t *s) +mpz_clear(mrb_state *mrb, struct RBigint *s) { - if (s->p) mrb_free(mrb, s->p); - s->p = NULL; - s->sn = 0; - s->sz = 0; + if (!RBIGINT_EMBED_P(s)) mrb_free(mrb, RBIGINT_HEAP_ARY(s)); + for (size_t i = 0; i < RBIGINT_EMBED_SIZE_MAX; i++) { + s->as.ary[i] = 0; + } + RBIGINT_SET_EMBED_SIGN(s, 0); + RBIGINT_SET_EMBED_ZERO(s); } static void -mpz_move(mrb_state *mrb, mpz_t *y, mpz_t *x) +mpz_move(mrb_state *mrb, struct RBigint *y, struct RBigint *x) { mpz_clear(mrb, y); - y->sn = x->sn; - y->sz = x->sz; - y->p = x->p; - x->p = NULL; - x->sn = 0; - x->sz = 0; + + if (RBIGINT_EMBED_P(x)) { + LIMB_COPY(y->as.ary, x->as.ary, RBIGINT_EMBED_SIZE_MAX); + RBIGINT_SET_EMBED_SIGN(y, RBIGINT_EMBED_SIGN(x)); + RBIGINT_SET_EMBED_SIZE(y, RBIGINT_EMBED_SIZE(x)); + } + else { + y->as.heap.sn = x->as.heap.sn; + y->as.heap.sz = x->as.heap.sz; + y->as.heap.p = x->as.heap.p; + RBIGINT_SET_HEAP(y); + x->as.heap.p = NULL; + x->as.heap.sn = 0; + x->as.heap.sz = 0; + } } static size_t -digits(mpz_t *x) +digits(struct RBigint *x) { size_t i; - if (x->sz == 0) return 0; - for (i = x->sz - 1; x->p[i] == 0; i--) + if (RBIGINT_SIZE(x) == 0) return 0; + const mp_limb *p = RBIGINT_ARY(x); + for (i = RBIGINT_SIZE(x) - 1; p[i] == 0; i--) if (i == 0) break; return i+1; } static void -trim(mpz_t *x) +trim(struct RBigint *x) { - while (x->sz && x->p[x->sz-1] == 0) { - x->sz--; + size_t n = RBIGINT_SIZE(x); + const mp_limb *p = RBIGINT_ARY(x) + n; + while (n > 0 && *--p == 0) { + n--; } + RBIGINT_SET_SIZE(x, n); } /* z = x + y, without regard for sign */ static void -uadd(mrb_state *mrb, mpz_t *z, mpz_t *x, mpz_t *y) +uadd(mrb_state *mrb, struct RBigint *z, struct RBigint *x, struct RBigint *y) { - if (y->sz < x->sz) { - mpz_t *t; /* swap x,y */ + size_t xsz = RBIGINT_SIZE(x); + size_t ysz = RBIGINT_SIZE(y); + if (ysz < xsz) { + struct RBigint *t; /* swap x,y */ t=x; x=y; y=t; + xsz = RBIGINT_SIZE(x); + ysz = RBIGINT_SIZE(y); } - /* now y->sz >= x->sz */ - mpz_realloc(mrb, z, y->sz+1); + /* now RBIGINT_SIZE(y) >= RBIGINT_SIZE(x) */ + mpz_realloc(mrb, z, ysz+1); + const mp_limb *xp = RBIGINT_ARY(x); + const mp_limb *yp = RBIGINT_ARY(y); + mp_limb *zp = RBIGINT_ARY(z); mp_dbl_limb c = 0; size_t i; - for (i=0; isz; i++) { - c += (mp_dbl_limb)y->p[i] + (mp_dbl_limb)x->p[i]; - z->p[i] = LOW(c); + for (i=0; i>= DIG_SIZE; } - for (;isz; i++) { - c += y->p[i]; - z->p[i] = LOW(c); + for (;i>= DIG_SIZE; } - z->p[y->sz] = (mp_limb)c; + zp[ysz] = (mp_limb)c; trim(z); } /* z = y - x, ignoring sign */ /* precondition: abs(y) >= abs(x) */ static void -usub(mrb_state *mrb, mpz_t *z, mpz_t *y, mpz_t *x) +usub(mrb_state *mrb, struct RBigint *z, struct RBigint *y, struct RBigint *x) { - mpz_realloc(mrb, z, (size_t)(y->sz)); + size_t xsz = RBIGINT_SIZE(x); + size_t ysz = RBIGINT_SIZE(y); + mpz_realloc(mrb, z, ysz); mp_dbl_limb_signed b = 0; + const mp_limb *xp = RBIGINT_ARY(x); + const mp_limb *yp = RBIGINT_ARY(y); + mp_limb *zp = RBIGINT_ARY(z); size_t i; - for (i=0;isz;i++) { - b += (mp_dbl_limb_signed)y->p[i]; - b -= (mp_dbl_limb_signed)x->p[i]; - z->p[i] = LOW(b); + for (i=0;isz; i++) { - b += y->p[i]; - z->p[i] = LOW(b); + for (;isz = digits(z); + RBIGINT_SET_SIZE(z, digits(z)); } /* compare abs(x) and abs(y) */ static int -ucmp(mpz_t *y, mpz_t *x) +ucmp(struct RBigint *y, struct RBigint *x) { - if (y->sz < x->sz) return -1; - if (y->sz > x->sz) return 1; - if (x->sz == 0) return 0; - for (size_t i=x->sz-1;; i--) { - mp_limb a = y->p[i]; - mp_limb b = x->p[i]; + size_t xsz = RBIGINT_SIZE(x); + size_t ysz = RBIGINT_SIZE(y); + if (ysz < xsz) return -1; + if (ysz > xsz) return 1; + if (xsz == 0) return 0; + const mp_limb *xp = RBIGINT_ARY(x); + const mp_limb *yp = RBIGINT_ARY(y); + for (size_t i=xsz-1;; i--) { + mp_limb a = yp[i]; + mp_limb b = xp[i]; if (a > b) return 1; if (a < b) return -1; if (i == 0) break; @@ -242,35 +302,42 @@ ucmp(mpz_t *y, mpz_t *x) return 0; } -#define zero_p(x) ((x)->sn == 0) +#define zero_p(x) (RBIGINT_SIGN(x) == 0) /* check if all digits are zero */ static int -uzero_p(mpz_t *x) +uzero_p(struct RBigint *x) { - if (x->sz == 0) return 1; - for (size_t i=0; i < x->sz; i++) - if (x->p[i] != 0) + size_t xsz = RBIGINT_SIZE(x); + if (xsz == 0) return 1; + const mp_limb *xp = RBIGINT_ARY(x); + for (size_t i=0; i < xsz; i++) + if (xp[i] != 0) return 0; return 1; } static void -zero(mpz_t *x) +zero(struct RBigint *x) { - x->sn=0; - if (x->p) { - x->sz=1; - x->p[0]=0; + RBIGINT_SET_SIGN(x, 0); + if (RBIGINT_EMBED_P(x)) { + for (size_t i = 0; i < RBIGINT_EMBED_SIZE_MAX; i++) { + x->as.ary[i] = 0; + } + } + else if (x->as.heap.p) { + RBIGINT_SET_HEAP_SIZE(x, 1); + RBIGINT_HEAP_ARY(x)[0]=0; } else { - x->sz=0; + RBIGINT_SET_HEAP_SIZE(x, 0); } } /* z = x + y */ static void -mpz_add(mrb_state *mrb, mpz_t *zz, mpz_t *x, mpz_t *y) +mpz_add(mrb_state *mrb, struct RBigint *zz, struct RBigint *x, struct RBigint *y) { if (zero_p(x)) { mpz_set(mrb, zz, y); @@ -280,16 +347,16 @@ mpz_add(mrb_state *mrb, mpz_t *zz, mpz_t *x, mpz_t *y) mpz_set(mrb, zz, x); return; } - mpz_t z; + struct RBigint z; mpz_init(mrb, &z); - if (x->sn > 0 && y->sn > 0) { + if (RBIGINT_SIGN(x) > 0 && RBIGINT_SIGN(y) > 0) { uadd(mrb, &z, x, y); - z.sn = 1; + RBIGINT_SET_SIGN(&z, 1); } - else if (x->sn < 0 && y->sn < 0) { + else if (RBIGINT_SIGN(x) < 0 && RBIGINT_SIGN(y) < 0) { uadd(mrb, &z, x, y); - z.sn = -1; + RBIGINT_SET_SIGN(&z, -1); } else { int mg; @@ -300,11 +367,11 @@ mpz_add(mrb_state *mrb, mpz_t *zz, mpz_t *x, mpz_t *y) } else if (mg > 0) { /* abs(y) < abs(x) */ usub(mrb, &z, x, y); - z.sn = (x->sn > 0 && y->sn < 0) ? 1 : (-1); + RBIGINT_SET_SIGN(&z, (RBIGINT_SIGN(x) > 0 && RBIGINT_SIGN(y) < 0) ? 1 : (-1)); } else { /* abs(y) > abs(x) */ usub(mrb, &z, y, x); - z.sn = (x->sn < 0 && y->sn > 0) ? 1 : (-1); + RBIGINT_SET_SIGN(&z, (RBIGINT_SIGN(x) < 0 && RBIGINT_SIGN(y) > 0) ? 1 : (-1)); } } trim(&z); @@ -313,9 +380,9 @@ mpz_add(mrb_state *mrb, mpz_t *zz, mpz_t *x, mpz_t *y) /* x = y - n */ static void -mpz_add_int(mrb_state *mrb, mpz_t *x, mpz_t *y, mrb_int n) +mpz_add_int(mrb_state *mrb, struct RBigint *x, struct RBigint *y, mrb_int n) { - mpz_t z; + struct RBigint z; mpz_init_set_int(mrb, &z, n); mpz_add(mrb, x, y, &z); @@ -324,22 +391,22 @@ mpz_add_int(mrb_state *mrb, mpz_t *x, mpz_t *y, mrb_int n) /* z = x - y -- just use mpz_add - I'm lazy */ static void -mpz_sub(mrb_state *mrb, mpz_t *z, mpz_t *x, mpz_t *y) +mpz_sub(mrb_state *mrb, struct RBigint *z, struct RBigint *x, struct RBigint *y) { - mpz_t u; + struct RBigint u; mpz_init(mrb, &u); mpz_set(mrb, &u, y); - u.sn = -(u.sn); + RBIGINT_SET_SIGN(&u, -(RBIGINT_SIGN(&u))); mpz_add(mrb, z, x, &u); mpz_clear(mrb, &u); } /* x = y - n */ static void -mpz_sub_int(mrb_state *mrb, mpz_t *x, mpz_t *y, mrb_int n) +mpz_sub_int(mrb_state *mrb, struct RBigint *x, struct RBigint *y, mrb_int n) { - mpz_t z; + struct RBigint z; mpz_init_set_int(mrb, &z, n); mpz_sub(mrb, x, y, &z); @@ -349,40 +416,44 @@ mpz_sub_int(mrb_state *mrb, mpz_t *x, mpz_t *y, mrb_int n) /* w = u * v */ /* Simple Multiply */ static void -mul_base(mrb_state *mrb, mpz_t *ww, mpz_t *u, mpz_t *v) +mul_base(mrb_state *mrb, struct RBigint *ww, struct RBigint *u, struct RBigint *v) { if (zero_p(u) || zero_p(v)) { mpz_set_int(mrb, ww, 0); return; } - mpz_t w; + size_t usz = RBIGINT_SIZE(u); + size_t vsz = RBIGINT_SIZE(v); + struct RBigint w; mpz_init(mrb, &w); - mpz_realloc(mrb, &w, u->sz + v->sz); + mpz_realloc(mrb, &w, usz + vsz); - for (size_t j = 0; j < u->sz; j++) { + const mp_limb *up = RBIGINT_ARY(u); + const mp_limb *vp = RBIGINT_ARY(v); + mp_limb *wp = RBIGINT_ARY(&w); + for (size_t j = 0; j < usz; j++) { size_t i; mp_dbl_limb cc = (mp_limb)0; - mp_limb u0 = u->p[j]; + mp_limb u0 = up[j]; if (u0 == 0) continue; - for (i = 0; i < v->sz; i++) { - mp_limb v0 = v->p[i]; + for (i = 0; i < vsz; i++) { + mp_limb v0 = vp[i]; if (v0 == 0) continue; - cc += (mp_dbl_limb)w.p[i + j] + (mp_dbl_limb)u0 * (mp_dbl_limb)v0; - w.p[i + j] = LOW(cc); + cc += (mp_dbl_limb)wp[i + j] + (mp_dbl_limb)u0 * (mp_dbl_limb)v0; + wp[i + j] = LOW(cc); cc = HIGH(cc); } if (cc) { - w.p[i + j] = (mp_limb)cc; + wp[i + j] = (mp_limb)cc; } } - - w.sn = u->sn * v->sn; + RBIGINT_SET_SIGN(&w, RBIGINT_SIGN(u) * RBIGINT_SIGN(v)); trim(&w); mpz_move(mrb, ww, &w); } -static void mpz_mul_2exp(mrb_state *mrb, mpz_t *z, mpz_t *x, mrb_int e); +static void mpz_mul_2exp(mrb_state *mrb, struct RBigint *z, struct RBigint *x, mrb_int e); /* Thresholds */ #define KARATSUBA_THRESHOLD 32 @@ -390,43 +461,46 @@ static void mpz_mul_2exp(mrb_state *mrb, mpz_t *z, mpz_t *x, mrb_int e); /* Karatsuba Multiply */ static void -mul_karatsuba(mrb_state *mrb, mpz_t *ww, mpz_t *u, mpz_t *v, int depth) +mul_karatsuba(mrb_state *mrb, struct RBigint *ww, struct RBigint *u, struct RBigint *v, int depth) { - if (depth > MAX_RECURSION_DEPTH || u->sz < KARATSUBA_THRESHOLD || v->sz < KARATSUBA_THRESHOLD) { + if (depth > MAX_RECURSION_DEPTH || RBIGINT_SIZE(u) < KARATSUBA_THRESHOLD || RBIGINT_SIZE(v) < KARATSUBA_THRESHOLD) { mul_base(mrb, ww, u, v); return; } - size_t n = (u->sz > v->sz ? v->sz : u->sz) / 2; + size_t n = (RBIGINT_SIZE(u) > RBIGINT_SIZE(v) ? RBIGINT_SIZE(v) : RBIGINT_SIZE(u)) / 2; /* Split u, v into low/high */ - mpz_t u0, u1, v0, v1; + struct RBigint u0, u1, v0, v1; mpz_init(mrb, &u0); mpz_init(mrb, &u1); mpz_init(mrb, &v0); mpz_init(mrb, &v1); - u0.sn = u1.sn = v0.sn = v1.sn = 1; + RBIGINT_SET_SIGN(&u0, 1); + RBIGINT_SET_SIGN(&u1, 1); + RBIGINT_SET_SIGN(&v0, 1); + RBIGINT_SET_SIGN(&v1, 1); mpz_realloc(mrb, &u0, n); - mpz_realloc(mrb, &u1, u->sz - n); + mpz_realloc(mrb, &u1, RBIGINT_SIZE(u) - n); mpz_realloc(mrb, &v0, n); - mpz_realloc(mrb, &v1, v->sz - n); + mpz_realloc(mrb, &v1, RBIGINT_SIZE(v) - n); - memcpy(u0.p, u->p, n * sizeof(mp_limb)); - memcpy(u1.p, u->p + n, (u->sz - n) * sizeof(mp_limb)); - memcpy(v0.p, v->p, n * sizeof(mp_limb)); - memcpy(v1.p, v->p + n, (v->sz - n) * sizeof(mp_limb)); + LIMB_COPY(RBIGINT_ARY(&u0), RBIGINT_ARY(u), n); + LIMB_COPY(RBIGINT_ARY(&u1), RBIGINT_ARY(u) + n, RBIGINT_SIZE(u) - n); + LIMB_COPY(RBIGINT_ARY(&v0), RBIGINT_ARY(v), n); + LIMB_COPY(RBIGINT_ARY(&v1), RBIGINT_ARY(v) + n, RBIGINT_SIZE(v) - n); /* u1*v1 (high part) */ - mpz_t z2; + struct RBigint z2; mpz_init(mrb, &z2); mul_karatsuba(mrb, &z2, &u1, &v1, depth + 1); /* u0*v0 (low part) */ - mpz_t z0; + struct RBigint z0; mpz_init(mrb, &z0); mul_karatsuba(mrb, &z0, &u0, &v0, depth + 1); /* (u1+u0)*(v1+v0) */ - mpz_t u0u1, v0v1, z1; + struct RBigint u0u1, v0v1, z1; mpz_init(mrb, &u0u1); mpz_init(mrb, &v0v1); mpz_init(mrb, &z1); mpz_add(mrb, &u0u1, &u0, &u1); @@ -452,21 +526,21 @@ mul_karatsuba(mrb_state *mrb, mpz_t *ww, mpz_t *u, mpz_t *v, int depth) // Multiplication Entry Point */ static void -mpz_mul(mrb_state *mrb, mpz_t *ww, mpz_t *u, mpz_t *v) +mpz_mul(mrb_state *mrb, struct RBigint *ww, struct RBigint *u, struct RBigint *v) { mul_karatsuba(mrb, ww, u, v, 0); - ww->sn = u->sn * v->sn; + RBIGINT_SET_SIGN(ww, RBIGINT_SIGN(u) * RBIGINT_SIGN(v)); } static void -mpz_mul_int(mrb_state *mrb, mpz_t *x, mpz_t *y, mrb_int n) +mpz_mul_int(mrb_state *mrb, struct RBigint *x, struct RBigint *y, mrb_int n) { if (n == 0) { zero(x); return; } - mpz_t z; + struct RBigint z; mpz_init_set_int(mrb, &z, n); mpz_mul(mrb, x, y, &z); mpz_clear(mrb, &z); @@ -494,7 +568,7 @@ lzb(mp_limb x) /* c1 = a>>n */ /* n must be < DIG_SIZE */ static void -urshift(mrb_state *mrb, mpz_t *c1, mpz_t *a, size_t n) +urshift(mrb_state *mrb, struct RBigint *c1, struct RBigint *a, size_t n) { mrb_assert(n < DIG_SIZE); @@ -504,15 +578,18 @@ urshift(mrb_state *mrb, mpz_t *c1, mpz_t *a, size_t n) mpz_set_int(mrb, c1, 0); } else { - mpz_t c; + struct RBigint c; mp_limb cc = 0; mp_dbl_limb rm = (((mp_dbl_limb)1<sz); - for (size_t i=a->sz-1;; i--) { - c.p[i] = ((a->p[i] >> n) | cc) & DIG_MASK; - cc = (a->p[i] & rm) << (DIG_SIZE - n); + mpz_realloc(mrb, &c, asz); + const mp_limb *ap = RBIGINT_ARY(a); + mp_limb *cp = RBIGINT_ARY(&c); + for (size_t i=asz-1;; i--) { + cp[i] = ((ap[i] >> n) | cc) & DIG_MASK; + cc = (ap[i] & rm) << (DIG_SIZE - n); if (i == 0) break; } trim(&c); @@ -523,7 +600,7 @@ urshift(mrb_state *mrb, mpz_t *c1, mpz_t *a, size_t n) /* c1 = a<sz+1); + mpz_realloc(mrb, &c, asz+1); + const mp_limb *ap = RBIGINT_ARY(a); + mp_limb *cp = RBIGINT_ARY(&c); size_t i; - for (i=0; isz; i++) { - c.p[i] = ((a->p[i] << n) | cc) & DIG_MASK; - cc = (a->p[i] & rm) >> (DIG_SIZE-n); + for (i=0; i> (DIG_SIZE-n); } - c.p[i] = cc; + cp[i] = cc; trim(&c); mpz_move(mrb, c1, &c); } @@ -553,7 +633,7 @@ ulshift(mrb_state *mrb, mpz_t *c1, mpz_t *a, size_t n) /* internal routine to compute x/y and x%y ignoring signs */ /* qq = xx/yy; rr = xx%yy */ static void -udiv(mrb_state *mrb, mpz_t *qq, mpz_t *rr, mpz_t *xx, mpz_t *yy) +udiv(mrb_state *mrb, struct RBigint *qq, struct RBigint *rr, struct RBigint *xx, struct RBigint *yy) { /* simple cases */ int cmp = ucmp(xx, yy); @@ -568,54 +648,59 @@ udiv(mrb_state *mrb, mpz_t *qq, mpz_t *rr, mpz_t *xx, mpz_t *yy) return; } - mpz_t q, x, y; + struct RBigint q, x, y; - mrb_assert(yy->sn != 0); /* divided by zero */ + mrb_assert(RBIGINT_SIGN(yy) != 0); /* divided by zero */ mpz_init(mrb, &q); mpz_init(mrb, &x); mpz_init(mrb, &y); - mpz_realloc(mrb, &x, xx->sz+1); + mpz_realloc(mrb, &x, RBIGINT_SIZE(xx)+1); size_t yd = digits(yy); - size_t ns = lzb(yy->p[yd-1]); + size_t ns = lzb(RBIGINT_ARY(yy)[yd-1]); ulshift(mrb, &x, xx, ns); ulshift(mrb, &y, yy, ns); size_t xd = digits(&x); mpz_realloc(mrb, &q, xd); - mp_dbl_limb z = y.p[yd-1]; + mp_dbl_limb z = RBIGINT_ARY(&y)[yd-1]; if (xd>=yd) { + mp_limb *xp = RBIGINT_ARY(&x); + const mp_limb *yp = RBIGINT_ARY(&y); + mp_limb *qp = RBIGINT_ARY(&q); for (size_t j=xd-yd;; j--) { mp_dbl_limb_signed b=0; mp_dbl_limb qhat; if (j+yd == xd) - qhat = x.p[j+yd-1] / z; + qhat = xp[j+yd-1] / z; else - qhat = (((mp_dbl_limb)x.p[j+yd] << DIG_SIZE) + x.p[j+yd-1]) / z; + qhat = (((mp_dbl_limb)xp[j+yd] << DIG_SIZE) + xp[j+yd-1]) / z; if (qhat) { size_t i; for (i=0; i i+j) { + b += xp[i+j]; + } } for (; b!=0; qhat--) { mp_dbl_limb c = 0; for (size_t i=0; isz; + RBIGINT_SET_SIZE(&x, RBIGINT_SIZE(yy)); urshift(mrb, rr, &x, ns); trim(&q); mpz_move(mrb, qq, &q); @@ -624,10 +709,10 @@ udiv(mrb_state *mrb, mpz_t *qq, mpz_t *rr, mpz_t *xx, mpz_t *yy) } static void -mpz_mdiv(mrb_state *mrb, mpz_t *q, mpz_t *x, mpz_t *y) +mpz_mdiv(mrb_state *mrb, struct RBigint *q, struct RBigint *x, struct RBigint *y) { - mpz_t r; - short sn1 = x->sn, sn2 = y->sn, qsign; + struct RBigint r; + short sn1 = RBIGINT_SIGN(x), sn2 = RBIGINT_SIGN(y), qsign; if (zero_p(x)) { mpz_init_set_int(mrb, q, 0); @@ -635,9 +720,9 @@ mpz_mdiv(mrb_state *mrb, mpz_t *q, mpz_t *x, mpz_t *y) } mpz_init(mrb, &r); udiv(mrb, q, &r, x, y); - qsign = q->sn = sn1*sn2; + RBIGINT_SET_SIGN(q, qsign = sn1*sn2); if (uzero_p(q)) - q->sn = 0; + RBIGINT_SET_SIGN(q, 0); /* now if r != 0 and q < 0 we need to round q towards -inf */ if (!uzero_p(&r) && qsign < 0) mpz_sub_int(mrb, q, q, 1); @@ -645,10 +730,10 @@ mpz_mdiv(mrb_state *mrb, mpz_t *q, mpz_t *x, mpz_t *y) } static void -mpz_mmod(mrb_state *mrb, mpz_t *r, mpz_t *x, mpz_t *y) +mpz_mmod(mrb_state *mrb, struct RBigint *r, struct RBigint *x, struct RBigint *y) { - mpz_t q; - short sn1 = x->sn, sn2 = y->sn, sn3; + struct RBigint q; + short sn1 = RBIGINT_SIGN(x), sn2 = RBIGINT_SIGN(y), sn3; mpz_init(mrb, &q); if (sn1 == 0) { @@ -658,26 +743,26 @@ mpz_mmod(mrb_state *mrb, mpz_t *r, mpz_t *x, mpz_t *y) udiv(mrb, &q, r, x, y); mpz_clear(mrb, &q); if (uzero_p(r)) { - r->sn = 0; + RBIGINT_SET_SIGN(r, 0); return; } sn3 = sn1*sn2; if (sn3 > 0) - r->sn = sn1; + RBIGINT_SET_SIGN(r, sn1); else if (sn1 < 0 && sn2 > 0) { - r->sn = 1; + RBIGINT_SET_SIGN(r, 1); mpz_sub(mrb, r, y, r); } else { - r->sn = 1; + RBIGINT_SET_SIGN(r, 1); mpz_add(mrb, r, y, r); } } static void -mpz_mdivmod(mrb_state *mrb, mpz_t *q, mpz_t *r, mpz_t *x, mpz_t *y) +mpz_mdivmod(mrb_state *mrb, struct RBigint *q, struct RBigint *r, struct RBigint *x, struct RBigint *y) { - short sn1 = x->sn, sn2 = y->sn, qsign; + short sn1 = RBIGINT_SIGN(x), sn2 = RBIGINT_SIGN(y), qsign; if (sn1 == 0) { zero(q); @@ -685,34 +770,34 @@ mpz_mdivmod(mrb_state *mrb, mpz_t *q, mpz_t *r, mpz_t *x, mpz_t *y) return; } udiv(mrb, q, r, x, y); - qsign = q->sn = sn1*sn2; + RBIGINT_SET_SIGN(q, qsign = sn1*sn2); if (uzero_p(r)) { /* q != 0, since q=r=0 would mean x=0, which was tested above */ - r->sn = 0; + RBIGINT_SET_SIGN(r, 0); return; } - if (q->sn > 0) - r->sn = sn1; + if (RBIGINT_SIGN(q) > 0) + RBIGINT_SET_SIGN(r, sn1); else if (sn1 < 0 && sn2 > 0) { - r->sn = 1; + RBIGINT_SET_SIGN(r, 1); mpz_sub(mrb, r, y, r); } else { - r->sn = 1; + RBIGINT_SET_SIGN(r, 1); mpz_add(mrb, r, y, r); } if (uzero_p(q)) - q->sn = 0; + RBIGINT_SET_SIGN(q, 0); /* now if r != 0 and q < 0 we need to round q towards -inf */ if (!uzero_p(r) && qsign < 0) mpz_sub_int(mrb, q, q, 1); } static void -mpz_mod(mrb_state *mrb, mpz_t *r, mpz_t *x, mpz_t *y) +mpz_mod(mrb_state *mrb, struct RBigint *r, struct RBigint *x, struct RBigint *y) { - mpz_t q; - short sn = x->sn; + struct RBigint q; + short sn = RBIGINT_SIGN(x); if (zero_p(x)) { zero(r); @@ -720,42 +805,42 @@ mpz_mod(mrb_state *mrb, mpz_t *r, mpz_t *x, mpz_t *y) } mpz_init(mrb, &q); udiv(mrb, &q, r, x, y); - r->sn = sn; + RBIGINT_SET_SIGN(r, sn); if (uzero_p(r)) - r->sn = 0; + RBIGINT_SET_SIGN(r, 0); mpz_clear(mrb, &q); } static mrb_int -mpz_cmp(mrb_state *mrb, mpz_t *x, mpz_t *y) +mpz_cmp(mrb_state *mrb, struct RBigint *x, struct RBigint *y) { - if (x->sn < 0 && y->sn > 0) + if (RBIGINT_SIGN(x) < 0 && RBIGINT_SIGN(y) > 0) return (-1); - if (x->sn > 0 && y->sn < 0) + if (RBIGINT_SIGN(x) > 0 && RBIGINT_SIGN(y) < 0) return 1; int abscmp=ucmp(x, y); - if (x->sn >=0 && y->sn >=0) + if (RBIGINT_SIGN(x) >=0 && RBIGINT_SIGN(y) >=0) return abscmp; - return (-abscmp); // if (x->sn <=0 && y->sn <=0) + return (-abscmp); // if (RBIGINT_SIGN(x) <=0 && RBIGINT_SIGN(y) <=0) } /* 2<=base<=36 - this overestimates the optimal value, which is OK */ static size_t -mpz_sizeinbase(mpz_t *x, mrb_int base) +mpz_sizeinbase(struct RBigint *x, mrb_int base) { size_t i, j; size_t bits = digits(x) * DIG_SIZE; mrb_assert(2 <= base && base <= 36); - if (zero_p(x) || x->sz == 0) return 0; + if (zero_p(x) || RBIGINT_SIZE(x) == 0) return 0; for (j=0,i=1; i<=(size_t)base; i*=2,j++) ; return bits/(j-1)+1; } static int -mpz_init_set_str(mrb_state *mrb, mpz_t *x, const char *s, mrb_int len, mrb_int base) +mpz_init_set_str(mrb_state *mrb, struct RBigint *x, const char *s, mrb_int len, mrb_int base) { int retval = 0; short sn; @@ -786,12 +871,12 @@ mpz_init_set_str(mrb_state *mrb, mpz_t *x, const char *s, mrb_int len, mrb_int b mpz_mul_int(mrb, x, x, base); mpz_add_int(mrb, x, x, k); } - x->sn = sn; + RBIGINT_SET_SIGN(x, sn); return retval; } static char* -mpz_get_str(mrb_state *mrb, char *s, mrb_int sz, mrb_int base, mpz_t *x) +mpz_get_str(mrb_state *mrb, char *s, mrb_int sz, mrb_int base, struct RBigint *x) { mrb_assert(2 <= base && base <= 36); if (zero_p(x)) { @@ -811,8 +896,9 @@ mpz_get_str(mrb_state *mrb, char *s, mrb_int sz, mrb_int base, mpz_t *x) mp_dbl_limb value = 0; int bits = 0; + const mp_limb *xp = RBIGINT_ARY(x); for (int i = 0; i < xlen; i++) { - value |= (mp_dbl_limb)x->p[i] << bits; + value |= (mp_dbl_limb)xp[i] << bits; bits += DIG_SIZE; while (bits >= shift) { mp_limb digit = value & mask; @@ -827,7 +913,7 @@ mpz_get_str(mrb_state *mrb, char *s, mrb_int sz, mrb_int base, mpz_t *x) else { mp_limb *t = (mp_limb*)mrb_malloc(mrb, xlen*sizeof(mp_limb)); mp_limb *tend = t + xlen; - memcpy(t, x->p, xlen*sizeof(mp_limb)); + memcpy(t, RBIGINT_ARY(x), xlen*sizeof(mp_limb)); mp_limb b2 = (mp_limb)base; const int blim = (sizeof(mp_limb)<4)?(base<=10?4:3):(base<=10?9:5); for (int i=1; isn < 0) { + if (RBIGINT_SIGN(x) < 0) { *s++ = '-'; } @@ -879,7 +965,7 @@ mpz_get_str(mrb_state *mrb, char *s, mrb_int sz, mrb_int base, mpz_t *x) } static int -mpz_get_int(mpz_t *y, mrb_int *v) +mpz_get_int(struct RBigint *y, mrb_int *v) { if (zero_p(y)) { *v = 0; @@ -887,9 +973,11 @@ mpz_get_int(mpz_t *y, mrb_int *v) } mp_dbl_limb i = 0; - mp_limb *d = y->p + y->sz; + size_t ysz = RBIGINT_SIZE(y); + const mp_limb *yp = RBIGINT_ARY(y); + const mp_limb *d = yp + ysz; - while (d-- > y->p) { + while (d-- > yp) { if (HIGH(i) != 0) { /* will overflow */ return FALSE; @@ -900,7 +988,7 @@ mpz_get_int(mpz_t *y, mrb_int *v) /* overflow */ return FALSE; } - if (y->sn < 0) { + if (RBIGINT_SIGN(y) < 0) { *v = -(mrb_int)i; } else { @@ -910,20 +998,23 @@ mpz_get_int(mpz_t *y, mrb_int *v) } static void -mpz_mul_2exp(mrb_state *mrb, mpz_t *z, mpz_t *x, mrb_int e) +mpz_mul_2exp(mrb_state *mrb, struct RBigint *z, struct RBigint *x, mrb_int e) { if (e==0) mpz_set(mrb, z, x); else { - short sn = x->sn; + short sn = RBIGINT_SIGN(x); size_t digs = e / DIG_SIZE; size_t bs = e % DIG_SIZE; - mpz_t y; + size_t xsz = RBIGINT_SIZE(x); + struct RBigint y; mpz_init(mrb, &y); - mpz_realloc(mrb, &y, x->sz+digs); - for (size_t i=0;isz;i++) - y.p[i+digs] = x->p[i]; + mpz_realloc(mrb, &y, xsz+digs); + const mp_limb *xp = RBIGINT_ARY(x); + mp_limb *yp = RBIGINT_ARY(&y); + for (size_t i=0;isn = sn; + RBIGINT_SET_SIGN(z, sn); } } static void -mpz_div_2exp(mrb_state *mrb, mpz_t *z, mpz_t *x, mrb_int e) +mpz_div_2exp(mrb_state *mrb, struct RBigint *z, struct RBigint *x, mrb_int e) { - short sn = x->sn; + short sn = RBIGINT_SIGN(x); if (e==0) mpz_set(mrb, z, x); else { size_t digs = e / DIG_SIZE; size_t bs = e % DIG_SIZE; - mpz_t y; + size_t xsz = RBIGINT_SIZE(x); + struct RBigint y; mpz_init(mrb, &y); - mpz_realloc(mrb, &y, x->sz-digs); - for (size_t i=0; i < x->sz-digs; i++) - y.p[i] = x->p[i+digs]; + mpz_realloc(mrb, &y, xsz-digs); + const mp_limb *xp = RBIGINT_ARY(x); + mp_limb *yp = RBIGINT_ARY(&y); + for (size_t i=0; i < xsz-digs; i++) + yp[i] = xp[i+digs]; if (bs) { urshift(mrb, z, &y, bs); mpz_clear(mrb, &y); @@ -958,50 +1052,58 @@ mpz_div_2exp(mrb_state *mrb, mpz_t *z, mpz_t *x, mrb_int e) mpz_move(mrb, z, &y); } if (uzero_p(z)) - z->sn = 0; + RBIGINT_SET_SIGN(z, 0); else { - z->sn = sn; + RBIGINT_SET_SIGN(z, sn); } } } static void -mpz_neg(mrb_state *mrb, mpz_t *x, mpz_t *y) +mpz_neg(mrb_state *mrb, struct RBigint *x, struct RBigint *y) { mpz_set(mrb, x, y); - x->sn = -(y->sn); + RBIGINT_SET_SIGN(x, -RBIGINT_SIGN(y)); } #define make_2comp(v,c) do { v=~(v)+(c); c=((v)==0 && (c));} while (0) void -mpz_and(mrb_state *mrb, mpz_t *z, mpz_t *x, mpz_t *y) +mpz_and(mrb_state *mrb, struct RBigint *z, struct RBigint *x, struct RBigint *y) { if (zero_p(x) || zero_p(y)) { zero(z); return; } - mrb_assert(x->sz > 0 || y->sz > 0); + size_t xsz = RBIGINT_SIZE(x); + size_t ysz = RBIGINT_SIZE(y); + mrb_assert(xsz > 0 || ysz > 0); - size_t max_sz = (x->sz > y->sz) ? x->sz : y->sz; + size_t max_sz = (xsz > ysz) ? xsz : ysz; mpz_realloc(mrb, z, max_sz); - z->sn = (x->sn == y->sn) ? x->sn : 1; + RBIGINT_SET_SIGN(z, (RBIGINT_SIGN(x) == RBIGINT_SIGN(y)) ? RBIGINT_SIGN(x) : 1); + const mp_limb *xp = RBIGINT_ARY(x); + const mp_limb *yp = RBIGINT_ARY(y); + mp_limb *zp = RBIGINT_ARY(z); + mrb_bool xneg = RBIGINT_SIGN(x) < 0; + mrb_bool yneg = RBIGINT_SIGN(y) < 0; + mrb_bool zneg = RBIGINT_SIGN(z) < 0; char c1 = 1, c2 = 1, c3 = 1; for (size_t i = 0; i < max_sz; i++) { - mp_limb xv = (i < x->sz) ? x->p[i] : 0; - mp_limb yv = (i < y->sz) ? y->p[i] : 0; + mp_limb xv = (i < xsz) ? xp[i] : 0; + mp_limb yv = (i < ysz) ? yp[i] : 0; - if (x->sn < 0) make_2comp(xv, c1); - if (y->sn < 0) make_2comp(yv, c2); + if (xneg) make_2comp(xv, c1); + if (yneg) make_2comp(yv, c2); mp_limb zv = xv & yv; - if (z->sn < 0) make_2comp(zv, c3); - z->p[i] = zv; + if (zneg) make_2comp(zv, c3); + zp[i] = zv; } } static void -mpz_or(mrb_state *mrb, mpz_t *z, mpz_t *x, mpz_t *y) /* not the most efficient way to do this */ +mpz_or(mrb_state *mrb, struct RBigint *z, struct RBigint *x, struct RBigint *y) /* not the most efficient way to do this */ { if (zero_p(x)) { mpz_set(mrb, z, y); @@ -1011,27 +1113,35 @@ mpz_or(mrb_state *mrb, mpz_t *z, mpz_t *x, mpz_t *y) /* not the most efficient mpz_set(mrb, z, x); return; } - mrb_assert(x->sz > 0 || y->sz > 0); + size_t xsz = RBIGINT_SIZE(x); + size_t ysz = RBIGINT_SIZE(y); + mrb_assert(xsz > 0 || ysz > 0); - size_t max_sz = (x->sz > y->sz) ? x->sz : y->sz; + size_t max_sz = (xsz > ysz) ? xsz : ysz; mpz_realloc(mrb, z, max_sz); - z->sn = (x->sn == y->sn) ? x->sn : -1; + RBIGINT_SET_SIGN(z, (RBIGINT_SIGN(x) == RBIGINT_SIGN(y)) ? RBIGINT_SIGN(x) : -1); + const mp_limb *xp = RBIGINT_ARY(x); + const mp_limb *yp = RBIGINT_ARY(y); + mp_limb *zp = RBIGINT_ARY(z); + mrb_bool xneg = RBIGINT_SIGN(x) < 0; + mrb_bool yneg = RBIGINT_SIGN(y) < 0; + mrb_bool zneg = RBIGINT_SIGN(z) < 0; char c1 = 1, c2 = 1, c3 = 1; for (size_t i = 0; i < max_sz; i++) { - mp_limb xv = (i < x->sz) ? x->p[i] : 0; - mp_limb yv = (i < y->sz) ? y->p[i] : 0; + mp_limb xv = (i < xsz) ? xp[i] : 0; + mp_limb yv = (i < ysz) ? yp[i] : 0; - if (x->sn < 0) make_2comp(xv, c1); - if (y->sn < 0) make_2comp(yv, c2); + if (xneg) make_2comp(xv, c1); + if (yneg) make_2comp(yv, c2); mp_limb zv = xv | yv; - if (z->sn < 0) make_2comp(zv, c3); - z->p[i] = zv; + if (zneg) make_2comp(zv, c3); + zp[i] = zv; } } static void -mpz_xor(mrb_state *mrb, mpz_t *z, mpz_t *x, mpz_t *y) /* not the most efficient way to do this */ +mpz_xor(mrb_state *mrb, struct RBigint *z, struct RBigint *x, struct RBigint *y) /* not the most efficient way to do this */ { if (zero_p(x)) { mpz_set(mrb, z, y); @@ -1041,29 +1151,37 @@ mpz_xor(mrb_state *mrb, mpz_t *z, mpz_t *x, mpz_t *y) /* not the most efficient mpz_set(mrb, z, x); return; } - mrb_assert(x->sz > 0 || y->sz > 0); + size_t xsz = RBIGINT_SIZE(x); + size_t ysz = RBIGINT_SIZE(y); + mrb_assert(xsz > 0 || ysz > 0); - size_t max_sz = (x->sz > y->sz) ? x->sz : y->sz; + size_t max_sz = (xsz > ysz) ? xsz : ysz; mpz_realloc(mrb, z, max_sz); - z->sn = (x->sn == y->sn) ? 1 : -1; + RBIGINT_SET_SIGN(z, (RBIGINT_SIGN(x) == RBIGINT_SIGN(y)) ? 1 : -1); + const mp_limb *xp = RBIGINT_ARY(x); + const mp_limb *yp = RBIGINT_ARY(y); + mp_limb *zp = RBIGINT_ARY(z); + mrb_bool xneg = RBIGINT_SIGN(x) < 0; + mrb_bool yneg = RBIGINT_SIGN(y) < 0; + mrb_bool zneg = RBIGINT_SIGN(z) < 0; char c1 = 1, c2 = 1, c3 = 1; for (size_t i = 0; i < max_sz; i++) { - mp_limb xv = (i < x->sz) ? x->p[i] : 0; - mp_limb yv = (i < y->sz) ? y->p[i] : 0; + mp_limb xv = (i < xsz) ? xp[i] : 0; + mp_limb yv = (i < ysz) ? yp[i] : 0; - if (x->sn < 0) make_2comp(xv, c1); - if (y->sn < 0) make_2comp(yv, c2); + if (xneg) make_2comp(xv, c1); + if (yneg) make_2comp(yv, c2); mp_limb zv = xv ^ yv; - if (z->sn < 0) make_2comp(zv, c3); - z->p[i] = zv; + if (zneg) make_2comp(zv, c3); + zp[i] = zv; } } static void -mpz_pow(mrb_state *mrb, mpz_t *zz, mpz_t *x, mrb_int e) +mpz_pow(mrb_state *mrb, struct RBigint *zz, struct RBigint *x, mrb_int e) { - mpz_t t; + struct RBigint t; mrb_uint mask = 1ULL<<(sizeof(mrb_int)*8-1); if (e==0) { @@ -1085,24 +1203,24 @@ mpz_pow(mrb_state *mrb, mpz_t *zz, mpz_t *x, mrb_int e) } static void -mpz_powm(mrb_state *mrb, mpz_t *zz, mpz_t *x, mpz_t *ex, mpz_t *n) +mpz_powm(mrb_state *mrb, struct RBigint *zz, struct RBigint *x, struct RBigint *ex, struct RBigint *n) { if (zero_p(ex)) { mpz_set_int(mrb, zz, 1); return; } - if (ex->sn < 0) { + if (RBIGINT_SIGN(ex) < 0) { return; } - mpz_t t, b; + struct RBigint t, b; mpz_init_set_int(mrb, &t, 1); mpz_init_set(mrb, &b, x); size_t len = digits(ex); for (size_t i=0; ip[i]; + mp_limb e = RBIGINT_ARY(ex)[i]; for (size_t j=0; jsn == 0) - x->sn = 0; + if (RBIGINT_SIGN(y) == 0) + RBIGINT_SET_SIGN(x, 0); else - x->sn = 1; + RBIGINT_SET_SIGN(x, 1); } static void -mpz_gcd(mrb_state *mrb, mpz_t *gg, mpz_t *aa, mpz_t *bb) +mpz_gcd(mrb_state *mrb, struct RBigint *gg, struct RBigint *aa, struct RBigint *bb) { - mpz_t a, b, t; + struct RBigint a, b, t; mpz_abs(mrb, &a, aa); mpz_abs(mrb, &b, bb); mpz_init(mrb, &t); - while (b.sn != 0) { + while (RBIGINT_SIGN(&b) != 0) { mpz_mod(mrb, &t, &a, &b); mpz_set(mrb, &a, &b); mpz_set(mrb, &b, &t); @@ -1181,7 +1299,7 @@ static struct RBigint* bint_new(mrb_state *mrb) { struct RBigint *b = MRB_OBJ_ALLOC(mrb, MRB_TT_BIGINT, mrb->integer_class); - mpz_init(mrb, &b->mp); + mpz_init(mrb, b); return b; } @@ -1189,7 +1307,7 @@ static struct RBigint* bint_new_int(mrb_state *mrb, mrb_int x) { struct RBigint *b = MRB_OBJ_ALLOC(mrb, MRB_TT_BIGINT, mrb->integer_class); - mpz_init_set_int(mrb, &b->mp, x); + mpz_init_set_int(mrb, b, x); return b; } @@ -1205,8 +1323,8 @@ mrb_value mrb_bint_new_int64(mrb_state *mrb, int64_t x) { struct RBigint *b = bint_new(mrb); - mpz_init(mrb, &b->mp); - mpz_set_int64(mrb, &b->mp, x); + mpz_init(mrb, b); + mpz_set_int64(mrb, b, x); return mrb_obj_value(b); } #endif @@ -1215,8 +1333,8 @@ mrb_value mrb_bint_new_uint64(mrb_state *mrb, uint64_t x) { struct RBigint *b = bint_new(mrb); - mpz_init(mrb, &b->mp); - mpz_set_uint64(mrb, &b->mp, x); + mpz_init(mrb, b); + mpz_set_uint64(mrb, b, x); return mrb_obj_value(b); } @@ -1230,9 +1348,9 @@ mrb_bint_new_str(mrb_state *mrb, const char *x, mrb_int len, mrb_int base) sn = -1; } mrb_assert(2 <= base && base <= 36); - mpz_init_set_str(mrb, &b->mp, x, len, base); + mpz_init_set_str(mrb, b, x, len, base); if (sn < 0) { - b->mp.sn = sn; + RBIGINT_SET_SIGN(b, sn); } return mrb_obj_value(b); } @@ -1242,7 +1360,7 @@ bint_norm(mrb_state *mrb, struct RBigint *b) { mrb_int i; - if (mpz_get_int(&b->mp, &i)) { + if (mpz_get_int(b, &i)) { return mrb_int_value(mrb, i); } return mrb_obj_value(b); @@ -1252,7 +1370,7 @@ void mrb_gc_free_bint(mrb_state *mrb, struct RBasic *x) { struct RBigint *b = (struct RBigint*)x; - mpz_clear(mrb, &b->mp); + mpz_clear(mrb, b); } #ifndef MRB_NO_FLOAT @@ -1279,8 +1397,8 @@ mrb_bint_new_float(mrb_state *mrb, mrb_float x) } struct RBigint *bint = bint_new(mrb); - mpz_t *r = &bint->mp; - r->sn = sn; + struct RBigint *r = bint; + RBIGINT_SET_SIGN(r, sn); mrb_float b = (double)DIG_BASE; mrb_float bi = 1.0 / b; @@ -1291,7 +1409,7 @@ mrb_bint_new_float(mrb_state *mrb, mrb_float x) x *= bi; mpz_realloc(mrb, r, rn); - rp = r->p; + rp = RBIGINT_ARY(r); for (size_t i=rn-1;;i--) { mp_limb f = LOW((mp_limb)x); x -= f; @@ -1306,15 +1424,15 @@ mrb_float mrb_bint_as_float(mrb_state *mrb, mrb_value self) { struct RBigint *b = RBIGINT(self); - mpz_t *i = &b->mp; - mp_limb *d = i->p + i->sz; + struct RBigint *i = b; + mp_limb *d = RBIGINT_ARY(i) + RBIGINT_SIZE(i); mrb_float val = 0; - while (d-- > i->p) { + while (d-- > RBIGINT_ARY(i)) { val = val * DIG_BASE + *d; } - if (i->sn < 0) { + if (RBIGINT_SIGN(i) < 0) { val = -val; } return val; @@ -1334,7 +1452,7 @@ mrb_bint_as_int(mrb_state *mrb, mrb_value x) struct RBigint *b = RBIGINT(x); mrb_int i; - if (!mpz_get_int(&b->mp, &i)) { + if (!mpz_get_int(b, &i)) { mrb_raise(mrb, E_RANGE_ERROR, "integer out of range"); } return i; @@ -1345,7 +1463,7 @@ int64_t mrb_bint_as_int64(mrb_state *mrb, mrb_value x) { struct RBigint *b = RBIGINT(x); - mpz_t *m = &b->mp; + struct RBigint *m = b; uint64_t u = 0; size_t len = digits(m); @@ -1355,11 +1473,11 @@ mrb_bint_as_int64(mrb_state *mrb, mrb_value x) } for (size_t i=len-1; ; i--) { u <<= DIG_SIZE; - u |= m->p[i]; + u |= RBIGINT_ARY(m)[i]; if (i==0) break; } if (u > INT64_MAX) goto out_of_range; - if (m->sn < 0) return -(int64_t)u; + if (RBIGINT_SIGN(m) < 0) return -(int64_t)u; return (int64_t)u; } #endif @@ -1368,16 +1486,16 @@ uint64_t mrb_bint_as_uint64(mrb_state *mrb, mrb_value x) { struct RBigint *b = RBIGINT(x); - mpz_t *m = &b->mp; + struct RBigint *m = b; uint64_t u = 0; size_t len = digits(m); - if (m->sn < 0 || len*sizeof(mp_limb) > sizeof(uint64_t)) { + if (RBIGINT_SIGN(m) < 0 || len*sizeof(mp_limb) > sizeof(uint64_t)) { mrb_raise(mrb, E_RANGE_ERROR, "integer out of range"); } for (size_t i=len-1; ; i--) { u <<= DIG_SIZE; - u |= m->p[i]; + u |= RBIGINT_ARY(m)[i]; if (i==0) break; } return u; @@ -1391,7 +1509,7 @@ mrb_bint_add_n(mrb_state *mrb, mrb_value x, mrb_value y) struct RBigint *b = RBIGINT(x); struct RBigint *b2 = RBIGINT(y); struct RBigint *b3 = bint_new(mrb); - mpz_add(mrb, &b3->mp, &b->mp, &b2->mp); + mpz_add(mrb, b3, b, b2); return mrb_obj_value(b3); } @@ -1417,7 +1535,7 @@ mrb_bint_sub_n(mrb_state *mrb, mrb_value x, mrb_value y) struct RBigint *b = RBIGINT(x); struct RBigint *b2 = RBIGINT(y); struct RBigint *b3 = bint_new(mrb); - mpz_sub(mrb, &b3->mp, &b->mp, &b2->mp); + mpz_sub(mrb, b3, b, b2); return mrb_obj_value(b3); } @@ -1442,7 +1560,7 @@ bint_mul(mrb_state *mrb, mrb_value x, mrb_value y) struct RBigint *b = RBIGINT(x); struct RBigint *b2 = RBIGINT(y); struct RBigint *b3 = bint_new(mrb); - mpz_mul(mrb, &b3->mp, &b->mp, &b2->mp); + mpz_mul(mrb, b3, b, b2); return b3; } @@ -1488,10 +1606,10 @@ mrb_bint_div(mrb_state *mrb, mrb_value x, mrb_value y) struct RBigint *b = RBIGINT(x); struct RBigint *b2 = RBIGINT(y); struct RBigint *b3 = bint_new(mrb); - if (zero_p(&b2->mp)) { + if (zero_p(b2)) { mrb_int_zerodiv(mrb); } - mpz_mdiv(mrb, &b3->mp, &b->mp, &b2->mp); + mpz_mdiv(mrb, b3, b, b2); return bint_norm(mrb, b3); } @@ -1499,11 +1617,11 @@ mrb_value mrb_bint_add_ii(mrb_state *mrb, mrb_int x, mrb_int y) { struct RBigint *b = bint_new(mrb); - mpz_t z1, z2; + struct RBigint z1, z2; mpz_init_set_int(mrb, &z1, x); mpz_init_set_int(mrb, &z2, y); - mpz_add(mrb, &b->mp, &z1, &z2); + mpz_add(mrb, b, &z1, &z2); mpz_clear(mrb, &z1); mpz_clear(mrb, &z2); return bint_norm(mrb, b); @@ -1513,11 +1631,11 @@ mrb_value mrb_bint_sub_ii(mrb_state *mrb, mrb_int x, mrb_int y) { struct RBigint *b = bint_new(mrb); - mpz_t z1, z2; + struct RBigint z1, z2; mpz_init_set_int(mrb, &z1, x); mpz_init_set_int(mrb, &z2, y); - mpz_sub(mrb, &b->mp, &z1, &z2); + mpz_sub(mrb, b, &z1, &z2); mpz_clear(mrb, &z1); mpz_clear(mrb, &z2); return bint_norm(mrb, b); @@ -1527,11 +1645,11 @@ mrb_value mrb_bint_mul_ii(mrb_state *mrb, mrb_int x, mrb_int y) { struct RBigint *b = bint_new(mrb); - mpz_t z1, z2; + struct RBigint z1, z2; mpz_init_set_int(mrb, &z1, x); mpz_init_set_int(mrb, &z2, y); - mpz_mul(mrb, &b->mp, &z1, &z2); + mpz_mul(mrb, b, &z1, &z2); mpz_clear(mrb, &z1); mpz_clear(mrb, &z2); return bint_norm(mrb, b); @@ -1554,10 +1672,10 @@ mrb_bint_mod(mrb_state *mrb, mrb_value x, mrb_value y) struct RBigint *b = RBIGINT(x); struct RBigint *b2 = RBIGINT(y); struct RBigint *b3 = bint_new(mrb); - if (zero_p(&b2->mp)) { + if (zero_p(b2)) { mrb_int_zerodiv(mrb); } - mpz_mmod(mrb, &b3->mp, &b->mp, &b2->mp); + mpz_mmod(mrb, b3, b, b2); return bint_norm(mrb, b3); } @@ -1573,10 +1691,10 @@ mrb_bint_rem(mrb_state *mrb, mrb_value x, mrb_value y) struct RBigint *b = RBIGINT(x); struct RBigint *b2 = RBIGINT(y); struct RBigint *b3 = bint_new(mrb); - if (zero_p(&b2->mp)) { + if (zero_p(b2)) { mrb_int_zerodiv(mrb); } - mpz_mod(mrb, &b3->mp, &b->mp, &b2->mp); + mpz_mod(mrb, b3, b, b2); return bint_norm(mrb, b3); } @@ -1593,10 +1711,10 @@ mrb_bint_divmod(mrb_state *mrb, mrb_value x, mrb_value y) struct RBigint *b2 = RBIGINT(y); struct RBigint *b3 = bint_new(mrb); struct RBigint *b4 = bint_new(mrb); - if (zero_p(&b2->mp)) { + if (zero_p(b2)) { mrb_int_zerodiv(mrb); } - mpz_mdivmod(mrb, &b3->mp, &b4->mp, &b->mp, &b2->mp); + mpz_mdivmod(mrb, b3, b4, b, b2); x = bint_norm(mrb, b3); y = bint_norm(mrb, b4); return mrb_assoc_new(mrb, x, y); @@ -1619,16 +1737,16 @@ mrb_bint_cmp(mrb_state *mrb, mrb_value x, mrb_value y) if (!mrb_integer_p(y)) return -2; /* type mismatch */ mrb_int i1, i2 = mrb_integer(y); - if (mpz_get_int(&b->mp, &i1)) { + if (mpz_get_int(b, &i1)) { if (i1 == i2) return 0; if (i1 > i2) return 1; return -1; } - if (b->mp.sn > 0) return 1; + if (RBIGINT_SIGN(b) > 0) return 1; return -1; } struct RBigint *b2 = RBIGINT(y); - return mpz_cmp(mrb, &b->mp, &b2->mp); + return mpz_cmp(mrb, b, b2); } mrb_value @@ -1639,7 +1757,7 @@ mrb_bint_pow(mrb_state *mrb, mrb_value x, mrb_value y) case MRB_TT_INTEGER: { struct RBigint *b3 = bint_new(mrb); - mpz_pow(mrb, &b3->mp, &b->mp, mrb_integer(y)); + mpz_pow(mrb, b3, b, mrb_integer(y)); return mrb_obj_value(b3); } case MRB_TT_BIGINT: @@ -1658,7 +1776,7 @@ mrb_bint_powm(mrb_state *mrb, mrb_value x, mrb_value exp, mrb_value mod) if (mrb_bigint_p(mod)) { b2 = RBIGINT(mod); - if (zero_p(&b2->mp)) mrb_int_zerodiv(mrb); + if (zero_p(b2)) mrb_int_zerodiv(mrb); } else { mrb_int m = mrb_integer(mod); @@ -1668,17 +1786,17 @@ mrb_bint_powm(mrb_state *mrb, mrb_value x, mrb_value exp, mrb_value mod) b3 = bint_new(mrb); if (mrb_bigint_p(exp)) { struct RBigint *be = RBIGINT(exp); - if (be->mp.sn < 0) { + if (RBIGINT_SIGN(be) < 0) { mrb_raise(mrb, E_ARGUMENT_ERROR, "int.pow(n,m): n must be positive"); } - mpz_powm(mrb, &b3->mp, &b->mp, &be->mp, &b2->mp); + mpz_powm(mrb, b3, b, be, b2); } else { mrb_int e = mrb_integer(exp); if (e < 0) { mrb_raise(mrb, E_ARGUMENT_ERROR, "int.pow(n,m): n must be positive"); } - mpz_powm_i(mrb, &b3->mp, &b->mp, e, &b2->mp); + mpz_powm_i(mrb, b3, b, e, b2); } return bint_norm(mrb, b3); } @@ -1688,15 +1806,15 @@ mrb_bint_to_s(mrb_state *mrb, mrb_value x, mrb_int base) { struct RBigint *b = RBIGINT(x); - if (zero_p(&b->mp) || b->mp.sz == 0) + if (zero_p(b) || RBIGINT_SIZE(b) == 0) return mrb_str_new_lit(mrb, "0"); - size_t len = mpz_sizeinbase(&b->mp, (int)base); + size_t len = mpz_sizeinbase(b, (int)base); if (MRB_INT_MAX-2 < len) { mrb_raise(mrb, E_ARGUMENT_ERROR, "too long string from Integer"); } mrb_value str = mrb_str_new(mrb, NULL, len+2); - mpz_get_str(mrb, RSTRING_PTR(str), len, base, &b->mp); + mpz_get_str(mrb, RSTRING_PTR(str), len, base, b); RSTR_SET_LEN(RSTRING(str), strlen(RSTRING_PTR(str))); return str; } @@ -1710,21 +1828,21 @@ mrb_bint_and(mrb_state *mrb, mrb_value x, mrb_value y) mrb_int z = mrb_integer(y); if (z == 0) return mrb_fixnum_value(0); if (z > 0 && (mp_dbl_limb)z < DIG_BASE) { - z &= b1->mp.p[0]; + z &= RBIGINT_ARY(b1)[0]; return mrb_int_value(mrb, z); } if (z == -1) return x; if (z < 0 && (mp_dbl_limb)-z < DIG_BASE) { struct RBigint *b3 = bint_new(mrb); - mpz_set(mrb, &b3->mp, &b1->mp); - b3->mp.p[0] &= (mp_limb)z; + mpz_set(mrb, b3, b1); + RBIGINT_ARY(b3)[0] &= (mp_limb)z; return bint_norm(mrb, b3); } } y = mrb_as_bint(mrb, y); struct RBigint *b2 = RBIGINT(y); struct RBigint *b3 = bint_new(mrb); - mpz_and(mrb, &b3->mp, &b1->mp, &b2->mp); + mpz_and(mrb, b3, b1, b2); return bint_norm(mrb, b3); } @@ -1738,13 +1856,13 @@ mrb_bint_or(mrb_state *mrb, mrb_value x, mrb_value y) if (z == 0) return x; if (z == -1) return y; if (z > 0 && (mp_dbl_limb)z < DIG_BASE) { - z |= b1->mp.p[0]; + z |= RBIGINT_ARY(b1)[0]; return mrb_int_value(mrb, z); } if (z < 0 && (mp_dbl_limb)-z < DIG_BASE) { struct RBigint *b3 = bint_new(mrb); - mpz_set(mrb, &b3->mp, &b1->mp); - b3->mp.p[0] |= (mp_limb)z; + mpz_set(mrb, b3, b1); + RBIGINT_ARY(b3)[0] |= (mp_limb)z; return bint_norm(mrb, b3); } } @@ -1752,7 +1870,7 @@ mrb_bint_or(mrb_state *mrb, mrb_value x, mrb_value y) y = mrb_as_bint(mrb, y); struct RBigint *b2 = RBIGINT(y); struct RBigint *b3 = bint_new(mrb); - mpz_or(mrb, &b3->mp, &b1->mp, &b2->mp); + mpz_or(mrb, b3, b1, b2); return bint_norm(mrb, b3); } @@ -1762,7 +1880,7 @@ mrb_bint_neg(mrb_state *mrb, mrb_value x) struct RBigint *b1 = RBIGINT(x); struct RBigint *b2 = bint_new(mrb); - mpz_neg(mrb, &b2->mp, &b1->mp); + mpz_neg(mrb, b2, b1); /* no normalization */ return mrb_obj_value(b2); } @@ -1777,14 +1895,14 @@ mrb_bint_xor(mrb_state *mrb, mrb_value x, mrb_value y) if (z == 0) return x; // if (z == -1) return ; if (0 < z && (mp_dbl_limb)z < DIG_BASE) { - z ^= b1->mp.p[0]; + z ^= RBIGINT_ARY(b1)[0]; return mrb_int_value(mrb, z); } } y = mrb_as_bint(mrb, y); struct RBigint *b2 = RBIGINT(y); struct RBigint *b3 = bint_new(mrb); - mpz_xor(mrb, &b3->mp, &b1->mp, &b2->mp); + mpz_xor(mrb, b3, b1, b2); return bint_norm(mrb, b3); } @@ -1794,8 +1912,8 @@ mrb_bint_rev(mrb_state *mrb, mrb_value x) struct RBigint *b1 = RBIGINT(x); struct RBigint *b2 = bint_new(mrb); - mpz_neg(mrb, &b2->mp, &b1->mp); - mpz_sub_int(mrb, &b2->mp, &b2->mp, 1); + mpz_neg(mrb, b2, b1); + mpz_sub_int(mrb, b2, b2, 1); return bint_norm(mrb, b2); } @@ -1805,10 +1923,10 @@ mrb_bint_lshift(mrb_state *mrb, mrb_value x, mrb_int width) struct RBigint *b = RBIGINT(x); struct RBigint *b2 = bint_new(mrb); if (width < 0) { - mpz_div_2exp(mrb, &b2->mp, &b->mp, -width); + mpz_div_2exp(mrb, b2, b, -width); } else { - mpz_mul_2exp(mrb, &b2->mp, &b->mp, width); + mpz_mul_2exp(mrb, b2, b, width); } return bint_norm(mrb, b2); } @@ -1819,10 +1937,10 @@ mrb_bint_rshift(mrb_state *mrb, mrb_value x, mrb_int width) struct RBigint *b = RBIGINT(x); struct RBigint *b2 = bint_new(mrb); if (width < 0) { - mpz_mul_2exp(mrb, &b2->mp, &b->mp, -width); + mpz_mul_2exp(mrb, b2, b, -width); } else { - mpz_div_2exp(mrb, &b2->mp, &b->mp, width); + mpz_div_2exp(mrb, b2, b, width); } return bint_norm(mrb, b2); } @@ -1832,22 +1950,23 @@ mrb_bint_copy(mrb_state *mrb, mrb_value x, mrb_value y) { struct RBigint *b = RBIGINT(x); struct RBigint *b2 = RBIGINT(y); - mpz_init_set(mrb, &b->mp, &b2->mp); + mpz_init_set(mrb, b, b2); } size_t mrb_bint_memsize(mrb_value x) { struct RBigint *b = RBIGINT(x); - return b->mp.sz * sizeof(mp_limb); + return RBIGINT_EMBED_P(b) ? 0 : RBIGINT_SIZE(b) * sizeof(mp_limb); } mrb_value mrb_bint_hash(mrb_state *mrb, mrb_value x) { struct RBigint *b = RBIGINT(x); - uint32_t hash = mrb_byte_hash((uint8_t*)b->mp.p, b->mp.sz*sizeof(mp_limb)); - hash = mrb_byte_hash_step((uint8_t*)&b->mp.sn, sizeof(b->mp.sn), hash); + short sign = RBIGINT_SIGN(b); + uint32_t hash = mrb_byte_hash((uint8_t*)RBIGINT_ARY(b), RBIGINT_SIZE(b)*sizeof(mp_limb)); + hash = mrb_byte_hash_step((uint8_t*)&sign, sizeof(sign), hash); return mrb_int_value(mrb, hash); } @@ -1858,19 +1977,18 @@ mrb_bint_2comp(mrb_state *mrb, mrb_value x) struct RBigint *b = RBIGINT(x); struct RBigint *b2 = bint_new(mrb); - mrb_assert(b->mp.sn < 0); - size_t size = b->mp.sz; - mpz_t *z = &b2->mp; - mpz_realloc(mrb, z, size); - mp_limb *ds = b->mp.p; - mp_limb *dd = z->p; + mrb_assert(RBIGINT_SIGN(b) < 0); + size_t size = RBIGINT_SIZE(b); + mpz_realloc(mrb, b2, size); + mp_limb *ds = RBIGINT_ARY(b); + mp_limb *dd = RBIGINT_ARY(b2); char carry = 1; for (size_t i=0; isn = 1; + RBIGINT_SET_SIGN(b2, 1); return mrb_obj_value(b2); } @@ -1880,14 +1998,14 @@ mrb_bint_reduce(mrb_state *mrb, mrb_value *xp, mrb_value *yp) { struct RBigint *b1 = RBIGINT(*xp); struct RBigint *b2 = RBIGINT(*yp); - mpz_t r; mpz_init(mrb, &r); + struct RBigint r; mpz_init(mrb, &r); - mpz_gcd(mrb, &r, &b1->mp, &b2->mp); + mpz_gcd(mrb, &r, b1, b2); struct RBigint *b3 = bint_new(mrb); struct RBigint *b4 = bint_new(mrb); - mpz_mdiv(mrb, &b3->mp, &b1->mp, &r); - mpz_mdiv(mrb, &b4->mp, &b2->mp, &r); + mpz_mdiv(mrb, b3, b1, &r); + mpz_mdiv(mrb, b4, b2, &r); mpz_clear(mrb, &r); *xp = mrb_obj_value(b3); diff --git a/mrbgems/mruby-bigint/core/bigint.h b/mrbgems/mruby-bigint/core/bigint.h index eda82c080..2ab13dcb9 100644 --- a/mrbgems/mruby-bigint/core/bigint.h +++ b/mrbgems/mruby-bigint/core/bigint.h @@ -46,6 +46,8 @@ typedef int64_t mp_dbl_limb_signed; #define MPZ_DIG_SIZE 32 #endif +#define RBIGINT_EMBED_SIZE_MAX ((sizeof(void*) * 3) / sizeof(mp_limb)) + typedef struct _mpz_t { mp_limb *p; short sn; @@ -54,10 +56,82 @@ typedef struct _mpz_t { struct RBigint { MRB_OBJECT_HEADER; - mpz_t mp; + union { + mpz_t heap; + mp_limb ary[RBIGINT_EMBED_SIZE_MAX]; + } as; }; #define RBIGINT(v) ((struct RBigint*)mrb_ptr(v)) +/* + * flags of struct RBigint + * + * 6..: UNUSED + * 4..5: sign flags + * 00: negative (<--> -1) + * 01: zero (<--> 0) + * 10: positive (<--> +1) + * 11: UNUSED + * 0..3: size of embeded array; 15 means used with heap + */ + +#define RBIGINT_EMBED_SIZE_MASK 0x0f +#define RBIGINT_EMBED_SIZE_OVER RBIGINT_EMBED_SIZE_MASK +#define RBIGINT_EMBED_SIZE_SHIFT 0 +#define RBIGINT_EMBED_SIGN_MASK 0x03 +#define RBIGINT_EMBED_SIGN_SHIFT 4 + +#define RBIGINT_ARY(m) (RBIGINT_EMBED_P(m) ? RBIGINT_EMBED_ARY(m) : RBIGINT_HEAP_ARY(m)) +#define RBIGINT_SIGN(m) (RBIGINT_EMBED_P(m) ? RBIGINT_EMBED_SIGN(m) : RBIGINT_HEAP_SIGN(m)) +#define RBIGINT_SIZE(m) (RBIGINT_EMBED_P(m) ? RBIGINT_EMBED_SIZE(m) : RBIGINT_HEAP_SIZE(m)) +#define RBIGINT_SET_SIGN(m, s) do { \ + if (RBIGINT_EMBED_P(m)) { \ + RBIGINT_SET_EMBED_SIGN(m, s); \ + } \ + else { \ + RBIGINT_SET_HEAP_SIGN(m, s); \ + } \ +} while (0) +#define RBIGINT_SET_SIZE(m, s) do { \ + if (RBIGINT_EMBED_P(m)) { \ + RBIGINT_SET_EMBED_SIZE(m, s); \ + } \ + else { \ + RBIGINT_SET_HEAP_SIZE(m, s); \ + } \ +} while (0) + +#define RBIGINT_HEAP_ARY(m) ((m)->as.heap.p) +#define RBIGINT_HEAP_SIGN(m) ((m)->as.heap.sn) +#define RBIGINT_HEAP_SIZE(m) ((m)->as.heap.sz) +#define RBIGINT_SET_HEAP(m) do { \ + (m)->flags |= RBIGINT_EMBED_SIZE_OVER << RBIGINT_EMBED_SIZE_SHIFT; \ +} while (0) +#define RBIGINT_SET_HEAP_SIGN(m, s) do { \ + (m)->as.heap.sn = (s); \ +} while (0) +#define RBIGINT_SET_HEAP_SIZE(m, s) do { \ + (m)->as.heap.sz = (s); \ +} while (0) + +#define RBIGINT_EMBED_P(m) ((((m)->flags >> RBIGINT_EMBED_SIZE_SHIFT) & RBIGINT_EMBED_SIZE_MASK) < RBIGINT_EMBED_SIZE_OVER) +#define RBIGINT_EMBED_ARY(m) ((m)->as.ary) +#define RBIGINT_EMBED_SIGN(m) ((short)(((m)->flags >> RBIGINT_EMBED_SIGN_SHIFT) & RBIGINT_EMBED_SIGN_MASK) - 1) +#define RBIGINT_EMBED_SIZE(m) (size_t)(((m)->flags >> RBIGINT_EMBED_SIZE_SHIFT) & RBIGINT_EMBED_SIZE_MASK) +#define RBIGINT_SET_EMBED_ZERO(m) do { \ + (m)->flags &= ~(RBIGINT_EMBED_SIZE_MASK << RBIGINT_EMBED_SIZE_SHIFT); \ +} while (0) +#define RBIGINT_SET_EMBED_SIGN(m, s) do { \ + (m)->flags = ((((s) + 1) & RBIGINT_EMBED_SIGN_MASK) << RBIGINT_EMBED_SIGN_SHIFT) | \ + ((m)->flags & ~(RBIGINT_EMBED_SIGN_MASK << RBIGINT_EMBED_SIGN_SHIFT)); \ +} while (0) +#define RBIGINT_SET_EMBED_SIZE(m, s) do { \ + size_t s_tmp = (s); \ + mrb_assert((s_tmp) <= RBIGINT_EMBED_SIZE_MAX); \ + RBIGINT_SET_EMBED_ZERO(m); \ + (m)->flags |= (s_tmp) << RBIGINT_EMBED_SIZE_SHIFT; \ +} while (0) + mrb_static_assert_object_size(struct RBigint); #endif /* MRUBY_BIGINT_H */ From 6366f1cbb9121425ceedace0452762f78cea01bd Mon Sep 17 00:00:00 2001 From: dearblue Date: Sun, 6 Oct 2024 23:03:03 +0900 Subject: [PATCH 2/2] Update mrbgems/mruby-bigint/core/bigint.h Co-authored-by: John Bampton --- mrbgems/mruby-bigint/core/bigint.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrbgems/mruby-bigint/core/bigint.h b/mrbgems/mruby-bigint/core/bigint.h index 2ab13dcb9..6de6f98a4 100644 --- a/mrbgems/mruby-bigint/core/bigint.h +++ b/mrbgems/mruby-bigint/core/bigint.h @@ -72,7 +72,7 @@ struct RBigint { * 01: zero (<--> 0) * 10: positive (<--> +1) * 11: UNUSED - * 0..3: size of embeded array; 15 means used with heap + * 0..3: size of embedded array; 15 means used with heap */ #define RBIGINT_EMBED_SIZE_MASK 0x0f