PPL  0.12.1
Bit_Row.cc
Go to the documentation of this file.
00001 /* Bit_Row class implementation (non-inline functions).
00002    Copyright (C) 2001-2010 Roberto Bagnara <bagnara@cs.unipr.it>
00003    Copyright (C) 2010-2012 BUGSENG srl (http://bugseng.com)
00004 
00005 This file is part of the Parma Polyhedra Library (PPL).
00006 
00007 The PPL is free software; you can redistribute it and/or modify it
00008 under the terms of the GNU General Public License as published by the
00009 Free Software Foundation; either version 3 of the License, or (at your
00010 option) any later version.
00011 
00012 The PPL is distributed in the hope that it will be useful, but WITHOUT
00013 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00014 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00015 for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with this program; if not, write to the Free Software Foundation,
00019 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307, USA.
00020 
00021 For the most up-to-date information see the Parma Polyhedra Library
00022 site: http://bugseng.com/products/ppl/ . */
00023 
00024 #include "ppl-config.h"
00025 #include "Bit_Row.defs.hh"
00026 #include "assert.hh"
00027 #include "C_Integer.hh"
00028 
00029 namespace PPL = Parma_Polyhedra_Library;
00030 
00031 unsigned long
00032 PPL::Bit_Row::first() const {
00033   const mp_size_t vec_size = vec->_mp_size;
00034   PPL_ASSERT(vec_size >= 0);
00035   mp_srcptr p = vec->_mp_d;
00036   for (mp_size_t li = 0; li < vec_size; ++li, ++p) {
00037     const mp_limb_t limb = *p;
00038     if (limb != 0)
00039       return static_cast<unsigned long>(li) * PPL_BITS_PER_GMP_LIMB
00040         + Implementation::first_one(limb);
00041   }
00042   return C_Integer<unsigned long>::max;
00043 }
00044 
00045 unsigned long
00046 PPL::Bit_Row::next(unsigned long position) const {
00047   ++position;
00048 
00049   // The alternative implementation using the mpz_scan1() function
00050   // of GMP was measured to be slower that ours.  Here it is, in
00051   // case mpz_scan1() is improved.
00052   //
00053   // <CODE>
00054   //   unsigned long r = mpz_scan1(vec, position);
00055   //   return (r == C_Integer<unsigned long>::max) ? -1 : r;
00056   // </CODE>
00057 
00058   const unsigned long uli = position / PPL_BITS_PER_GMP_LIMB;
00059   mp_size_t li = static_cast<mp_size_t>(uli);
00060   const mp_size_t vec_size = vec->_mp_size;
00061   PPL_ASSERT(vec_size >= 0);
00062   if (li >= vec_size)
00063     return C_Integer<unsigned long>::max;
00064 
00065   // Get the first limb.
00066   mp_srcptr p = vec->_mp_d + li;
00067 
00068   // Mask off any bits before `position' in the first limb.
00069   mp_limb_t limb
00070     = *p & ((~static_cast<mp_limb_t>(0)) << (position % PPL_BITS_PER_GMP_LIMB));
00071 
00072   while (true) {
00073     if (limb != 0)
00074       return static_cast<unsigned long>(li) * PPL_BITS_PER_GMP_LIMB
00075         + Implementation::first_one(limb);
00076     ++li;
00077     if (li == vec_size)
00078       break;
00079     ++p;
00080     limb = *p;
00081   }
00082   return C_Integer<unsigned long>::max;
00083 }
00084 
00085 unsigned long
00086 PPL::Bit_Row::last() const {
00087   mp_size_t li = vec->_mp_size;
00088   PPL_ASSERT(li >= 0);
00089   if (li == 0)
00090     return C_Integer<unsigned long>::max;
00091   --li;
00092   const mp_srcptr p = vec->_mp_d + li;
00093   const mp_limb_t limb = *p;
00094   PPL_ASSERT(limb != 0);
00095   return static_cast<unsigned long>(li) * PPL_BITS_PER_GMP_LIMB
00096     + Implementation::last_one(limb);
00097 }
00098 
00099 unsigned long
00100 PPL::Bit_Row::prev(unsigned long position) const {
00101   if (position == 0)
00102     return C_Integer<unsigned long>::max;
00103 
00104   --position;
00105 
00106   const mp_size_t vec_size = vec->_mp_size;
00107   PPL_ASSERT(vec_size > 0);
00108   const unsigned long uli = position / PPL_BITS_PER_GMP_LIMB;
00109   mp_size_t li = static_cast<mp_size_t>(uli);
00110 
00111   mp_limb_t limb;
00112   mp_srcptr p = vec->_mp_d;
00113 
00114   // Get the first limb.
00115   if (li >= vec_size) {
00116     li = vec_size - 1;
00117     p += li;
00118     limb = *p;
00119   }
00120   else {
00121     const mp_limb_t mask
00122       = (~static_cast<mp_limb_t>(0))
00123       >> (PPL_BITS_PER_GMP_LIMB - 1U - position % PPL_BITS_PER_GMP_LIMB);
00124     p += li;
00125     limb = *p & mask;
00126   }
00127 
00128   while (true) {
00129     if (limb != 0)
00130       return static_cast<unsigned long>(li) * PPL_BITS_PER_GMP_LIMB 
00131         + Implementation::last_one(limb);
00132     if (li == 0)
00133       break;
00134     --li;
00135     --p;
00136     limb = *p;
00137   }
00138   return C_Integer<unsigned long>::max;
00139 }
00140 
00141 bool
00142 PPL::Bit_Row::operator[](const unsigned long k) const {
00143   const mp_size_t vec_size = vec->_mp_size;
00144   PPL_ASSERT(vec_size >= 0);
00145 
00146   unsigned long i = k / static_cast<unsigned long>(GMP_NUMB_BITS);
00147   if (i >= static_cast<unsigned long>(vec_size))
00148     return false;
00149 
00150   mp_limb_t limb = *(vec->_mp_d + i);
00151   return ((limb >> (k % static_cast<unsigned long>(GMP_NUMB_BITS))) & 1U) != 0;
00152 }
00153 
00154 void
00155 PPL::Bit_Row::set_until(unsigned long k) {
00156   // FIXME, TODO: this is an inefficient implementation.
00157   while (k-- > 0)
00158     mpz_setbit(vec, k);
00159 }
00160 
00162 int
00163 PPL::compare(const Bit_Row& x, const Bit_Row& y) {
00164   const mp_size_t x_size = x.vec->_mp_size;
00165   PPL_ASSERT(x_size >= 0);
00166   const mp_size_t y_size = y.vec->_mp_size;
00167   PPL_ASSERT(y_size >= 0);
00168   mp_size_t size = ((x_size > y_size) ? y_size : x_size);
00169   mp_srcptr xp = x.vec->_mp_d;
00170   mp_srcptr yp = y.vec->_mp_d;
00171   while (size > 0) {
00172     const mp_limb_t xl = *xp;
00173     const mp_limb_t yl = *yp;
00174     if (xl != yl) {
00175       // Get the ones where they are different.
00176       const mp_limb_t diff = xl ^ yl;
00177       // First bit that is different.
00178       const mp_limb_t mask = diff & ~(diff-1);
00179       return ((xl & mask) != 0) ? 1 : -1;
00180     }
00181     ++xp;
00182     ++yp;
00183     --size;
00184   }
00185   return (x_size == y_size) ? 0 : ((x_size > y_size) ? 1 : -1);
00186 }
00187 
00189 bool
00190 PPL::subset_or_equal(const Bit_Row& x, const Bit_Row& y) {
00191   mp_size_t x_size = x.vec->_mp_size;
00192   PPL_ASSERT(x_size >= 0);
00193   mp_size_t y_size = y.vec->_mp_size;
00194   PPL_ASSERT(y_size >= 0);
00195   if (x_size > y_size)
00196     return false;
00197   mp_srcptr xp = x.vec->_mp_d;
00198   mp_srcptr yp = y.vec->_mp_d;
00199   while (x_size > 0) {
00200     if ((*xp & ~*yp) != 0)
00201       return false;
00202     ++xp;
00203     ++yp;
00204     --x_size;
00205   }
00206   return true;
00207 }
00208 
00210 bool
00211 PPL::subset_or_equal(const Bit_Row& x, const Bit_Row& y,
00212                      bool& strict_subset) {
00213   mp_size_t x_size = x.vec->_mp_size;
00214   PPL_ASSERT(x_size >= 0);
00215   mp_size_t y_size = y.vec->_mp_size;
00216   PPL_ASSERT(y_size >= 0);
00217   if (x_size > y_size)
00218     return false;
00219   mp_srcptr xp = x.vec->_mp_d;
00220   mp_srcptr yp = y.vec->_mp_d;
00221   strict_subset = (x_size < y_size);
00222   mp_limb_t xl;
00223   mp_limb_t yl;
00224   if (strict_subset) {
00225     while (x_size > 0) {
00226       xl = *xp;
00227       yl = *yp;
00228       if ((xl & ~yl) != 0)
00229         return false;
00230     strict_subset_next:
00231       ++xp;
00232       ++yp;
00233       --x_size;
00234     }
00235   }
00236   else {
00237     while (x_size > 0) {
00238       xl = *xp;
00239       yl = *yp;
00240       if (xl != yl) {
00241         if ((xl & ~yl) != 0)
00242           return false;
00243         strict_subset = true;
00244         goto strict_subset_next;
00245       }
00246       ++xp;
00247       ++yp;
00248       --x_size;
00249     }
00250   }
00251   return true;
00252 }
00253 
00255 bool
00256 PPL::strict_subset(const Bit_Row& x, const Bit_Row& y) {
00257   mp_size_t x_size = x.vec->_mp_size;
00258   PPL_ASSERT(x_size >= 0);
00259   mp_size_t y_size = y.vec->_mp_size;
00260   PPL_ASSERT(y_size >= 0);
00261   if (x_size > y_size)
00262     return false;
00263   bool different = (x_size < y_size);
00264   mp_srcptr xp = x.vec->_mp_d;
00265   mp_srcptr yp = y.vec->_mp_d;
00266   while (x_size > 0) {
00267     const mp_limb_t xl = *xp;
00268     const mp_limb_t yl = *yp;
00269     if ((xl & ~yl) != 0)
00270       return false;
00271     if (!different && xl != yl)
00272       different = true;
00273     ++xp;
00274     ++yp;
00275     --x_size;
00276   }
00277   return different;
00278 }
00279 
00281 bool
00282 PPL::operator==(const Bit_Row& x, const Bit_Row& y) {
00283   const mp_size_t x_vec_size = x.vec->_mp_size;
00284   PPL_ASSERT(x_vec_size >= 0);
00285   const mp_size_t y_vec_size = y.vec->_mp_size;
00286   PPL_ASSERT(y_vec_size >= 0);
00287 
00288   if (x_vec_size != y_vec_size)
00289     return false;
00290 
00291   return mpn_cmp(x.vec->_mp_d, y.vec->_mp_d, x_vec_size) == 0;
00292 }
00293 
00295 bool
00296 PPL::operator!=(const Bit_Row& x, const Bit_Row& y) {
00297   const mp_size_t x_vec_size = x.vec->_mp_size;
00298   PPL_ASSERT(x_vec_size >= 0);
00299   const mp_size_t y_vec_size = y.vec->_mp_size;
00300   PPL_ASSERT(y_vec_size >= 0);
00301 
00302   if (x_vec_size != y_vec_size)
00303     return true;
00304 
00305   return mpn_cmp(x.vec->_mp_d, y.vec->_mp_d, x_vec_size) != 0;
00306 }
00307 
00308 bool
00309 PPL::Bit_Row::OK() const {
00310   const mp_size_t vec_size = vec->_mp_size;
00311   const mp_size_t vec_alloc = vec->_mp_alloc;
00312   return vec_size >= 0
00313     && vec_alloc >= vec_size
00314     && (vec_size == 0 || mpz_getlimbn(vec, vec_size-1) != 0);
00315 }
00316 
00317 void
00318 PPL::Bit_Row::union_helper(const Bit_Row& y, const Bit_Row& z) {
00319   mp_size_t y_size = y.vec->_mp_size;
00320   mp_size_t z_size = z.vec->_mp_size;
00321   PPL_ASSERT(y_size <= z_size);
00322   PPL_ASSERT(vec->_mp_alloc >= z_size);
00323   vec->_mp_size = z.vec->_mp_size;
00324   mp_srcptr yp = y.vec->_mp_d;
00325   mp_srcptr zp = z.vec->_mp_d;
00326   mp_ptr p = vec->_mp_d;
00327   z_size -= y_size;
00328   while (y_size > 0) {
00329     *p = *yp | * zp;
00330     ++yp;
00331     ++zp;
00332     ++p;
00333     --y_size;
00334   }
00335   while (z_size > 0) {
00336     *p = *zp;
00337     ++zp;
00338     ++p;
00339     --z_size;
00340   }
00341 }