From c269421942b7969b5aa9c75ad1ef3f1932e60708 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 8 Feb 2026 14:48:21 -0800 Subject: [PATCH] Revert "mpz: use pointer tagging to save space (#8447)" This reverts commit 2f4abe2ce6b69b82fbcf86c4fa6bc9e6eaacf23b. --- src/util/mpz.cpp | 473 ++++++++++++++++++++++++----------------------- src/util/mpz.h | 174 ++++++----------- 2 files changed, 294 insertions(+), 353 deletions(-) diff --git a/src/util/mpz.cpp b/src/util/mpz.cpp index d55991219..10c345b0c 100644 --- a/src/util/mpz.cpp +++ b/src/util/mpz.cpp @@ -214,8 +214,8 @@ void mpz_manager::deallocate(bool is_heap, mpz_cell * ptr) { template mpz_manager::sign_cell::sign_cell(mpz_manager& m, mpz const& a): m_local(reinterpret_cast(m_bytes)), m_a(a) { - m_local.ptr()->m_capacity = capacity; - m.get_sign_cell(a, m_sign, m_cell, m_local.ptr()); + m_local.m_ptr->m_capacity = capacity; + m.get_sign_cell(a, m_sign, m_cell, m_local.m_ptr); } @@ -224,13 +224,12 @@ mpz_manager::sign_cell::sign_cell(mpz_manager& m, mpz const& a): template void mpz_manager::del(mpz_manager* m, mpz & a) { - if (!a.is_small()) { - mpz::mpz_type* p = a.ptr(); - if (p) { - SASSERT(m); - m->deallocate(!a.is_external(), p); - a.set(0); // Reset to small zero - } + if (a.m_ptr) { + SASSERT(m); + m->deallocate(a.m_owner == mpz_self, a.m_ptr); + a.m_ptr = nullptr; + a.m_kind = mpz_small; + a.m_owner = mpz_self; } } @@ -261,44 +260,43 @@ void mpz_manager::sub(mpz const & a, mpz const & b, mpz & c) { template void mpz_manager::set_big_i64(mpz & c, int64_t v) { #ifndef _MP_GMP - mpz_cell* cell = c.is_small() ? nullptr : c.ptr(); - if (cell == nullptr) { - cell = allocate(m_init_cell_capacity); - c.set_ptr(cell, false, false); // Will update sign below + if (c.m_ptr == nullptr) { + c.m_ptr = allocate(m_init_cell_capacity); + c.m_owner = mpz_self; } + c.m_kind = mpz_large; SASSERT(capacity(c) >= m_init_cell_capacity); uint64_t _v; - bool is_negative = false; if (v == std::numeric_limits::min()) { // min-int is even _v = -(v/2); - is_negative = true; + c.m_val = -1; } else if (v < 0) { _v = -v; - is_negative = true; + c.m_val = -1; } else { _v = v; + c.m_val = 1; } - c.set_sign(is_negative ? -1 : 1); if (sizeof(digit_t) == sizeof(uint64_t)) { // 64-bit machine digits(c)[0] = static_cast(_v); - c.ptr()->m_size = 1; + c.m_ptr->m_size = 1; } else { // 32-bit machine digits(c)[0] = static_cast(_v); digits(c)[1] = static_cast(_v >> 32); - c.ptr()->m_size = digits(c)[1] == 0 ? 1 : 2; + c.m_ptr->m_size = digits(c)[1] == 0 ? 1 : 2; } #else - mpz_t* cell = c.is_small() ? nullptr : c.ptr(); - if (cell == nullptr) { - cell = allocate(); - c.set_ptr(cell, false, false); + if (c.m_ptr == nullptr) { + c.m_ptr = allocate(); + c.m_owner = mpz_self; } + c.m_kind = mpz_large; uint64_t _v; bool sign = v < 0; if (v == std::numeric_limits::min()) { @@ -310,14 +308,14 @@ void mpz_manager::set_big_i64(mpz & c, int64_t v) { else { _v = v; } - mpz_set_ui(*c.ptr(), static_cast(_v)); + mpz_set_ui(*c.m_ptr, static_cast(_v)); MPZ_BEGIN_CRITICAL(); mpz_set_ui(m_tmp, static_cast(_v >> 32)); mpz_mul(m_tmp, m_tmp, m_two32); - mpz_add(*c.ptr(), *c.ptr(), m_tmp); + mpz_add(*c.m_ptr, *c.m_ptr, m_tmp); MPZ_END_CRITICAL(); if (sign) - mpz_neg(*c.ptr(), *c.ptr()); + mpz_neg(*c.m_ptr, *c.m_ptr); #endif if (v == std::numeric_limits::min()) { big_add(c, c, c); @@ -327,35 +325,35 @@ void mpz_manager::set_big_i64(mpz & c, int64_t v) { template void mpz_manager::set_big_ui64(mpz & c, uint64_t v) { #ifndef _MP_GMP - mpz_cell* cell = c.is_small() ? nullptr : c.ptr(); - if (cell == nullptr) { - cell = allocate(m_init_cell_capacity); - c.set_ptr(cell, false, false); // positive, owned + if (c.m_ptr == nullptr) { + c.m_ptr = allocate(m_init_cell_capacity); + c.m_owner = mpz_self; } + c.m_kind = mpz_large; SASSERT(capacity(c) >= m_init_cell_capacity); - c.set_sign(1); // positive + c.m_val = 1; if (sizeof(digit_t) == sizeof(uint64_t)) { // 64-bit machine digits(c)[0] = static_cast(v); - c.ptr()->m_size = 1; + c.m_ptr->m_size = 1; } else { // 32-bit machine digits(c)[0] = static_cast(v); digits(c)[1] = static_cast(v >> 32); - c.ptr()->m_size = digits(c)[1] == 0 ? 1 : 2; + c.m_ptr->m_size = digits(c)[1] == 0 ? 1 : 2; } #else - mpz_t* cell = c.is_small() ? nullptr : c.ptr(); - if (cell == nullptr) { - cell = allocate(); - c.set_ptr(cell, false, false); // positive, owned + if (c.m_ptr == nullptr) { + c.m_ptr = allocate(); + c.m_owner = mpz_self; } - mpz_set_ui(*c.ptr(), static_cast(v)); + c.m_kind = mpz_large; + mpz_set_ui(*c.m_ptr, static_cast(v)); MPZ_BEGIN_CRITICAL(); mpz_set_ui(m_tmp, static_cast(v >> 32)); mpz_mul(m_tmp, m_tmp, m_two32); - mpz_add(*c.ptr(), *c.ptr(), m_tmp); + mpz_add(*c.m_ptr, *c.m_ptr, m_tmp); MPZ_END_CRITICAL(); #endif } @@ -367,10 +365,10 @@ mpz_manager::ensure_mpz_t::ensure_mpz_t(mpz const& a) { if (is_small(a)) { m_result = &m_local; mpz_init(m_local); - mpz_set_si(m_local, a.value()); + mpz_set_si(m_local, a.m_val); } else { - m_result = a.ptr(); + m_result = a.m_ptr; } } @@ -398,14 +396,15 @@ void mpz_manager::set(mpz_cell& src, mpz & a, int sign, unsigned sz) { unsigned d = src.m_digits[0]; if (i == 1 && d <= INT_MAX) { // src fits is a fixnum - a.set(sign < 0 ? -static_cast(d) : static_cast(d)); + a.m_val = sign < 0 ? -static_cast(d) : static_cast(d); + a.m_kind = mpz_small; return; } set_digits(a, i, src.m_digits); - a.set_sign(sign); + a.m_val = sign; - SASSERT(!a.is_small()); + SASSERT(a.m_kind == mpz_large); } #endif @@ -444,14 +443,15 @@ void mpz_manager::set_digits(mpz & target, unsigned sz, digit_t const * d set(target, digits[0]); else { #ifndef _MP_GMP - mpz_cell* cell = target.is_small() ? nullptr : target.ptr(); - if (cell == nullptr) { + target.m_val = 1; // number is positive. + if (target.m_ptr == nullptr) { unsigned c = sz < m_init_cell_capacity ? m_init_cell_capacity : sz; - cell = allocate(c); - cell->m_size = sz; - cell->m_capacity = c; - target.set_ptr(cell, false, false); // positive, owned - memcpy(cell->m_digits, digits, sizeof(digit_t) * sz); + target.m_ptr = allocate(c); + target.m_ptr->m_size = sz; + target.m_ptr->m_capacity = c; + target.m_kind = mpz_large; + target.m_owner = mpz_self; + memcpy(target.m_ptr->m_digits, digits, sizeof(digit_t) * sz); } else if (capacity(target) < sz) { SASSERT(sz > m_init_cell_capacity); @@ -460,26 +460,29 @@ void mpz_manager::set_digits(mpz & target, unsigned sz, digit_t const * d ptr->m_size = sz; ptr->m_capacity = sz; deallocate(target); - target.set_ptr(ptr, false, false); // positive, owned + target.m_val = 1; + target.m_ptr = ptr; + target.m_kind = mpz_large; + target.m_owner = mpz_self; } else { - target.ptr()->m_size = sz; - if (target.ptr()->m_digits != digits) - memcpy(target.ptr()->m_digits, digits, sizeof(digit_t) * sz); - // already large + target.m_ptr->m_size = sz; + if (target.m_ptr->m_digits != digits) + memcpy(target.m_ptr->m_digits, digits, sizeof(digit_t) * sz); + target.m_kind = mpz_large; } #else mk_big(target); // reset - mpz_set_ui(*target.ptr(), digits[sz - 1]); + mpz_set_ui(*target.m_ptr, digits[sz - 1]); SASSERT(sz > 0); unsigned i = sz - 1; MPZ_BEGIN_CRITICAL(); while (i > 0) { --i; - mpz_mul_2exp(*target.ptr(), *target.ptr(), 32); + mpz_mul_2exp(*target.m_ptr, *target.m_ptr, 32); mpz_set_ui(m_tmp, digits[i]); - mpz_add(*target.ptr(), *target.ptr(), m_tmp); + mpz_add(*target.m_ptr, *target.m_ptr, m_tmp); } MPZ_END_CRITICAL(); #endif @@ -670,7 +673,7 @@ mpz mpz_manager::mod2k(mpz const & a, unsigned k) { if (rem_bits > 0 && digit_count < ca.cell()->m_size) { is_zero &= (digits(result)[digit_count] = ca.cell()->m_digits[digit_count] & mask) == 0; } - result.ptr()->m_size = total_digits; + result.m_ptr->m_size = total_digits; if (ca.sign() < 0 && !is_zero) { // Negative case: if non-zero, result = 2^k - (|a| mod 2^k) @@ -697,7 +700,7 @@ mpz mpz_manager::mod2k(mpz const & a, unsigned k) { ensure_mpz_t a1(a); mk_big(result); MPZ_BEGIN_CRITICAL(); - mpz_tdiv_r_2exp(*result.ptr(), a1(), k); + mpz_tdiv_r_2exp(*result.m_ptr, a1(), k); MPZ_END_CRITICAL(); #endif return result; @@ -706,24 +709,19 @@ mpz mpz_manager::mod2k(mpz const & a, unsigned k) { template void mpz_manager::neg(mpz & a) { STRACE(mpz, tout << "[mpz] 0 - " << to_string(a) << " == ";); - if (is_small(a) && a.value() == INT_MIN) { + if (is_small(a) && a.m_val == INT_MIN) { // neg(INT_MIN) is not a small int set_big_i64(a, - static_cast(INT_MIN)); return; } #ifndef _MP_GMP - if (is_small(a)) { - a.set(-a.value()); - } - else { - a.set_sign(-a.sign()); - } + a.m_val = -a.m_val; #else if (is_small(a)) { - a.set(-a.value()); + a.m_val = -a.m_val; } else { - mpz_neg(*a.ptr(), *a.ptr()); + mpz_neg(*a.m_ptr, *a.m_ptr); } #endif STRACE(mpz, tout << to_string(a) << "\n";); @@ -732,21 +730,20 @@ void mpz_manager::neg(mpz & a) { template void mpz_manager::abs(mpz & a) { if (is_small(a)) { - int v = a.value(); - if (v < 0) { - if (v == INT_MIN) { + if (a.m_val < 0) { + if (a.m_val == INT_MIN) { // abs(INT_MIN) is not a small int set_big_i64(a, - static_cast(INT_MIN)); } else - a.set(-v); + a.m_val = -a.m_val; } } else { #ifndef _MP_GMP - a.set_sign(1); + a.m_val = 1; #else - mpz_abs(*a.ptr(), *a.ptr()); + mpz_abs(*a.m_ptr, *a.m_ptr); #endif } } @@ -768,9 +765,9 @@ void mpz_manager::big_add_sub(mpz const & a, mpz const & b, mpz & c) { allocate_if_needed(tmp, sz); m_mpn_manager.add(ca.cell()->m_digits, ca.cell()->m_size, cb.cell()->m_digits, cb.cell()->m_size, - tmp.ptr()->m_digits, sz, &real_sz); + tmp.m_ptr->m_digits, sz, &real_sz); SASSERT(real_sz <= sz); - set(*tmp.ptr(), c, ca.sign(), real_sz); + set(*tmp.m_ptr, c, ca.sign(), real_sz); } else { digit_t borrow; @@ -787,10 +784,10 @@ void mpz_manager::big_add_sub(mpz const & a, mpz const & b, mpz & c) { cb.cell()->m_size, ca.cell()->m_digits, ca.cell()->m_size, - tmp.ptr()->m_digits, + tmp.m_ptr->m_digits, &borrow); SASSERT(borrow == 0); - set(*tmp.ptr(), c, sign_b, sz); + set(*tmp.m_ptr, c, sign_b, sz); } else { // a > b @@ -800,10 +797,10 @@ void mpz_manager::big_add_sub(mpz const & a, mpz const & b, mpz & c) { ca.cell()->m_size, cb.cell()->m_digits, cb.cell()->m_size, - tmp.ptr()->m_digits, + tmp.m_ptr->m_digits, &borrow); SASSERT(borrow == 0); - set(*tmp.ptr(), c, ca.sign(), sz); + set(*tmp.m_ptr, c, ca.sign(), sz); } } del(tmp); @@ -820,7 +817,7 @@ void mpz_manager::big_add(mpz const & a, mpz const & b, mpz & c) { // GMP version ensure_mpz_t a1(a), b1(b); mk_big(c); - mpz_add(*c.ptr(), a1(), b1()); + mpz_add(*c.m_ptr, a1(), b1()); #endif } @@ -832,7 +829,7 @@ void mpz_manager::big_sub(mpz const & a, mpz const & b, mpz & c) { // GMP version ensure_mpz_t a1(a), b1(b); mk_big(c); - mpz_sub(*c.ptr(), a1(), b1()); + mpz_sub(*c.m_ptr, a1(), b1()); #endif } @@ -848,14 +845,14 @@ void mpz_manager::big_mul(mpz const & a, mpz const & b, mpz & c) { ca.cell()->m_size, cb.cell()->m_digits, cb.cell()->m_size, - tmp.ptr()->m_digits); - set(*tmp.ptr(), c, ca.sign() == cb.sign() ? 1 : -1, sz); + tmp.m_ptr->m_digits); + set(*tmp.m_ptr, c, ca.sign() == cb.sign() ? 1 : -1, sz); del(tmp); #else // GMP version ensure_mpz_t a1(a), b1(b); mk_big(c); - mpz_mul(*c.ptr(), a1(), b1()); + mpz_mul(*c.m_ptr, a1(), b1()); #endif } @@ -869,7 +866,7 @@ void mpz_manager::big_div_rem(mpz const & a, mpz const & b, mpz & q, mpz ensure_mpz_t a1(a), b1(b); mk_big(q); mk_big(r); - mpz_tdiv_qr(*q.ptr(), *r.ptr(), a1(), b1()); + mpz_tdiv_qr(*q.m_ptr, *r.m_ptr, a1(), b1()); #endif } @@ -900,12 +897,12 @@ void mpz_manager::quot_rem_core(mpz const & a, mpz const & b, mpz & q, mp allocate_if_needed(r1, r_sz); m_mpn_manager.div(ca.cell()->m_digits, ca.cell()->m_size, cb.cell()->m_digits, cb.cell()->m_size, - q1.ptr()->m_digits, - r1.ptr()->m_digits); + q1.m_ptr->m_digits, + r1.m_ptr->m_digits); if (MODE == QUOT_ONLY || MODE == QUOT_AND_REM) - set(*q1.ptr(), q, ca.sign() == cb.sign() ? 1 : -1, q_sz); + set(*q1.m_ptr, q, ca.sign() == cb.sign() ? 1 : -1, q_sz); if (MODE == REM_ONLY || MODE == QUOT_AND_REM) - set(*r1.ptr(), r, ca.sign(), r_sz); + set(*r1.m_ptr, r, ca.sign(), r_sz); del(q1); del(r1); } @@ -922,7 +919,7 @@ void mpz_manager::big_div(mpz const & a, mpz const & b, mpz & c) { // GMP version ensure_mpz_t a1(a), b1(b); mk_big(c); - mpz_tdiv_q(*c.ptr(), a1(), b1()); + mpz_tdiv_q(*c.m_ptr, a1(), b1()); #endif } @@ -937,17 +934,17 @@ void mpz_manager::big_rem(mpz const & a, mpz const & b, mpz & c) { // GMP version ensure_mpz_t a1(a), b1(b); mk_big(c); - mpz_tdiv_r(*c.ptr(), a1(), b1()); + mpz_tdiv_r(*c.m_ptr, a1(), b1()); #endif } template void mpz_manager::gcd(mpz const & a, mpz const & b, mpz & c) { - static_assert(sizeof(int) == sizeof(int), "size mismatch"); + static_assert(sizeof(a.m_val) == sizeof(int), "size mismatch"); static_assert(sizeof(mpz) <= 16, "mpz size overflow"); - if (is_small(a) && is_small(b) && a.value() != INT_MIN && b.value() != INT_MIN) { - int _a = a.value(); - int _b = b.value(); + if (is_small(a) && is_small(b) && a.m_val != INT_MIN && b.m_val != INT_MIN) { + int _a = a.m_val; + int _b = b.m_val; if (_a < 0) _a = -_a; if (_b < 0) _b = -_b; unsigned r = u_gcd(_a, _b); @@ -957,7 +954,7 @@ void mpz_manager::gcd(mpz const & a, mpz const & b, mpz & c) { #ifdef _MP_GMP ensure_mpz_t a1(a), b1(b); mk_big(c); - mpz_gcd(*c.ptr(), a1(), b1()); + mpz_gcd(*c.m_ptr, a1(), b1()); return; #endif if (is_zero(a)) { @@ -1004,9 +1001,9 @@ void mpz_manager::gcd(mpz const & a, mpz const & b, mpz & c) { // reset least significant bit if (is_small(v)) - v.set(v.value() & ~1); + v.m_val &= ~1; else - v.ptr()->m_digits[0] &= ~static_cast(1); + v.m_ptr->m_digits[0] &= ~static_cast(1); k_v = power_of_two_multiple(v); } @@ -1121,7 +1118,7 @@ void mpz_manager::gcd(mpz const & a, mpz const & b, mpz & c) { SASSERT(ge(a1, b1)); if (is_small(b1)) { if (is_small(a1)) { - unsigned r = u_gcd(a1.value(), b1.value()); + unsigned r = u_gcd(a1.m_val, b1.m_val); set(c, r); break; } @@ -1138,11 +1135,11 @@ void mpz_manager::gcd(mpz const & a, mpz const & b, mpz & c) { } SASSERT(!is_small(a1)); SASSERT(!is_small(b1)); - a_sz = a1.ptr()->m_size; - b_sz = b1.ptr()->m_size; + a_sz = a1.m_ptr->m_size; + b_sz = b1.m_ptr->m_size; SASSERT(b_sz <= a_sz); - a_hat = a1.ptr()->m_digits[a_sz - 1]; - b_hat = (b_sz == a_sz) ? b1.ptr()->m_digits[b_sz - 1] : 0; + a_hat = a1.m_ptr->m_digits[a_sz - 1]; + b_hat = (b_sz == a_sz) ? b1.m_ptr->m_digits[b_sz - 1] : 0; A = 1; B = 0; C = 0; @@ -1206,9 +1203,9 @@ unsigned mpz_manager::size_info(mpz const & a) { if (is_small(a)) return 1; #ifndef _MP_GMP - return a.ptr()->m_size + 1; + return a.m_ptr->m_size + 1; #else - return mpz_size(*a.ptr()); + return mpz_size(*a.m_ptr); #endif } @@ -1401,7 +1398,8 @@ void mpz_manager::bitwise_or(mpz const & a, mpz const & b, mpz & c) { SASSERT(is_nonneg(b)); TRACE(mpz, tout << "is_small(a): " << is_small(a) << ", is_small(b): " << is_small(b) << "\n";); if (is_small(a) && is_small(b)) { - c.set(a.value() | b.value()); + c.m_val = a.m_val | b.m_val; + c.m_kind = mpz_small; } else { #ifndef _MP_GMP @@ -1436,7 +1434,7 @@ void mpz_manager::bitwise_or(mpz const & a, mpz const & b, mpz & c) { #else ensure_mpz_t a1(a), b1(b); mk_big(c); - mpz_ior(*c.ptr(), a1(), b1()); + mpz_ior(*c.m_ptr, a1(), b1()); #endif } } @@ -1446,7 +1444,8 @@ void mpz_manager::bitwise_and(mpz const & a, mpz const & b, mpz & c) { SASSERT(is_nonneg(a)); SASSERT(is_nonneg(b)); if (is_small(a) && is_small(b)) { - c.set(a.value() & b.value()); + c.m_val = a.m_val & b.m_val; + c.m_kind = mpz_small; } else { #ifndef _MP_GMP @@ -1470,7 +1469,7 @@ void mpz_manager::bitwise_and(mpz const & a, mpz const & b, mpz & c) { #else ensure_mpz_t a1(a), b1(b); mk_big(c); - mpz_and(*c.ptr(), a1(), b1()); + mpz_and(*c.m_ptr, a1(), b1()); #endif } } @@ -1512,7 +1511,7 @@ void mpz_manager::bitwise_xor(mpz const & a, mpz const & b, mpz & c) { #else ensure_mpz_t a1(a), b1(b); mk_big(c); - mpz_xor(*c.ptr(), a1(), b1()); + mpz_xor(*c.m_ptr, a1(), b1()); #endif } } @@ -1559,32 +1558,33 @@ void mpz_manager::big_set(mpz & target, mpz const & source) { #ifndef _MP_GMP if (&target == &source) return; - int src_sign = source.sign(); - mpz_cell* target_cell = target.is_small() ? nullptr : target.ptr(); - if (target_cell == nullptr) { - mpz_cell* new_cell = allocate(capacity(source)); - new_cell->m_size = size(source); - new_cell->m_capacity = capacity(source); - memcpy(new_cell->m_digits, source.ptr()->m_digits, sizeof(digit_t) * size(source)); - target.set_ptr(new_cell, src_sign < 0, false); + target.m_val = source.m_val; + if (target.m_ptr == nullptr) { + target.m_ptr = allocate(capacity(source)); + target.m_ptr->m_size = size(source); + target.m_ptr->m_capacity = capacity(source); + target.m_kind = mpz_large; + target.m_owner = mpz_self; + memcpy(target.m_ptr->m_digits, source.m_ptr->m_digits, sizeof(digit_t) * size(source)); } else if (capacity(target) < size(source)) { deallocate(target); - mpz_cell* new_cell = allocate(capacity(source)); - new_cell->m_size = size(source); - new_cell->m_capacity = capacity(source); - memcpy(new_cell->m_digits, source.ptr()->m_digits, sizeof(digit_t) * size(source)); - target.set_ptr(new_cell, src_sign < 0, false); + target.m_ptr = allocate(capacity(source)); + target.m_ptr->m_size = size(source); + target.m_ptr->m_capacity = capacity(source); + target.m_kind = mpz_large; + target.m_owner = mpz_self; + memcpy(target.m_ptr->m_digits, source.m_ptr->m_digits, sizeof(digit_t) * size(source)); } else { - target.ptr()->m_size = size(source); - memcpy(target.ptr()->m_digits, source.ptr()->m_digits, sizeof(digit_t) * size(source)); - target.set_sign(src_sign); + target.m_ptr->m_size = size(source); + memcpy(target.m_ptr->m_digits, source.m_ptr->m_digits, sizeof(digit_t) * size(source)); + target.m_kind = mpz_large; } #else // GMP version mk_big(target); - mpz_set(*target.ptr(), *source.ptr()); + mpz_set(*target.m_ptr, *source.m_ptr); #endif } @@ -1628,10 +1628,10 @@ int mpz_manager::big_compare(mpz const & a, mpz const & b) { template bool mpz_manager::is_uint64(mpz const & a) const { #ifndef _MP_GMP - if (!is_small(a) && a.sign() < 0) + if (a.m_val < 0) return false; if (is_small(a)) - return a.value() >= 0; + return true; if (sizeof(digit_t) == sizeof(uint64_t)) { return size(a) <= 1; } @@ -1641,8 +1641,8 @@ bool mpz_manager::is_uint64(mpz const & a) const { #else // GMP version if (is_small(a)) - return a.value() >= 0; - return is_nonneg(a) && mpz_cmp(*a.ptr(), m_uint64_max) <= 0; + return a.m_val >= 0; + return is_nonneg(a) && mpz_cmp(*a.m_ptr, m_uint64_max) <= 0; #endif } @@ -1656,7 +1656,7 @@ bool mpz_manager::is_int64(mpz const & a) const { uint64_t num = big_abs_to_uint64(a); uint64_t msb = static_cast(1) << 63; uint64_t msb_val = msb & num; - if (a.sign() >= 0) { + if (a.m_val >= 0) { // non-negative number. return (0 == msb_val); } @@ -1669,29 +1669,29 @@ bool mpz_manager::is_int64(mpz const & a) const { } #else // GMP version - return mpz_cmp(m_int64_min, *a.ptr()) <= 0 && mpz_cmp(*a.ptr(), m_int64_max) <= 0; + return mpz_cmp(m_int64_min, *a.m_ptr) <= 0 && mpz_cmp(*a.m_ptr, m_int64_max) <= 0; #endif } template uint64_t mpz_manager::get_uint64(mpz const & a) const { if (is_small(a)) - return static_cast(a.value()); + return static_cast(a.m_val); #ifndef _MP_GMP - SASSERT(a.ptr()->m_size > 0); + SASSERT(a.m_ptr->m_size > 0); return big_abs_to_uint64(a); #else // GMP version if (sizeof(uint64_t) == sizeof(unsigned long)) { - return mpz_get_ui(*a.ptr()); + return mpz_get_ui(*a.m_ptr); } else { MPZ_BEGIN_CRITICAL(); mpz_manager * _this = const_cast(this); - mpz_set(_this->m_tmp, *a.ptr()); + mpz_set(_this->m_tmp, *a.m_ptr); mpz_mod(_this->m_tmp, m_tmp, m_two32); uint64_t r = static_cast(mpz_get_ui(m_tmp)); - mpz_set(_this->m_tmp, *a.ptr()); + mpz_set(_this->m_tmp, *a.m_ptr); mpz_div(_this->m_tmp, m_tmp, m_two32); r += static_cast(mpz_get_ui(m_tmp)) << static_cast(32); MPZ_END_CRITICAL(); @@ -1703,11 +1703,11 @@ uint64_t mpz_manager::get_uint64(mpz const & a) const { template int64_t mpz_manager::get_int64(mpz const & a) const { if (is_small(a)) - return static_cast(a.value()); + return static_cast(a.m_val); #ifndef _MP_GMP SASSERT(is_int64(a)); uint64_t num = big_abs_to_uint64(a); - if (a.sign() < 0) { + if (a.m_val < 0) { if (num != 0 && (num << 1) == 0) return INT64_MIN; return -static_cast(num); @@ -1715,15 +1715,15 @@ int64_t mpz_manager::get_int64(mpz const & a) const { return static_cast(num); #else // GMP - if (sizeof(int64_t) == sizeof(long) || mpz_fits_slong_p(*a.ptr())) { - return mpz_get_si(*a.ptr()); + if (sizeof(int64_t) == sizeof(long) || mpz_fits_slong_p(*a.m_ptr)) { + return mpz_get_si(*a.m_ptr); } else { MPZ_BEGIN_CRITICAL(); mpz_manager * _this = const_cast(this); - mpz_mod(_this->m_tmp, *a.ptr(), m_two32); + mpz_mod(_this->m_tmp, *a.m_ptr, m_two32); int64_t r = static_cast(mpz_get_ui(m_tmp)); - mpz_div(_this->m_tmp, *a.ptr(), m_two32); + mpz_div(_this->m_tmp, *a.m_ptr, m_two32); r += static_cast(mpz_get_si(m_tmp)) << static_cast(32); MPZ_END_CRITICAL(); return r; @@ -1734,7 +1734,7 @@ int64_t mpz_manager::get_int64(mpz const & a) const { template double mpz_manager::get_double(mpz const & a) const { if (is_small(a)) - return static_cast(a.value()); + return static_cast(a.m_val); #ifndef _MP_GMP double r = 0.0; double d = 1.0; @@ -1749,34 +1749,30 @@ double mpz_manager::get_double(mpz const & a) const { if (!(r >= 0.0)) { r = static_cast(UINT64_MAX); // some large number } - return a.sign() < 0 ? -r : r; + return a.m_val < 0 ? -r : r; #else - return mpz_get_d(*a.ptr()); + return mpz_get_d(*a.m_ptr); #endif } template void mpz_manager::display(std::ostream & out, mpz const & a) const { if (is_small(a)) { - out << a.value(); + out << a.m_val; } else { #ifndef _MP_GMP - if (a.sign() < 0) - out << "-"; - if (sizeof(digit_t) == 4) { - sbuffer buffer(11*size(a), 0); - out << m_mpn_manager.to_string(digits(a), size(a), buffer.begin(), buffer.size()); - } - else { - sbuffer buffer(21*size(a), 0); - out << m_mpn_manager.to_string(digits(a), size(a), buffer.begin(), buffer.size()); - } + if (a.m_val < 0) + out << '-'; + + auto sz = sizeof(digit_t) == 4 ? 11 : 21; + sbuffer buffer(sz * size(a), 0); + out << m_mpn_manager.to_string(digits(a), size(a), buffer.begin(), buffer.size()); #else // GMP version - size_t sz = mpz_sizeinbase(*a.ptr(), 10) + 2; + size_t sz = mpz_sizeinbase(*a.m_ptr, 10) + 2; sbuffer buffer(sz, 0); - mpz_get_str(buffer.data(), 10, *a.ptr()); + mpz_get_str(buffer.data(), 10, *a.m_ptr); out << buffer.data(); #endif } @@ -1832,11 +1828,11 @@ void mpz_manager::display_hex(std::ostream & out, mpz const & a, unsigned } #else // GMP version - size_t sz = mpz_sizeinbase(*(a.ptr()), 16); + size_t sz = mpz_sizeinbase(*(a.m_ptr), 16); unsigned requiredLength = num_bits / 4; unsigned padding = requiredLength > sz ? requiredLength - sz : 0; sbuffer buffer(sz, 0); - mpz_get_str(buffer.data(), 16, *(a.ptr())); + mpz_get_str(buffer.data(), 16, *(a.m_ptr)); for (unsigned i = 0; i < padding; ++i) { out << "0"; } @@ -1887,10 +1883,10 @@ void mpz_manager::display_bin(std::ostream & out, mpz const & a, unsigned } #else // GMP version - size_t sz = mpz_sizeinbase(*(a.ptr()), 2); + size_t sz = mpz_sizeinbase(*(a.m_ptr), 2); unsigned padding = num_bits > sz ? num_bits - sz : 0; sbuffer buffer(sz, 0); - mpz_get_str(buffer.data(), 2, *(a.ptr())); + mpz_get_str(buffer.data(), 2, *(a.m_ptr)); for (unsigned i = 0; i < padding; ++i) { out << "0"; } @@ -1909,14 +1905,14 @@ std::string mpz_manager::to_string(mpz const & a) const { template unsigned mpz_manager::hash(mpz const & a) { if (is_small(a)) - return ::abs(a.value()); + return ::abs(a.m_val); #ifndef _MP_GMP unsigned sz = size(a); if (sz == 1) return static_cast(digits(a)[0]); return string_hash(std::string_view(reinterpret_cast(digits(a)), sz * sizeof(digit_t)), 17); #else - return mpz_get_si(*a.ptr()); + return mpz_get_si(*a.m_ptr); #endif } @@ -1925,37 +1921,38 @@ void mpz_manager::power(mpz const & a, unsigned p, mpz & b) { #ifdef _MP_GMP if (!is_small(a)) { mk_big(b); - mpz_pow_ui(*b.ptr(), *a.ptr(), p); + mpz_pow_ui(*b.m_ptr, *a.m_ptr, p); return; } #endif #ifndef _MP_GMP if (is_small(a)) { - if (a.value() == 2) { + if (a.m_val == 2) { if (p < 8 * sizeof(int) - 1) { - b.set(1 << p); + b.m_val = 1 << p; + b.m_kind = mpz_small; } else { unsigned sz = p/(8 * sizeof(digit_t)) + 1; unsigned shift = p%(8 * sizeof(digit_t)); SASSERT(sz > 0); allocate_if_needed(b, sz); - SASSERT(b.ptr()->m_capacity >= sz); - b.ptr()->m_size = sz; + SASSERT(b.m_ptr->m_capacity >= sz); + b.m_ptr->m_size = sz; for (unsigned i = 0; i < sz - 1; ++i) - b.ptr()->m_digits[i] = 0; - b.ptr()->m_digits[sz-1] = 1 << shift; - // b is already large after allocate_if_needed, just ensure sign is positive - b.set_sign(1); + b.m_ptr->m_digits[i] = 0; + b.m_ptr->m_digits[sz-1] = 1 << shift; + b.m_val = 1; + b.m_kind = mpz_large; } return; } - if (a.value() == 0) { + if (a.m_val == 0) { SASSERT(p != 0); set(b, 0); return; } - if (a.value() == 1) { + if (a.m_val == 1) { set(b, 1); return; } @@ -1986,8 +1983,8 @@ bool mpz_manager::is_power_of_two(mpz const & a, unsigned & shift) { if (is_nonpos(a)) return false; if (is_small(a)) { - if (::is_power_of_two(a.value())) { - shift = ::log2((unsigned)a.value()); + if (::is_power_of_two(a.m_val)) { + shift = ::log2((unsigned)a.m_val); return true; } else { @@ -1995,7 +1992,7 @@ bool mpz_manager::is_power_of_two(mpz const & a, unsigned & shift) { } } #ifndef _MP_GMP - mpz_cell * c = a.ptr(); + mpz_cell * c = a.m_ptr; unsigned sz = c->m_size; digit_t * ds = c->m_digits; for (unsigned i = 0; i < sz - 1; ++i) { @@ -2011,7 +2008,7 @@ bool mpz_manager::is_power_of_two(mpz const & a, unsigned & shift) { return false; } #else - if (mpz_popcount(*a.ptr()) == 1) { + if (mpz_popcount(*a.m_ptr) == 1) { shift = log2(a); return true; } @@ -2031,43 +2028,45 @@ void mpz_manager::ensure_capacity(mpz & a, unsigned capacity) { capacity = m_init_cell_capacity; if (is_small(a)) { - int val = a.value(); + int val = a.m_val; allocate_if_needed(a, capacity); - SASSERT(a.ptr()->m_capacity >= capacity); + a.m_kind = mpz_large; + SASSERT(a.m_ptr->m_capacity >= capacity); if (val == INT_MIN) { - unsigned intmin_sz = m_int_min.ptr()->m_size; + unsigned intmin_sz = m_int_min.m_ptr->m_size; for (unsigned i = 0; i < intmin_sz; ++i) - a.ptr()->m_digits[i] = m_int_min.ptr()->m_digits[i]; - a.set_sign(-1); - a.ptr()->m_size = m_int_min.ptr()->m_size; + a.m_ptr->m_digits[i] = m_int_min.m_ptr->m_digits[i]; + a.m_val = -1; + a.m_ptr->m_size = m_int_min.m_ptr->m_size; } else if (val < 0) { - a.ptr()->m_digits[0] = -val; - a.set_sign(-1); - a.ptr()->m_size = 1; + a.m_ptr->m_digits[0] = -val; + a.m_val = -1; + a.m_ptr->m_size = 1; } else { - a.ptr()->m_digits[0] = val; - a.set_sign(1); - a.ptr()->m_size = 1; + a.m_ptr->m_digits[0] = val; + a.m_val = 1; + a.m_ptr->m_size = 1; } } - else if (a.ptr()->m_capacity < capacity) { + else if (a.m_ptr->m_capacity < capacity) { mpz_cell * new_cell = allocate(capacity); SASSERT(new_cell->m_capacity == capacity); - unsigned old_sz = a.ptr()->m_size; + unsigned old_sz = a.m_ptr->m_size; new_cell->m_size = old_sz; for (unsigned i = 0; i < old_sz; ++i) - new_cell->m_digits[i] = a.ptr()->m_digits[i]; - bool is_neg = a.sign() < 0; + new_cell->m_digits[i] = a.m_ptr->m_digits[i]; deallocate(a); - a.set_ptr(new_cell, is_neg, false); + a.m_ptr = new_cell; + a.m_owner = mpz_self; + a.m_kind = mpz_large; } } template void mpz_manager::normalize(mpz & a) { - mpz_cell * c = a.ptr(); + mpz_cell * c = a.m_ptr; digit_t * ds = c->m_digits; unsigned i = c->m_size; for (; i > 0; --i) { @@ -2083,8 +2082,9 @@ void mpz_manager::normalize(mpz & a) { if (i == 1 && ds[0] <= INT_MAX) { // a is small - int val = a.sign() < 0 ? -static_cast(ds[0]) : static_cast(ds[0]); - a.set(val); + int val = a.m_val < 0 ? -static_cast(ds[0]) : static_cast(ds[0]); + a.m_val = val; + a.m_kind = mpz_small; return; } // adjust size @@ -2099,17 +2099,17 @@ void mpz_manager::machine_div2k(mpz & a, unsigned k) { if (is_small(a)) { if (k < 32) { int64_t twok = 1ull << ((int64_t)k); - int64_t val = a.value(); - a.set((int)(val/twok)); + int64_t val = a.m_val; + a.m_val = (int)(val/twok); } else { - a.set(0); + a.m_val = 0; } return; } #ifndef _MP_GMP unsigned digit_shift = k / (8 * sizeof(digit_t)); - mpz_cell * c = a.ptr(); + mpz_cell * c = a.m_ptr; unsigned sz = c->m_size; if (digit_shift >= sz) { set(a, 0); @@ -2157,7 +2157,7 @@ void mpz_manager::machine_div2k(mpz & a, unsigned k) { MPZ_BEGIN_CRITICAL(); mpz_tdiv_q_2exp(m_tmp, a1(), k); mk_big(a); - mpz_swap(*a.ptr(), m_tmp); + mpz_swap(*a.m_ptr, m_tmp); MPZ_END_CRITICAL(); #endif } @@ -2174,13 +2174,14 @@ void mpz_manager::mul2k(mpz & a, unsigned k) { TRACE(mpz_mul2k, tout << "mul2k\na: " << to_string(a) << "\nk: " << k << "\n";); unsigned word_shift = k / (8 * sizeof(digit_t)); unsigned bit_shift = k % (8 * sizeof(digit_t)); - unsigned old_sz = is_small(a) ? 1 : a.ptr()->m_size; + unsigned old_sz = is_small(a) ? 1 : a.m_ptr->m_size; unsigned new_sz = old_sz + word_shift + 1; ensure_capacity(a, new_sz); TRACE(mpz_mul2k, tout << "word_shift: " << word_shift << "\nbit_shift: " << bit_shift << "\nold_sz: " << old_sz << "\nnew_sz: " << new_sz - << "\na after ensure capacity:\n" << to_string(a) << "\n";); + << "\na after ensure capacity:\n" << to_string(a) << "\n"; + tout << a.m_kind << "\n";); SASSERT(!is_small(a)); - mpz_cell * cell_a = a.ptr(); + mpz_cell * cell_a = a.m_ptr; old_sz = cell_a->m_size; digit_t * ds = cell_a->m_digits; for (unsigned i = old_sz; i < new_sz; ++i) @@ -2219,7 +2220,7 @@ void mpz_manager::mul2k(mpz & a, unsigned k) { #else ensure_mpz_t a1(a); mk_big(a); - mpz_mul_2exp(*a.ptr(), a1(), k); + mpz_mul_2exp(*a.m_ptr, a1(), k); #endif } @@ -2233,7 +2234,7 @@ unsigned mpz_manager::power_of_two_multiple(mpz const & a) { return 0; if (is_small(a)) { unsigned r = 0; - int v = a.value(); + int v = a.m_val; #define COUNT_DIGIT_RIGHT_ZEROS() \ if (v % (1 << 16) == 0) { \ r += 16; \ @@ -2258,7 +2259,7 @@ unsigned mpz_manager::power_of_two_multiple(mpz const & a) { return r; } #ifndef _MP_GMP - mpz_cell * c = a.ptr(); + mpz_cell * c = a.m_ptr; unsigned sz = c->m_size; unsigned r = 0; digit_t * source = c->m_digits; @@ -2280,7 +2281,7 @@ unsigned mpz_manager::power_of_two_multiple(mpz const & a) { } return r; #else - return mpz_scan1(*a.ptr(), 0); + return mpz_scan1(*a.m_ptr, 0); #endif } @@ -2289,10 +2290,10 @@ unsigned mpz_manager::log2(mpz const & a) { if (is_nonpos(a)) return 0; if (is_small(a)) - return ::log2((unsigned)a.value()); + return ::log2((unsigned)a.m_val); #ifndef _MP_GMP static_assert(sizeof(digit_t) == 8 || sizeof(digit_t) == 4, ""); - mpz_cell * c = a.ptr(); + mpz_cell * c = a.m_ptr; unsigned sz = c->m_size; digit_t * ds = c->m_digits; if (sizeof(digit_t) == 8) @@ -2300,7 +2301,7 @@ unsigned mpz_manager::log2(mpz const & a) { else return (sz - 1)*32 + ::log2(static_cast(ds[sz-1])); #else - unsigned r = mpz_sizeinbase(*a.ptr(), 2); + unsigned r = mpz_sizeinbase(*a.m_ptr, 2); SASSERT(r > 0); return r - 1; #endif @@ -2310,14 +2311,14 @@ template unsigned mpz_manager::mlog2(mpz const & a) { if (is_nonneg(a)) return 0; - if (is_small(a) && a.value() == INT_MIN) - return ::log2((unsigned)a.value()); + if (is_small(a) && a.m_val == INT_MIN) + return ::log2((unsigned)a.m_val); if (is_small(a)) - return ::log2((unsigned)-a.value()); + return ::log2((unsigned)-a.m_val); #ifndef _MP_GMP static_assert(sizeof(digit_t) == 8 || sizeof(digit_t) == 4, ""); - mpz_cell * c = a.ptr(); + mpz_cell * c = a.m_ptr; unsigned sz = c->m_size; digit_t * ds = c->m_digits; if (sizeof(digit_t) == 8) @@ -2326,7 +2327,7 @@ unsigned mpz_manager::mlog2(mpz const & a) { return (sz - 1)*32 + ::log2(static_cast(ds[sz-1])); #else MPZ_BEGIN_CRITICAL(); - mpz_neg(m_tmp, *a.ptr()); + mpz_neg(m_tmp, *a.m_ptr); unsigned r = mpz_sizeinbase(m_tmp, 2); MPZ_END_CRITICAL(); SASSERT(r > 0); @@ -2533,15 +2534,15 @@ template digit_t mpz_manager::get_least_significant(mpz const& a) { SASSERT(!is_neg(a)); if (is_small(a)) - return std::abs(a.value()); + return std::abs(a.m_val); #ifndef _MP_GMP - mpz_cell* cell_a = a.ptr(); + mpz_cell* cell_a = a.m_ptr; unsigned sz = cell_a->m_size; if (sz == 0) return 0; return cell_a->m_digits[0]; #else - return mpz_get_ui(*a.ptr()); + return mpz_get_ui(*a.m_ptr); #endif } @@ -2549,27 +2550,27 @@ template bool mpz_manager::decompose(mpz const & a, svector & digits) { digits.reset(); if (is_small(a)) { - if (a.value() < 0) { - digits.push_back(-a.value()); + if (a.m_val < 0) { + digits.push_back(-a.m_val); return true; } else { - digits.push_back(a.value()); + digits.push_back(a.m_val); return false; } } else { #ifndef _MP_GMP - mpz_cell * cell_a = a.ptr(); + mpz_cell * cell_a = a.m_ptr; unsigned sz = cell_a->m_size; for (unsigned i = 0; i < sz; ++i) { digits.push_back(cell_a->m_digits[i]); } - return a.sign() < 0; + return a.m_val < 0; #else bool r = is_neg(a); MPZ_BEGIN_CRITICAL(); - mpz_set(m_tmp, *a.ptr()); + mpz_set(m_tmp, *a.m_ptr); mpz_abs(m_tmp, m_tmp); while (mpz_sgn(m_tmp) != 0) { mpz_tdiv_r_2exp(m_tmp2, m_tmp, 32); @@ -2586,16 +2587,16 @@ bool mpz_manager::decompose(mpz const & a, svector & digits) { template bool mpz_manager::get_bit(mpz const & a, unsigned index) { if (is_small(a)) { - SASSERT(a.value() >= 0); + SASSERT(a.m_val >= 0); if (index >= 8*sizeof(digit_t)) return false; - return 0 != (a.value() & (1ull << (digit_t)index)); + return 0 != (a.m_val & (1ull << (digit_t)index)); } unsigned i = index / (sizeof(digit_t)*8); unsigned o = index % (sizeof(digit_t)*8); #ifndef _MP_GMP - mpz_cell * cell_a = a.ptr(); + mpz_cell * cell_a = a.m_ptr; unsigned sz = cell_a->m_size; if (sz*sizeof(digit_t)*8 <= index) return false; diff --git a/src/util/mpz.h b/src/util/mpz.h index 8f9548462..505bb177e 100644 --- a/src/util/mpz.h +++ b/src/util/mpz.h @@ -68,63 +68,27 @@ class mpz_cell { /** \brief Multi-precision integer. - - m_value encodes either a small integer (if the least significant bit is 1) - or a pointer to a mpz_cell structure (if the least significant bit is 0). - The last 3 bits of pointers are always 0 due to alignment, so we use them - to store additional information: - - bit 0: small/large info (1 = small, 0 = large) - - bit 1: sign bit (0 = non-negative, 1 = negative) - - bit 2: owner info (0 = owned, 1 = external) + + If m_kind == mpz_small, it is a small number and the value is stored in m_val. + If m_kind == mpz_large, the value is stored in m_ptr and m_ptr != nullptr. + m_val contains the sign (-1 negative, 1 positive) + under winodws, m_ptr points to a mpz_cell that store the value. */ +enum mpz_kind { mpz_small = 0, mpz_large = 1}; +enum mpz_owner { mpz_self = 0, mpz_ext = 1}; + class mpz { #ifndef _MP_GMP typedef mpz_cell mpz_type; #else typedef mpz_t mpz_type; #endif -private: - uintptr_t m_value = 1; // Default to small integer 0: (0 << 1) | 1 = 1 - - static constexpr uintptr_t SMALL_BIT = 0x1; - static constexpr uintptr_t SIGN_BIT = 0x2; - static constexpr uintptr_t OWNER_BIT = 0x4; - static constexpr uintptr_t MPZ_PTR_MASK = ~static_cast(0x7); - - mpz_type * ptr() const { - SASSERT(!is_small()); - return reinterpret_cast(m_value & MPZ_PTR_MASK); - } - - void set_ptr(mpz_type* p, bool is_negative, bool is_external) { - SASSERT((reinterpret_cast(p) & 0x7) == 0); // Check alignment - m_value = reinterpret_cast(p); - if (is_negative) - m_value |= SIGN_BIT; - if (is_external) - m_value |= OWNER_BIT; - } - - int get_sign() const { - SASSERT(!is_small()); - return (m_value & SIGN_BIT) ? -1 : 1; - } - - void set_sign(int s) { - SASSERT(!is_small()); - if (s < 0) - m_value |= SIGN_BIT; - else - m_value &= ~SIGN_BIT; - } - - bool is_external() const { - SASSERT(!is_small()); - return (m_value & OWNER_BIT) != 0; - } - protected: + int m_val; + unsigned m_kind:1; + unsigned m_owner:1; + mpz_type * m_ptr; friend class mpz_manager; friend class mpz_manager; friend class mpq_manager; @@ -134,58 +98,42 @@ protected: friend class mpbq_manager; friend class mpz_stack; public: - mpz(int v = 0) noexcept { - // Encode small integer: shift left by 1 and set bit 0 - m_value = (static_cast(static_cast(v)) << 1) | SMALL_BIT; - } - - mpz(mpz_type* ptr) noexcept { - SASSERT(ptr); - set_ptr(ptr, false, true); // external pointer, non-negative - } - - mpz(mpz && other) noexcept : mpz() { - swap(other); - } + mpz(int v = 0) noexcept : m_val(v), m_kind(mpz_small), m_owner(mpz_self), m_ptr(nullptr) {} + mpz(mpz_type* ptr) noexcept : m_val(0), m_kind(mpz_small), m_owner(mpz_ext), m_ptr(ptr) { SASSERT(ptr); } + mpz(mpz && other) noexcept : mpz() { swap(other); } mpz& operator=(mpz const& other) = delete; - mpz& operator=(mpz &&other) noexcept { swap(other); return *this; } void swap(mpz & other) noexcept { - std::swap(m_value, other.m_value); + std::swap(m_val, other.m_val); + std::swap(m_ptr, other.m_ptr); + unsigned o = m_owner; m_owner = other.m_owner; other.m_owner = o; + unsigned k = m_kind; m_kind = other.m_kind; other.m_kind = k; } void set(int v) { - m_value = (static_cast(static_cast(v)) << 1) | SMALL_BIT; + m_val = v; + m_kind = mpz_small; } - inline bool is_small() const { - return (m_value & SMALL_BIT) != 0; - } + inline bool is_small() const { return m_kind == mpz_small; } - inline int value() const { - SASSERT(is_small()); - // Decode small integer: shift right by 1 (arithmetic shift to preserve sign) - return static_cast(static_cast(m_value) >> 1); - } + inline int value() const { SASSERT(is_small()); return m_val; } - inline int sign() const { - SASSERT(!is_small()); - return get_sign(); - } + inline int sign() const { SASSERT(!is_small()); return m_val; } }; #ifndef _MP_GMP class mpz_stack : public mpz { static const unsigned capacity = 8; - alignas(8) unsigned char m_bytes[sizeof(mpz_cell) + sizeof(digit_t) * capacity]; + unsigned char m_bytes[sizeof(mpz_cell) + sizeof(digit_t) * capacity]; public: mpz_stack():mpz(reinterpret_cast(m_bytes)) { - ptr()->m_capacity = capacity; + m_ptr->m_capacity = capacity; } }; #else @@ -221,11 +169,16 @@ class mpz_manager { // make sure that n is a big number and has capacity equal to at least c. void allocate_if_needed(mpz & n, unsigned c) { if (m_init_cell_capacity > c) c = m_init_cell_capacity; - if (n.is_small() || n.ptr() == nullptr || capacity(n) < c) { + if (n.m_ptr == nullptr || capacity(n) < c) { deallocate(n); - n.set_ptr(allocate(c), false, false); // positive, owned + n.m_val = 1; + n.m_kind = mpz_large; + n.m_owner = mpz_self; + n.m_ptr = allocate(c); + } + else { + n.m_kind = mpz_large; } - // else already has enough capacity, keep as large } void deallocate(bool is_heap, mpz_cell * ptr); @@ -277,16 +230,14 @@ class mpz_manager { } } - void clear(mpz& n) { if (!n.is_small() && n.ptr()) { mpz_clear(*n.ptr()); }} + void clear(mpz& n) { if (n.m_ptr) { mpz_clear(*n.m_ptr); }} #endif void deallocate(mpz& n) { - if (!n.is_small()) { - typename mpz::mpz_type* p = n.ptr(); - if (p) { - deallocate(!n.is_external(), p); - n.set(0); // Reset to small zero - } + if (n.m_ptr) { + deallocate(n.m_owner == mpz_self, n.m_ptr); + n.m_ptr = nullptr; + n.m_kind = mpz_small; } } @@ -311,20 +262,11 @@ class mpz_manager { #ifndef _MP_GMP - static unsigned capacity(mpz const & c) { - SASSERT(!c.is_small()); - return c.ptr()->m_capacity; - } + static unsigned capacity(mpz const & c) { return c.m_ptr->m_capacity; } - static unsigned size(mpz const & c) { - SASSERT(!c.is_small()); - return c.ptr()->m_size; - } + static unsigned size(mpz const & c) { return c.m_ptr->m_size; } - static digit_t * digits(mpz const & c) { - SASSERT(!c.is_small()); - return c.ptr()->m_digits; - } + static digit_t * digits(mpz const & c) { return c.m_ptr->m_digits; } // Return true if the absolute value fits in a UINT64 static bool is_abs_uint64(mpz const & a) { @@ -340,7 +282,7 @@ class mpz_manager { static uint64_t big_abs_to_uint64(mpz const & a) { SASSERT(is_abs_uint64(a)); SASSERT(!is_small(a)); - if (a.ptr()->m_size == 1) + if (a.m_ptr->m_size == 1) return digits(a)[0]; if (sizeof(digit_t) == sizeof(uint64_t)) // 64-bit machine @@ -367,7 +309,7 @@ class mpz_manager { if (is_small(a)) { if (a.value() == INT_MIN) { sign = -1; - cell = m_int_min.ptr(); + cell = m_int_min.m_ptr; } else { cell = reserve; @@ -384,7 +326,7 @@ class mpz_manager { } else { sign = a.sign(); - cell = a.ptr(); + cell = a.m_ptr; } } @@ -401,10 +343,12 @@ class mpz_manager { }; void mk_big(mpz & a) { - if (a.is_small()) { - a.set_ptr(allocate(), false, false); // positive, owned + if (a.m_ptr == nullptr) { + a.m_val = 0; + a.m_ptr = allocate(); + a.m_owner = mpz_self; } - // else already large with valid pointer + a.m_kind = mpz_large; } @@ -504,17 +448,13 @@ public: static bool is_zero(mpz const & a) { return sign(a) == 0; } static int sign(mpz const & a) { - if (is_small(a)) { - int v = a.value(); - return (v > 0) - (v < 0); // Returns -1, 0, or 1 - } #ifndef _MP_GMP - else { - return a.sign(); - } + return a.m_val; #else + if (is_small(a)) + return a.m_val; else - return mpz_sgn(*a.ptr()); + return mpz_sgn(*a.m_ptr); #endif } @@ -685,7 +625,7 @@ public: #else if (is_small(a)) return a.value() == 1; - return mpz_cmp_si(*a.ptr(), 1) == 0; + return mpz_cmp_si(*a.m_ptr, 1) == 0; #endif } @@ -695,7 +635,7 @@ public: #else if (is_small(a)) return a.value() == -1; - return mpz_cmp_si(*a.ptr(), -1) == 0; + return mpz_cmp_si(*a.m_ptr, -1) == 0; #endif } @@ -773,7 +713,7 @@ public: #ifndef _MP_GMP return !(0x1 & digits(a)[0]); #else - return mpz_even_p(*a.ptr()); + return mpz_even_p(*a.m_ptr); #endif }