diff --git a/mrbgems/mruby-bigint/core/bigint.c b/mrbgems/mruby-bigint/core/bigint.c index e81c7dc36..b144642b7 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,117 +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; @@ -241,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=x->sz-1; 0 <= i; 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); @@ -279,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; @@ -299,35 +367,46 @@ 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); mpz_move(mrb, zz, &z); } +/* x = y - n */ +static void +mpz_add_int(mrb_state *mrb, struct RBigint *x, struct RBigint *y, mrb_int n) +{ + struct RBigint z; + + mpz_init_set_int(mrb, &z, n); + mpz_add(mrb, x, y, &z); + mpz_clear(mrb, &z); +} + /* 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); - u.p = y->p; - u.sz = y->sz; - u.sn = -(y->sn); + mpz_set(mrb, &u, y); + 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); @@ -337,37 +416,56 @@ mpz_sub_int(mrb_state *mrb, mpz_t *x, mpz_t *y, mrb_int n) /* w = u * v */ /* Simple Multiply */ 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) { if (zero_p(u) || zero_p(v)) { - zero(ww); + 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); + RBIGINT_SET_SIGN(ww, RBIGINT_SIGN(u) * RBIGINT_SIGN(v)); +} + +static void +mpz_mul_int(mrb_state *mrb, struct RBigint *x, struct RBigint *y, mrb_int n) +{ + if (n == 0) { + zero(x); + return; + } + + struct RBigint z; + mpz_init_set_int(mrb, &z, n); + mpz_mul(mrb, x, y, &z); + mpz_clear(mrb, &z); } /* number of leading zero bits in digit */ @@ -392,25 +490,28 @@ 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); if (n == 0) mpz_set(mrb, c1, a); else if (uzero_p(a)) { - zero(c1); + 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); @@ -421,28 +522,31 @@ 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); } @@ -451,7 +555,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); @@ -466,54 +570,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); @@ -522,10 +631,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); @@ -533,9 +642,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); @@ -543,10 +652,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) { @@ -556,26 +665,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); @@ -583,34 +692,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); @@ -618,112 +727,47 @@ 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; } -/* x = y * n (only called from mpz_init_set_str) */ -/* assumes x and n are positive or zero */ -/* assumes n is small (fits in mp_limb) */ -static void -mpz_mul_int(mrb_state *mrb, mpz_t *x, mrb_int n) -{ - if (n == 0 || zero_p(x)) { - zero(x); - return; - } - - size_t x_sz = x->sz; - size_t new_sz = x_sz + 1; // Maximum possible size after multiplication - - // Reallocate x if necessary - mpz_realloc(mrb, x, new_sz); - - mp_dbl_limb cc = 0; - mp_limb n_limb = (mp_limb)n; - - for (size_t i = 0; i < x_sz; i++) { - // Multiply each limb and add carry - cc += (mp_dbl_limb)x->p[i] * n_limb; - x->p[i] = LOW(cc); - cc = HIGH(cc); - } - - if (cc) { - // If there is a remaining carry, store it - x->p[x_sz] = (mp_limb)cc; - } else { - x->sz = x_sz; - } - - x->sn = 1; - trim(x); -} - -/* x = y + n (only called from mpz_init_set_str) */ -/* assumes x and n are positive or zero */ -/* assumes n is small (fits in mp_limb) */ -static void -mpz_add_int(mrb_state *mrb, mpz_t *x, mrb_int n) -{ - if (n == 0) { - // If n is zero, no operation is needed - return; - } - - // Assume x is positive and n is a small positive integer (n < 36) - mp_dbl_limb carry = n; // Initialize carry with n - for (size_t i = 0; i < x->sz && carry; i++) { - carry += (mp_dbl_limb)x->p[i]; // Add current limb and carry - x->p[i] = LOW(carry); // Store lower 32 bits in current limb - carry = HIGH(carry); // Update carry with higher bits - } - - if (carry != 0) { - mpz_realloc(mrb, x, x->sz + 1); - x->p[x->sz-1] = (mp_limb)carry; - x->sn = 1; - } - trim(x); -} - 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; uint8_t k; - + mpz_init(mrb, x); zero(x); if (*s == '-') { sn = -1; s++; @@ -746,15 +790,15 @@ mpz_init_set_str(mrb_state *mrb, mpz_t *x, const char *s, mrb_int len, mrb_int b retval = (-1); break; } - mpz_mul_int(mrb, x, base); - mpz_add_int(mrb, x, k); + 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)) { @@ -774,8 +818,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; @@ -790,7 +835,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++ = '-'; } @@ -842,7 +887,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; @@ -850,9 +895,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; @@ -863,7 +910,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 { @@ -873,20 +920,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); @@ -921,50 +974,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); @@ -974,27 +1035,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); @@ -1004,29 +1073,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) { @@ -1048,24 +1125,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; + 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); @@ -1144,7 +1221,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; } @@ -1152,7 +1229,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; } @@ -1168,8 +1245,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 @@ -1178,8 +1255,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); } @@ -1193,9 +1270,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); } @@ -1205,7 +1282,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); @@ -1215,7 +1292,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 @@ -1242,8 +1319,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; @@ -1254,7 +1331,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; @@ -1269,15 +1346,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; @@ -1297,7 +1374,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; @@ -1308,7 +1385,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); @@ -1318,11 +1395,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 @@ -1331,16 +1408,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; @@ -1354,7 +1431,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); } @@ -1380,7 +1457,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); } @@ -1405,7 +1482,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; } @@ -1451,10 +1528,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); } @@ -1462,11 +1539,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); @@ -1476,11 +1553,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); @@ -1490,11 +1567,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); @@ -1517,10 +1594,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); } @@ -1536,10 +1613,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); } @@ -1556,10 +1633,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); @@ -1582,16 +1659,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 @@ -1602,7 +1679,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: @@ -1621,7 +1698,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); @@ -1631,17 +1708,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); } @@ -1651,15 +1728,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; } @@ -1673,21 +1750,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); } @@ -1701,13 +1778,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); } } @@ -1715,7 +1792,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); } @@ -1725,7 +1802,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); } @@ -1740,14 +1817,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); } @@ -1757,8 +1834,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); } @@ -1768,10 +1845,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); } @@ -1782,10 +1859,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); } @@ -1795,22 +1872,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); } @@ -1821,19 +1899,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); } @@ -1843,14 +1920,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..6de6f98a4 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 embedded 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 */