/* Bit_Row class implementation (non-inline functions). Copyright (C) 2001-2010 Roberto Bagnara Copyright (C) 2010-2011 BUGSENG srl (http://bugseng.com) This file is part of the Parma Polyhedra Library (PPL). The PPL is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. The PPL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307, USA. For the most up-to-date information see the Parma Polyhedra Library site: http://www.cs.unipr.it/ppl/ . */ #include #include "Bit_Row.defs.hh" #include "assert.hh" #include namespace PPL = Parma_Polyhedra_Library; unsigned long PPL::Bit_Row::first() const { const mp_size_t vec_size = vec->_mp_size; PPL_ASSERT(vec_size >= 0); mp_size_t li = 0; mp_srcptr p = vec->_mp_d; for (; li < vec_size; ++li, ++p) { const mp_limb_t limb = *p; if (limb != 0) return li*PPL_BITS_PER_GMP_LIMB + Implementation::first_one(limb); } return ULONG_MAX; } unsigned long PPL::Bit_Row::next(unsigned long position) const { ++position; // The alternative implementation using the mpz_scan1() function // of GMP was measured to be slower that ours. Here it is, in // case mpz_scan1() is improved. // // unsigned long r = mpz_scan1(vec, position); // return (r == ULONG_MAX) ? -1 : r; mp_size_t li = position / PPL_BITS_PER_GMP_LIMB; const mp_size_t vec_size = vec->_mp_size; PPL_ASSERT(vec_size >= 0); if (li >= vec_size) return ULONG_MAX; // Get the first limb. mp_srcptr p = vec->_mp_d + li; // Mask off any bits before `position' in the first limb. mp_limb_t limb = *p & (~(mp_limb_t) 0) << (position % PPL_BITS_PER_GMP_LIMB); while (true) { if (limb != 0) return li*PPL_BITS_PER_GMP_LIMB + Implementation::first_one(limb); ++li; if (li == vec_size) break; ++p; limb = *p; } return ULONG_MAX; } unsigned long PPL::Bit_Row::last() const { mp_size_t li = vec->_mp_size; PPL_ASSERT(li >= 0); if (li == 0) return ULONG_MAX; --li; const mp_srcptr p = vec->_mp_d + li; const mp_limb_t limb = *p; PPL_ASSERT(limb != 0); return li*PPL_BITS_PER_GMP_LIMB + Implementation::last_one(limb); } unsigned long PPL::Bit_Row::prev(unsigned long position) const { if (position == 0) return ULONG_MAX; --position; const mp_size_t vec_size = vec->_mp_size; PPL_ASSERT(vec_size > 0); mp_size_t li = position / PPL_BITS_PER_GMP_LIMB; mp_limb_t limb; mp_srcptr p = vec->_mp_d; // Get the first limb. if (li >= vec_size) { li = vec_size - 1; p += li; limb = *p; } else { const mp_limb_t mask = (~(mp_limb_t) 0) >> (PPL_BITS_PER_GMP_LIMB - 1 - position % PPL_BITS_PER_GMP_LIMB); p += li; limb = *p & mask; } while (true) { if (limb != 0) return li*PPL_BITS_PER_GMP_LIMB + Implementation::last_one(limb); if (li == 0) break; --li; --p; limb = *p; } return ULONG_MAX; } bool PPL::Bit_Row::operator[](const unsigned long k) const { const mp_size_t vec_size = vec->_mp_size; PPL_ASSERT(vec_size >= 0); unsigned long i = k / GMP_NUMB_BITS; if (i >= static_cast(vec_size)) return false; mp_limb_t limb = *(vec->_mp_d + i); return (limb >> (k % GMP_NUMB_BITS)) & 1; } void PPL::Bit_Row::set_until(unsigned long k) { // FIXME, TODO: this is an inefficient implementation. while (k-- > 0) mpz_setbit(vec, k); } /*! \relates Parma_Polyhedra_Library::Bit_Row */ int PPL::compare(const Bit_Row& x, const Bit_Row& y) { const mp_size_t x_size = x.vec->_mp_size; PPL_ASSERT(x_size >= 0); const mp_size_t y_size = y.vec->_mp_size; PPL_ASSERT(y_size >= 0); mp_size_t size = (x_size > y_size ? y_size : x_size); mp_srcptr xp = x.vec->_mp_d; mp_srcptr yp = y.vec->_mp_d; while (size > 0) { const mp_limb_t xl = *xp; const mp_limb_t yl = *yp; if (xl != yl) { // Get the ones where they are different. const mp_limb_t diff = xl ^ yl; // First bit that is different. const mp_limb_t mask = diff & ~(diff-1); return (xl & mask) ? 1 : -1; } ++xp; ++yp; --size; } return x_size == y_size ? 0 : (x_size > y_size ? 1 : -1); } /*! \relates Parma_Polyhedra_Library::Bit_Row */ bool PPL::subset_or_equal(const Bit_Row& x, const Bit_Row& y) { mp_size_t x_size = x.vec->_mp_size; PPL_ASSERT(x_size >= 0); mp_size_t y_size = y.vec->_mp_size; PPL_ASSERT(y_size >= 0); if (x_size > y_size) return false; mp_srcptr xp = x.vec->_mp_d; mp_srcptr yp = y.vec->_mp_d; while (x_size > 0) { if (*xp & ~*yp) return false; ++xp; ++yp; --x_size; } return true; } /*! \relates Parma_Polyhedra_Library::Bit_Row */ bool PPL::subset_or_equal(const Bit_Row& x, const Bit_Row& y, bool& strict_subset) { mp_size_t x_size = x.vec->_mp_size; PPL_ASSERT(x_size >= 0); mp_size_t y_size = y.vec->_mp_size; PPL_ASSERT(y_size >= 0); if (x_size > y_size) return false; mp_srcptr xp = x.vec->_mp_d; mp_srcptr yp = y.vec->_mp_d; strict_subset = (x_size < y_size); mp_limb_t xl; mp_limb_t yl; if (strict_subset) { while (x_size > 0) { xl = *xp; yl = *yp; if (xl & ~yl) return false; strict_subset_next: ++xp; ++yp; --x_size; } } else { while (x_size > 0) { xl = *xp; yl = *yp; if (xl != yl) { if (xl & ~yl) return false; strict_subset = true; goto strict_subset_next; } ++xp; ++yp; --x_size; } } return true; } /*! \relates Parma_Polyhedra_Library::Bit_Row */ bool PPL::strict_subset(const Bit_Row& x, const Bit_Row& y) { mp_size_t x_size = x.vec->_mp_size; PPL_ASSERT(x_size >= 0); mp_size_t y_size = y.vec->_mp_size; PPL_ASSERT(y_size >= 0); if (x_size > y_size) return false; bool different = (x_size < y_size); mp_srcptr xp = x.vec->_mp_d; mp_srcptr yp = y.vec->_mp_d; while (x_size > 0) { const mp_limb_t xl = *xp; const mp_limb_t yl = *yp; if (xl & ~yl) return false; if (!different && xl != yl) different = true; ++xp; ++yp; --x_size; } return different; } /*! \relates Bit_Row */ bool PPL::operator==(const Bit_Row& x, const Bit_Row& y) { const mp_size_t x_vec_size = x.vec->_mp_size; PPL_ASSERT(x_vec_size >= 0); const mp_size_t y_vec_size = y.vec->_mp_size; PPL_ASSERT(y_vec_size >= 0); if (x_vec_size != y_vec_size) return false; return mpn_cmp(x.vec->_mp_d, y.vec->_mp_d, x_vec_size) == 0; } /*! \relates Bit_Row */ bool PPL::operator!=(const Bit_Row& x, const Bit_Row& y) { const mp_size_t x_vec_size = x.vec->_mp_size; PPL_ASSERT(x_vec_size >= 0); const mp_size_t y_vec_size = y.vec->_mp_size; PPL_ASSERT(y_vec_size >= 0); if (x_vec_size != y_vec_size) return true; return mpn_cmp(x.vec->_mp_d, y.vec->_mp_d, x_vec_size) != 0; } bool PPL::Bit_Row::OK() const { const mp_size_t vec_size = vec->_mp_size; const mp_size_t vec_alloc = vec->_mp_alloc; return vec_size >= 0 && vec_alloc >= vec_size && (vec_size == 0 || mpz_getlimbn(vec, vec_size-1) != 0); } void PPL::Bit_Row::union_helper(const Bit_Row& y, const Bit_Row& z) { mp_size_t y_size = y.vec->_mp_size; mp_size_t z_size = z.vec->_mp_size; PPL_ASSERT(y_size <= z_size); PPL_ASSERT(vec->_mp_alloc >= z_size); vec->_mp_size = z_size; mp_srcptr yp = y.vec->_mp_d; mp_srcptr zp = z.vec->_mp_d; mp_ptr p = vec->_mp_d; z_size -= y_size; while (y_size > 0) { *p = *yp | * zp; ++yp; ++zp; ++p; --y_size; } while (z_size > 0) { *p = *zp; ++zp; ++p; --z_size; } }