/* SatRow class implementation (non-inline functions).
Copyright (C) 2001-2004 Roberto Bagnara <bagnara@cs.unipr.it>
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 2 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., 59 Temple Place - Suite 330, 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 <config.h>
#include "SatRow.defs.hh"
#include <iostream>
#include <cassert>
#include <climits>
namespace PPL = Parma_Polyhedra_Library;
#define BITS_PER_GMP_LIMB (SIZEOF_MP_LIMB_T*CHAR_BIT)
unsigned int
PPL::SatRow::first_one(mp_limb_t w) {
unsigned int r = 0;
w = w & -w;
#if SIZEOF_MP_LIMB_T > 4
if ((w & 0xffffffff) == 0) {
w >>= 32;
r += 32;
}
#endif
if ((w & 0xffff) == 0) {
w >>= 16;
r += 16;
}
if ((w & 0xff) == 0) {
w >>= 8;
r += 8;
}
if (w & 0xf0)
r += 4;
if (w & 0xcc)
r += 2;
if (w & 0xaa)
r += 1;
return r;
}
unsigned int
PPL::SatRow::last_one(mp_limb_t w) {
unsigned int r = 0;
#if SIZEOF_MP_LIMB_T > 4
if (w & 0xffffffff00000000) {
w >>= 32;
r += 32;
}
#endif
if (w & 0xffff0000) {
w >>= 16;
r += 16;
}
if (w & 0xff00) {
w >>= 8;
r += 8;
}
if (w & 0xf0) {
w >>= 4;
r += 4;
}
if (w & 0xc) {
w >>= 2;
r += 2;
}
if (w & 0x2)
r += 1;
return r;
}
int
PPL::SatRow::first() const {
for (size_t li = 0, vec_size = mpz_size(vec); li < vec_size; ++li) {
const mp_limb_t limb = mpz_getlimbn(vec, li);
if (limb != 0)
return li*BITS_PER_GMP_LIMB + first_one(limb);
}
return -1;
}
int
PPL::SatRow::next(int position) const {
assert(position >= 0);
++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;
size_t li = position / BITS_PER_GMP_LIMB;
const size_t vec_size = mpz_size(vec);
if (li >= vec_size)
return -1;
// Get the first limb.
mp_limb_t limb = mpz_getlimbn(vec, li);
// Mask off any bits before `position' in the first limb.
limb &= (-(mp_limb_t) 1) << (position % BITS_PER_GMP_LIMB);
while (limb == 0 && ++li < vec_size)
limb = mpz_getlimbn(vec, li);
if (limb != 0)
return li*BITS_PER_GMP_LIMB + first_one(limb);
else
return -1;
}
int
PPL::SatRow::last() const {
for (size_t li = mpz_size(vec); li-- > 0; ) {
const mp_limb_t limb = mpz_getlimbn(vec, li);
if (limb != 0)
return li*BITS_PER_GMP_LIMB + last_one(limb);
}
return -1;
}
int
PPL::SatRow::prev(int position) const {
assert(position >= 0);
if (position == 0)
return -1;
--position;
size_t li = position / BITS_PER_GMP_LIMB;
const size_t vec_size = mpz_size(vec);
mp_limb_t limb;
// Get the first limb.
if (li >= vec_size) {
li = vec_size - 1;
limb = mpz_getlimbn(vec, li);
}
else {
const mp_limb_t mask
= (-(mp_limb_t) 1)
>> (BITS_PER_GMP_LIMB - ((position + 1) % BITS_PER_GMP_LIMB));
limb = mpz_getlimbn(vec, li) & mask;
}
do {
if (limb != 0)
return li*BITS_PER_GMP_LIMB + last_one(limb);
if (li == 0)
break;
limb = mpz_getlimbn(vec, --li);
} while (true);
return -1;
}
/*! \relates Parma_Polyhedra_Library::SatRow */
int
PPL::compare(const SatRow& x, const SatRow& y) {
const size_t x_size = mpz_size(x.vec);
const size_t y_size = mpz_size(y.vec);
size_t x_li = 0;
size_t y_li = 0;
while (x_li < x_size && y_li < y_size) {
const mp_limb_t a = mpz_getlimbn(x.vec, x_li++);
const mp_limb_t b = mpz_getlimbn(y.vec, y_li++);
if (a != b) {
// Get the one's where they are different.
const mp_limb_t diff = (a ^ b);
// First bit that is different.
const mp_limb_t mask = diff & ~(diff-1);
return (a & mask) ? 1 : -1;
}
}
if (x_size < y_size) {
while (y_li < y_size)
if (mpz_getlimbn(y.vec, y_li++) != 0)
return -1;
return 0;
}
else if (x_size > y_size) {
while (x_li < x_size)
if (mpz_getlimbn(x.vec, x_li++) != 0)
return 1;
return 0;
}
return 0;
}
/*! \relates Parma_Polyhedra_Library::SatRow */
bool
PPL::subset_or_equal(const SatRow& x, const SatRow& y) {
const size_t x_size = mpz_size(x.vec);
const size_t y_size = mpz_size(y.vec);
size_t x_li = 0;
size_t y_li = 0;
while (x_li < x_size && y_li < y_size) {
const mp_limb_t a = mpz_getlimbn(x.vec, x_li++);
const mp_limb_t b = mpz_getlimbn(y.vec, y_li++);
if ((a | b) != b)
return false;
}
if (x_size > y_size)
while (x_li < x_size)
if (mpz_getlimbn(x.vec, x_li++) != 0)
return false;
return true;
}
/*! \relates Parma_Polyhedra_Library::SatRow */
bool
PPL::strict_subset(const SatRow& x, const SatRow& y) {
const size_t x_size = mpz_size(x.vec);
const size_t y_size = mpz_size(y.vec);
bool one_diff = false;
size_t x_li = 0;
size_t y_li = 0;
while (x_li < x_size && y_li < y_size) {
const mp_limb_t a = mpz_getlimbn(x.vec, x_li++);
const mp_limb_t b = mpz_getlimbn(y.vec, y_li++);
const mp_limb_t c = a | b;
if (c != b)
return false;
else if (c != a)
one_diff = true;
}
if (x_size < y_size) {
if (one_diff)
return true;
while (y_li < y_size)
if (mpz_getlimbn(y.vec, y_li++) != 0)
return true;
return false;
}
else if (x_size > y_size) {
if (!one_diff)
return false;
while (x_li < x_size)
if (mpz_getlimbn(x.vec, x_li++) != 0)
return false;
return true;
}
return one_diff;
}
bool
PPL::SatRow::OK() const {
return true;
}
syntax highlighted by Code2HTML, v. 0.9.1