Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members

BitVector.C

Go to the documentation of this file.
00001 // Copyright (C) 2001, Compaq Computer Corporation
00002 // 
00003 // This file is part of Vesta.
00004 // 
00005 // Vesta is free software; you can redistribute it and/or
00006 // modify it under the terms of the GNU Lesser General Public
00007 // License as published by the Free Software Foundation; either
00008 // version 2.1 of the License, or (at your option) any later version.
00009 // 
00010 // Vesta is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013 // Lesser General Public License for more details.
00014 // 
00015 // You should have received a copy of the GNU Lesser General Public
00016 // License along with Vesta; if not, write to the Free Software
00017 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018 
00019 // Last modified on Sat Aug 13 00:31:27 EDT 2005 by ken@xorian.net         
00020 //      modified on Mon Jun 27 11:37:45 EDT 2005 by irina.furman@intel.com 
00021 //      modified on Sun Jul 28 11:55:57 EDT 2002 by lken@remote.xorian.net 
00022 //      modified on Sat Feb 12 12:02:15 PST 2000 by mann  
00023 //      modified on Tue Apr 13 14:10:13 PDT 1999 by heydon
00024 
00025 #include <Basics.H>
00026 #include <FS.H>
00027 #include <SRPC.H>
00028 #include <VestaLog.H>
00029 #include <Recovery.H>
00030 #include <BufStream.H>
00031 #include "BitVector.H"
00032 
00033 using std::endl;
00034 using Basics::OBufStream;
00035 
00036 /* When "BV_DEBUG" is defined, extra checks are performed to guarantee that
00037    the BitVector invariants are satisfied. These extra checks involve work
00038    that would still be performed even if assertion checking was disabled. */
00039 #define BV_DEBUG
00040 
00041 static const Word Zero = 0UL;
00042 static const Word One = 1UL;
00043 static const Word AllOnes = ~Zero;
00044 
00045 // Read-only after initialization by BitVectorInit::BitVectorInit()
00046 static int BitsPerWd = -1;   // number of bits per word
00047 static int BytesPerWd;       // number of bytes per word (== "BitsPerWd / 8")
00048 static int LogBitsPerWd;     // log (base 2) of "BitsPerWd"
00049 static int LowBitsMask;
00050 static Word *BitMask = NULL;
00051 
00052 
00053 /* The above values are initialized by the BitVectorInit
00054    constructor. They are read-only after initialization. The meanings
00055    of the first three variables are described by their comments above.
00056 
00057    "LowBitsMask" is a bit mask whose low-order "LogBitsPerWd" bits are set
00058    (with all other bits reset). Hence, for all non-negative integers "i", we
00059    have: 
00060 
00061 |    i / BitsPerWd == i >> LogBitsPerWd
00062 |    i % BitsPerWd == i & LowBitsMask
00063 
00064    "BitMask" points to an array of "BitsPerWd" masks. There is one mask per
00065    bit; where "BitMask[i] = 1 << i" for "0 <= i < BitsPerWd".
00066 
00067    "IntrvlMask" acts like an array of "2 * BitsPerWd - 1" masks. For "i" in
00068    the interval "[-(BitsPerWd-1), (BitsPerWd-1)]", we have:
00069 
00070 |    IntrvlMask[i] == AllOnes << i
00071 
00072    Notice that the index to the "IntrvlMask" array can be negative. A negative
00073    left shift is equivalent to a right shift of the negation of the shift
00074    amount, i.e., if "i < 0", then "IntrvlMask[i] == AllOnes >> (-i)". */
00075 
00076 inline short WdIndex(int n) throw ()
00077 /* Return "n DIV BitsPerWd". This is the index of the word that contains
00078    the bit numbered "n". */
00079 {
00080     return (short)(n >> LogBitsPerWd);
00081 }
00082 
00083 inline short BitIndex(int n) throw ()
00084 /* Return "n % BitsPerWd". This is the index of bit "n" within its word. */
00085 {
00086     return (short)(n & LowBitsMask);
00087 }
00088 
00089 inline short WdCnt(int n) throw ()
00090 /* Return ceiling(n / BitsPerWd). This is the number of words required
00091    to hold a total of "n" bits. */
00092 {
00093     return WdIndex(n + BitsPerWd - 1);
00094 }
00095 
00096 class BitVectorInit {
00097   public:
00098     BitVectorInit() throw ();
00099     // initialize the "BitVector" module
00100 };
00101 
00102 static BitVectorInit bitVectorInit;
00103 
00104 // This class implements "IntrvlMask" (described above). 
00105 class IntervalMask
00106 {
00107 private:
00108   // "mask" actually points to the lowest entry (corresponding to the
00109   // index -(BitsPerWd-1)).  This is neccessary for the garbage
00110   // collector to see a valid reference to the block and not collect
00111   // it as garbage.
00112   static Word* mask;
00113 
00114 public:
00115   // Init is separate from the constructor because it depends on
00116   // BitsPerWd
00117   static void Init() 
00118   {
00119     mask = NEW_PTRFREE_ARRAY(Word, (2 * BitsPerWd) - 1);
00120     Word* mask_middle = mask + (BitsPerWd - 1);
00121     Word left, right;
00122     mask_middle[0] = left = right = AllOnes;
00123     for (int i = 1; i < BitsPerWd; i++) {
00124       mask_middle[i] = (left <<= 1);
00125       mask_middle[-i] = (right >>= 1);
00126     }
00127   }
00128 
00129   Word operator[](int index)
00130   {
00131     // Note: assumes Init has already been called!
00132     return mask[(BitsPerWd - 1) + index];
00133   }
00134 };
00135 
00136 Word* IntervalMask::mask = 0;
00137 
00138 // The sole instance of class IntervalMask
00139 static IntervalMask IntrvlMask;
00140 
00141 BitVectorInit::BitVectorInit() throw ()
00142 /* Initialize the global variables of this module for this architecture. */
00143 {
00144     assert(BitsPerWd < 0);
00145     int i;
00146     Word wd;
00147     
00148     // initialize "BitsPerWd", "BytesPerWd"
00149     for (BitsPerWd = 0, wd = One; wd != Zero; wd <<= 1) BitsPerWd++;
00150     BytesPerWd = BitsPerWd / 8;
00151     
00152     // initialize "LogBitsPerWd"
00153     for (LogBitsPerWd = 0, wd = One; wd < BitsPerWd; wd <<= 1) {
00154         LogBitsPerWd++;
00155     }
00156     
00157     // initialize "LowBitsMask"
00158     LowBitsMask = (short)(BitsPerWd - 1);
00159     
00160     // initialize "BitMask"
00161     BitMask = NEW_PTRFREE_ARRAY(Word, BitsPerWd);
00162     for (i = 0, wd = One; i < BitsPerWd; i++, wd <<= 1) BitMask[i] = wd;
00163     
00164     // initialize "IntrvlMask"
00165     IntervalMask::Init();
00166 }
00167 
00168 // Constructors/destructors ---------------------------------------------------
00169 
00170 void BitVector::Init(int sizeHint, bool doZero) throw ()
00171 {
00172     assert(this->sz == 0 && this->firstAvailWd == 0);
00173     assert(sizeHint >= 0);
00174     short wdCnt = WdCnt(sizeHint);
00175     if (wdCnt > this->numWords) {
00176         Extend(wdCnt, /*doPreserve=*/ false);
00177     }
00178     if (doZero) {
00179         for (int i = 0; i < this->numWords; i++) {
00180             this->word[i] = Zero;
00181         }
00182     }
00183 }
00184 
00185 BitVector::BitVector(const BitVector *bv) throw ()
00186 : numWords(0), firstAvailWd(0), sz(0), word((Word *)NULL)
00187 {
00188     // invoke assignment operator
00189     *this = *bv;
00190 }
00191 
00192 // Extend/Reduce methods ------------------------------------------------------
00193 
00194 void BitVector::Extend(short wordCnt, bool doPreserve /*=true*/) throw ()
00195 {
00196     assert(wordCnt > this->numWords);
00197     short newNumWords = max(wordCnt, 2U * this->numWords);
00198     Word *newWord = NEW_PTRFREE_ARRAY(Word, newNumWords);
00199 
00200     // preserve bit vector if necessary
00201     if (doPreserve) {
00202         // copy old buffer to new if necessary
00203         if (this->word != NULL) {
00204             memcpy((char *)newWord, (char *)(this->word),
00205               this->numWords * BytesPerWd);
00206             delete this->word;
00207         }
00208 
00209         // zero out new high words
00210         for (short i = this->numWords; i < newNumWords; i++) {
00211             newWord[i] = Zero;
00212         }
00213     }
00214 
00215     // switch to new buffer
00216     this->numWords = newNumWords;
00217     this->word = newWord;
00218 }
00219 
00220 void BitVector::ExpandSz(int i, short wx) throw ()
00221 {
00222     i++;
00223     if (wx < this->numWords) {
00224         // fast path -- we already have enough words
00225         this->sz = max(this->sz, i);
00226     } else {
00227         // slow path -- extend "word" array
00228         Extend(wx + 1);
00229         this->sz = i;
00230     }
00231 }
00232 
00233 void BitVector::ReduceSz() throw ()
00234 {
00235     short lastWd = WdCnt(this->sz) - 1;
00236     assert(lastWd < this->numWords);
00237     short i;
00238     for (i = lastWd; i >= 0 && this->word[i] == Zero; i--) /* SKIP */;
00239     this->sz = min(this->sz, ((int)(i+1)) * BitsPerWd);
00240     assert(this->firstAvailWd * BitsPerWd <= this->sz);
00241 }
00242 
00243 // Read/Write methods ---------------------------------------------------------
00244 
00245 bool BitVector::IsEmpty() const throw ()
00246 {
00247     // do constant-time checks first
00248     if (this->sz == 0) return true;
00249     if (this->firstAvailWd > 0) return false;
00250 
00251     // otherwise, iterate over all candidate words in the bit vector
00252     short inUseWds = WdCnt(this->sz);
00253     assert(inUseWds > 0 && this->word != (Word *)NULL);
00254     for (short i = 0; i < inUseWds; i++) {
00255         if (this->word[i] != Zero) return false;
00256     }
00257     /* The following is correct, but would require "IsEmpty" to be
00258        a non-const method. It is a benign side-effect in the case
00259        where the bit vector is empty. */
00260     // this->sz = 0;
00261     return true;
00262 }
00263 
00264 // BitCnt[i] is the number of bits set in the binary representation of
00265 // the 8-bit value 'i'.
00266 static const short BitCnt[256] = {
00267   /*   0 */  0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
00268   /*  16 */  1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
00269   /*  32 */  1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
00270   /*  48 */  2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
00271   /*  64 */  1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
00272   /*  80 */  2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
00273   /*  96 */  2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
00274   /* 112 */  3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
00275   /* 128 */  1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
00276   /* 144 */  2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
00277   /* 160 */  2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
00278   /* 176 */  3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
00279   /* 192 */  2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
00280   /* 208 */  3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
00281   /* 224 */  3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
00282   /* 240 */  4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
00283 };
00284 static const int ByteMask = 0xff;
00285 
00286 int BitVector::Cardinality() const throw ()
00287 {
00288     // do constant-time checks first
00289     if (this->sz == 0) return 0;
00290 
00291     // iterate over words in bit vector
00292     short inUseWds = WdCnt(this->sz);
00293     int res = ((int)(this->firstAvailWd)) * BitsPerWd;
00294     for (short i = this->firstAvailWd; i < inUseWds; i++) {
00295         for (register Word wd = this->word[i]; wd != Zero; wd >>= 8) {
00296             res += (int)(BitCnt[wd & ByteMask]);
00297         }
00298     }
00299     return res;
00300 }
00301 
00302 bool BitVector::Read(int i) const throw ()
00303 {
00304     if (i >= this->sz) return false;
00305     short wx = WdIndex(i);
00306     if (wx < this->firstAvailWd) return true;
00307     return ((this->word[wx] & BitMask[BitIndex(i)]) != Zero);
00308 }
00309 
00310 Word BitVector::ReadWord(int start, short len) const throw ()
00311 {
00312     Word res;
00313     assert(len <= BitsPerWd);
00314     if (start >= this->sz) return Zero;
00315     short startWd = WdIndex(start);
00316     short startBit = BitIndex(start);
00317     assert(startWd < this->numWords);
00318     if (startBit + len <= BitsPerWd) {
00319         // fast path -- bits all in one word
00320         Word mask = IntrvlMask[len - BitsPerWd];   // "len" 1's in low bits
00321         res = (this->word[startWd] >> startBit) & mask;
00322     } else {
00323         // slow path -- bits span word boundary
00324         short loLen = BitsPerWd - startBit;
00325         short hiLen = len - loLen;
00326         Word loMask = IntrvlMask[loLen - BitsPerWd]; // "loLen" 1's in low bits
00327         res = (this->word[startWd] >> startBit) & loMask;
00328         startWd++; // move on to next word
00329         if (startWd < WdCnt(this->sz)) {
00330             assert(startWd < this->numWords);
00331             Word hiMask = IntrvlMask[hiLen - BitsPerWd];
00332             int hiBits = this->word[startWd] & hiMask;
00333             res |= (hiBits << loLen);
00334         }
00335     }
00336     return res;
00337 }
00338 
00339 void BitVector::WriteWord(int start, short len, Word val) throw ()
00340 {
00341     assert(len <= BitsPerWd);
00342     short startWd = WdIndex(start);
00343     short startBit = BitIndex(start);
00344     int end = (start + len) - 1; // index of last bit being set
00345     short endWd = WdIndex(end);
00346 
00347     // update "sz", "firstAvailWd" -- extend bit vector if necessary
00348     ExpandSz(end, endWd);
00349     this->firstAvailWd = min(this->firstAvailWd, start);
00350 
00351     // set the bits
00352     if (startWd == endWd) {
00353         // fast path -- bits all in one word
00354         assert(startBit + len <= BitsPerWd);
00355         Word mask = IntrvlMask[len - BitsPerWd];
00356         val &= mask;                    // clear any unwanted bits in "val"
00357         mask <<= startBit;              // shift mask up to proper position
00358         this->word[startWd] &= ~mask;   // reset target bits
00359         this->word[startWd] |= (val << startBit);
00360     } else {
00361         // slow path -- bits span word boundary
00362         short loLen = BitsPerWd - startBit;
00363         short hiLen = len - loLen;
00364         Word loMask = IntrvlMask[BitsPerWd - loLen];
00365         Word hiMask = IntrvlMask[hiLen - BitsPerWd];
00366 
00367         // lo word
00368         this->word[startWd] &= ~loMask;
00369         this->word[startWd] |= (val << startBit);
00370 
00371         // hi word
00372         startWd++; // move on to next word
00373         assert(startWd < this->numWords);
00374         Word hiVal = (val >> loLen) & hiMask; // clear any unwanted bits
00375         this->word[startWd] &= ~hiMask;
00376         this->word[startWd] |= hiVal;
00377     }
00378 }
00379 
00380 bool BitVector::Set(int i) throw ()
00381 {
00382     register short wx = WdIndex(i), bx = BitIndex(i);
00383     ExpandSz(i, wx);
00384     assert(wx < this->numWords);
00385     bool res = ((this->word[wx] & BitMask[bx]) != Zero);
00386     if (!res) { this->word[wx] |= BitMask[bx]; }
00387     return res;
00388 }
00389 
00390 bool BitVector::Reset(int i) throw ()
00391 {
00392     register short wx = WdIndex(i), bx = BitIndex(i);
00393     bool res;
00394     if (i < this->sz) {
00395         assert(wx < this->numWords);
00396         res = ((this->word[wx] & BitMask[bx]) != Zero);
00397         if (res) {
00398             this->word[wx] &= ~(BitMask[bx]);
00399             this->firstAvailWd = min(this->firstAvailWd, wx);
00400         }
00401     } else {
00402         res = false;
00403     }
00404     return res;
00405 }
00406 
00407 void BitVector::SetInterval(int lo, int hi) throw ()
00408 {
00409     short wxLo = WdIndex(lo), bxLo = BitIndex(lo);
00410     short wxHi = WdIndex(hi), bxHi = BitIndex(hi);
00411 
00412     // extend "sz" (and "word" if necessary)
00413     ExpandSz(hi, wxHi);
00414     assert(wxHi < this->numWords);
00415 
00416     // set the bits
00417     if (wxLo == wxHi) {
00418         // all bits in single word
00419         Word mask = IntrvlMask[(bxHi-bxLo+1) - BitsPerWd] << bxLo;
00420         this->word[wxLo] |= mask;
00421     } else {
00422         // bits span multiple words
00423         register short i;
00424 
00425         // partial low word
00426         if (wxLo < this->firstAvailWd ||
00427             (bxLo == 0 && wxLo == this->firstAvailWd)) {
00428             // low bits are already set by I4
00429             i = this->firstAvailWd;
00430             /* (The next statement anticipates the final result; it is
00431                not true at this instant.) */
00432             this->firstAvailWd = max(this->firstAvailWd, wxHi);
00433             assert(this->firstAvailWd * BitsPerWd <= this->sz);
00434         } else {
00435             // normal case
00436             this->word[wxLo] |= IntrvlMask[bxLo];
00437             i = wxLo + 1;
00438         }
00439 
00440         // middle full words
00441         while (i < wxHi) {
00442             this->word[i++] = AllOnes;
00443         }
00444 
00445         // partial hi word
00446         if (i == wxHi) { // guard needed in case "this->firstAvailWd > wxHi"
00447             this->word[i] |= IntrvlMask[(bxHi+1) - BitsPerWd];
00448         }
00449     }
00450 }
00451 
00452 void BitVector::ResetInterval(int lo, int hi) throw ()
00453 {
00454     // reduce "hi" if necessary by I3
00455     hi = min(hi, this->sz - 1);
00456 
00457     if (lo <= hi) {
00458         short wxLo = WdIndex(lo), bxLo = BitIndex(lo);
00459         short wxHi = WdIndex(hi), bxHi = BitIndex(hi);
00460 
00461         // reset the bits
00462         assert(wxHi < this->numWords);
00463         if (wxLo == wxHi) {
00464             // all bits in single word
00465             Word mask = IntrvlMask[(bxHi-bxLo+1) - BitsPerWd] << bxLo;
00466             this->word[wxLo] &= ~mask;
00467         } else {
00468             // bits span multiple words
00469             register short i;
00470 
00471             // partial low word
00472             this->word[wxLo] &= ~(IntrvlMask[bxLo]);
00473             i = wxLo + 1;
00474 
00475             // middle full words
00476             while (i < wxHi) {
00477                 this->word[i++] = Zero;
00478             }
00479 
00480             // partial hi word
00481             Word mask = IntrvlMask[(bxHi+1) - BitsPerWd];
00482             this->word[i] &= ~mask;
00483         }
00484 
00485         // reduce "this->sz" if possible
00486         if (hi == this->sz - 1) {
00487             this->sz = min(this->sz, lo);
00488         }
00489 
00490         // reduce "this->firstAvailWd" if necessary
00491         this->firstAvailWd = min(this->firstAvailWd, wxLo);
00492     }
00493 }
00494 
00495 void BitVector::ResetAll(bool freeMem) throw ()
00496 {
00497     if (this->word != NULL) {
00498         if (freeMem) {
00499             // maintain I1
00500             delete this->word;
00501             this->word = (Word *)NULL;
00502             this->numWords = 0;
00503         } else {
00504             // maintain I3
00505             short wdCnt = WdCnt(this->sz);
00506             assert(wdCnt <= this->numWords);
00507             for (short i = 0; i < wdCnt; i++) {
00508                 this->word[i] = Zero;
00509             }
00510         }
00511     }
00512     this->sz = 0;
00513 
00514     // maintain I4
00515     this->firstAvailWd = 0;
00516 }
00517 
00518 const Word Magic = CONST_INT_64(0x07edd5e59a4e28c2);
00519 const int MagicTable[] = {
00520   63, 0, 58, 1, 59, 47, 53, 2, 60, 39, 48, 27, 54, 33, 42, 3, 61, 51, 37,
00521   40, 49, 18, 28, 20, 55, 30, 34, 11, 43, 14, 22, 4, 62, 57, 46, 52, 38, 26,
00522   32, 41, 50, 36, 17, 19, 29, 10, 13, 21, 56, 45, 25, 31, 35, 16, 9, 12, 44,
00523   24, 15, 8, 23, 7, 6, 5
00524 };
00525 
00526 int BitVector::NextAvailExcept(BitVector *except, bool setIt) throw ()
00527 {
00528     int res;
00529     short maxWdExc; // only valid if "except != NULL"
00530     short wx = this->firstAvailWd; // word in which result bit will be set
00531 
00532     // find first word containing any 0's
00533     short maxWd = WdCnt(this->sz);
00534     while ((wx < maxWd) && (this->word[wx] == AllOnes)) wx++;
00535     this->firstAvailWd = wx;
00536 
00537     // advance further if "except != NULL"
00538     if (except != (BitVector *)NULL) {
00539         // advance "wx"
00540         wx = max(wx, except->firstAvailWd);
00541         maxWdExc = WdCnt(except->sz);
00542 
00543         // advance where both bit vectors are long enough
00544         short minWd = min(maxWd, maxWdExc);
00545         while ((wx < minWd) && ((this->word[wx] | except->word[wx])==AllOnes))
00546             wx++;
00547 
00548         // advance through longer of the two
00549         if (wx == minWd) {
00550             if (maxWdExc > maxWd) {
00551                 while ((wx < maxWdExc) && (except->word[wx] == AllOnes)) wx++;
00552             } else if (maxWd > maxWdExc) {
00553                 while ((wx < maxWd) && (this->word[wx] == AllOnes)) wx++;
00554             }
00555         }
00556     }
00557 
00558     // compute word in which to find 0
00559     res = ((int)wx) * BitsPerWd;
00560     Word wd = (wx < maxWd) ? this->word[wx] : Zero;
00561     if (except != NULL && wx < maxWdExc) {
00562         wd |= except->word[wx];
00563     }
00564     assert(wd != AllOnes);
00565 
00566     // find the first 0 in "wd"; set "bx" to its index within the word
00567     short bx = 0;
00568     if (wd != Zero) {
00569         // complement; now find a 1
00570         wd = ~wd;
00571         assert(wd != Zero);
00572 #ifdef SLOW
00573         short maskSz = BitsPerWd >> 1; // == BitsPerWd / 2
00574         Word mask = IntrvlMask[-maskSz];
00575         while (maskSz > 0) {
00576             if (!(wd & mask)) {
00577                 bx += maskSz; wd >>= maskSz;
00578             }
00579             maskSz >>= 1; mask >>= maskSz;
00580         }
00581 #endif
00582         wd = wd & ~(wd - 1); // reset all bits above least set bit
00583         bx = MagicTable[(wd * Magic) >> (BitsPerWd - LogBitsPerWd)];
00584         res += (int)bx;
00585     }
00586 
00587     // set the bit if necessary
00588     if (setIt) {
00589         ExpandSz(res, wx);
00590         this->word[wx] |= BitMask[bx];
00591     }
00592     return res;
00593 }
00594 
00595 int BitVector::MSB() const throw ()
00596 {
00597     // find the non-zero word with largest index
00598     short wx;
00599     short lastWd = WdCnt(this->sz) - 1; assert(lastWd < this->numWords);
00600     for (wx = lastWd; wx >= 0 && this->word[wx] == Zero; wx--) /*SKIP*/;
00601 
00602     // return immediately if vector is empty
00603     if (wx < 0) return -1;
00604 
00605     // use binary search to find MSB in "this->word[wx]"
00606     int res = ((int)wx) * BitsPerWd;
00607     Word w = this->word[wx]; assert(w != Zero);
00608     int maskSz = BitsPerWd >> 1; // == BitsPerWd / 2
00609     Word mask = IntrvlMask[maskSz];
00610     while (maskSz > 0) {
00611         if (w & mask) {
00612             res += maskSz; 
00613         } else {
00614             w <<= maskSz;
00615         }
00616         maskSz >>= 1; mask <<= maskSz;
00617     }
00618     return res;
00619 }
00620 
00621 void BitVector::Pack(const BitVector &m) throw ()
00622 /* REQUIRES SELF <= m */
00623 {
00624     short wdCnt = WdCnt(this->sz), mWdCnt = WdCnt(m.sz);
00625     assert(wdCnt <= this->numWords && mWdCnt <= m.numWords);
00626     short minWdCnt = min(wdCnt, mWdCnt);
00627 
00628     // we only have to consider bits in words at least "m.firstAvailWd"
00629     short wx = m.firstAvailWd;           // index of result word
00630 
00631     // return immediately if possible
00632     if (wx >= wdCnt) return;
00633 
00634     // otherwise, pack the bits
00635     const Word ZeroBit = BitMask[0];
00636     int bx = 0; Word thisBit = ZeroBit; // index and mask for result bit
00637     short mwx;                            // index of source word
00638     for (mwx = wx; mwx < minWdCnt; mwx++) {
00639         /* Loop invariants:
00640             I1. mwx < wdCnt && mwx < mWdCnt
00641             I2. wx <= mwx
00642             I3. thisBit = BitMask[bx]
00643         */
00644         int mbx;     // index of source bit within word "mwx"; like "bx"
00645         Word mBit;   // mask for source bit (see I4 below); like "thisBit"
00646         Word mMask;  // shifted word (see I5 below)
00647         for (mbx = 0, mMask = m.word[mwx], mBit = ZeroBit;
00648              mMask != Zero; mbx++, mMask >>= 1, mBit <<= 1) {
00649             /* Loop invariants:
00650                 I4. mBit == BitMask[mbx]
00651                 I5. mMask == m.word[mwx] >> mbx
00652             */
00653             if (mMask & ZeroBit) {
00654                 // set bit this(wx, thisBit) to this(mwx, mBit)
00655                 if (this->word[mwx] & mBit) {
00656                     // set the bit
00657                     this->word[wx] |= thisBit;
00658                 } else {
00659                     // reset the bit
00660                     this->word[wx] &= ~thisBit;
00661                 }
00662                 // advance (wx, thisBit)
00663                 bx++; thisBit <<= 1;
00664                 if (thisBit == Zero) {
00665                     bx = 0; thisBit = ZeroBit;
00666                     wx++;
00667                 }
00668             } else {
00669                 // check precondition
00670                 assert(!(this->word[mwx] & mBit));
00671             }
00672         }
00673 
00674         // if on the last source word...
00675         if (mwx == (minWdCnt - 1) && mbx < BitsPerWd) {
00676             // ...check that remainder of "this->word[mwx]" (if any) is zero
00677             assert((this->word[mwx] & IntrvlMask[mbx]) == Zero);
00678         }
00679     }
00680     assert(mwx == minWdCnt && wx <= mwx);
00681 
00682     // zero out bits in half-open interval [(wx, bx), (mwx, 0))
00683     if (wx < mwx) {
00684         this->word[wx] &= ~(IntrvlMask[bx]);               // rest of this word
00685         for (wx++; wx < mwx; wx++) this->word[wx] = Zero;  // whole words
00686     }
00687     assert(wx == mwx);
00688 
00689 #ifdef BV_DEBUG
00690     // check that remainder of bits in this bit vector are Zero
00691     for (/*SKIP*/; wx < wdCnt; wx++)
00692         assert(this->word[wx] == Zero);
00693 #endif // BV_DEBUG
00694 }
00695 
00696 BitVector& BitVector::operator = (const BitVector& bv) throw ()
00697 {
00698     short copyWds = WdCnt(bv.sz); // number of words to copy
00699     short lastNonZero; // upper bound on index of last word to be zeroed
00700 
00701     // allocate the words array
00702     if (copyWds > this->numWords) {
00703         Extend(copyWds, /*doPreserve=*/ false);
00704         // we have to zero all the way to end of the array
00705         lastNonZero = this->numWords;
00706     } else {
00707         /* We only have to zero up to the last word that might contain
00708            set bits; the words past that are zero by I3. */
00709         lastNonZero = WdCnt(this->sz);
00710     }
00711     assert(copyWds <= this->numWords && lastNonZero <= this->numWords);
00712 
00713     // update sizes
00714     this->sz = bv.sz;
00715     this->firstAvailWd = bv.firstAvailWd;
00716 
00717     // copy valid words and zero remaining ones
00718     short i;
00719     for (i = 0; i < copyWds; i++) { this->word[i] = bv.word[i]; }
00720     for (/*SKIP*/; i < lastNonZero; i++) { this->word[i] = Zero; }
00721 
00722 #ifdef BV_DEBUG
00723     // verify I3
00724     for (/*SKIP*/; i < this->numWords; i++)
00725         assert(this->word[i] == Zero);
00726 #endif // BV_DEBUG
00727 
00728     return *this;
00729 }
00730 
00731 // Bitwise operator methods ---------------------------------------------------
00732 
00733 bool operator == (const BitVector& bv1, const BitVector& bv2) throw ()
00734 {
00735     if (bv1.sz == 0) {
00736         return bv2.IsEmpty();
00737     } else if (bv2.sz == 0) {
00738         return bv1.IsEmpty();
00739     }
00740     assert((bv1.word != (Word *)NULL) && (bv2.word != (Word *)NULL));
00741     short wds1 = WdCnt(bv1.sz), wds2 = WdCnt(bv2.sz);
00742     short minWds = min(wds1, wds2);
00743     short firstWd = min(bv1.firstAvailWd, bv2.firstAvailWd);
00744 
00745     // check that words agree where they have words in common
00746     short i;
00747     for (i = firstWd; i < minWds; i++) {
00748         if (bv1.word[i] != bv2.word[i]) return false;
00749     }
00750 
00751     // check that remainder of longer word is all Zero
00752     if (wds1 > wds2) {
00753         for (/*SKIP*/; i < wds1; i++) {
00754             if (bv1.word[i] != Zero) return false;
00755         }
00756     } else if (wds2 > wds1) {
00757         for (/*SKIP*/; i < wds2; i++) {
00758             if (bv2.word[i] != Zero) return false;
00759         }
00760     }
00761     return true;
00762 }
00763 
00764 bool operator <= (const BitVector& bv1, const BitVector& bv2) throw ()
00765 /* The implementation works by first determining how many words "bv1" and
00766    "bv2" have in common. For each pair of words in common, we return false
00767    immediately if the word of "bv1" has a bit set that is not set in the
00768    corresponding word of "bv2". If "bv1" has more words than "bv2", we must
00769    then also check that all extra words of "bv1" are zero. */
00770 {
00771     // check for simple, special case
00772     if (bv1.sz == 0) return true;
00773     assert(bv1.word != (Word *)NULL);
00774 
00775     short wds1 = WdCnt(bv1.sz), wds2 = WdCnt(bv2.sz);
00776     short minWds = min(wds1, wds2);
00777 
00778     // Check that "bv1"'s bits are a subset of "bv2"'s for all common words;
00779     // we don't have to check the first "firstAvailWd" words of "bv2", since
00780     // all their bits are set, and so the corresponding words of "bv1" are
00781     // guaranteed to be a subset.
00782     short i;
00783     for (i = bv2.firstAvailWd; i < minWds; i++) {
00784         if (bv1.word[i] & ~(bv2.word[i])) return false;
00785     }
00786 
00787     // check that any extra words of "bv1" are zero
00788     for (/*SKIP*/; i < wds1; i++) {
00789         if (bv1.word[i] != Zero) return false;
00790     }
00791 
00792     // if both tests pass, return "true"
00793     return true;
00794 }
00795 
00796 bool operator < (const BitVector& bv1, const BitVector& bv2) throw ()
00797 {
00798     // check for special cases
00799     if (bv2.IsEmpty()) return false;
00800     if (bv1.IsEmpty()) return true;
00801     assert((bv1.word != (Word *)NULL) && (bv2.word != (Word *)NULL));
00802 
00803     /* First, check if there are any unset bits in the first
00804        "bv2.firstAvailWd" words of "bv1". The search can start
00805        at word "bv1.firstAvailWd" of "bv1" because all words
00806        before that are known to be all ones by I4. */
00807     short i;
00808     for (i = bv1.firstAvailWd; i < bv2.firstAvailWd; i++) {
00809         if (bv1.word[i] != AllOnes) return true;
00810     }
00811 
00812     // Next, look over words that agree
00813     short wds1 = WdCnt(bv1.sz), wds2 = WdCnt(bv2.sz);
00814     short minWds = min(wds1, wds2);
00815     for (/*SKIP*/; i < minWds; i++) {
00816         if (bv1.word[i] & ~(bv2.word[i])) return false;
00817         // now, every bit set in "bv1.word[i]" is also set in "bv2.word[i]"
00818         if (bv1.word[i] != bv2.word[i]) return true;
00819     }
00820 
00821     // common words are equal; check for set bits in bv2 not set in bv1
00822     for (/*SKIP*/; i < wds2; i++) {
00823         if (bv2.word[i] != Zero) return true;
00824     }
00825     return false;
00826 }
00827 
00828 BitVector* operator & (const BitVector& bv1, const BitVector& bv2) throw ()
00829 {
00830     int newSz = min(bv1.sz, bv2.sz);
00831     BitVector *res = NEW_CONSTR(BitVector, (newSz, /*doZero =*/ false));
00832 
00833     // initialize sizes
00834     res->sz = newSz;
00835     res->firstAvailWd = min(bv1.firstAvailWd, bv2.firstAvailWd);
00836     assert(res->firstAvailWd * BitsPerWd <= res->sz);
00837 
00838     short i, wdCnt1 = WdCnt(bv1.sz), wdCnt2 = WdCnt(bv2.sz);
00839     if (newSz > 0) { // work only necessary if both non-empty
00840         // set initial "firstAvailWd" words
00841         assert(res->firstAvailWd <= res->numWords);
00842         for (i = 0; i < res->firstAvailWd; i++) {
00843             res->word[i] = AllOnes;
00844         }
00845 
00846         // compute conjunction for words in common
00847         short minWds = min(wdCnt1, wdCnt2);
00848         assert(minWds <= res->numWords);
00849         for (/*SKIP*/; i < minWds; i++) {
00850             res->word[i] = bv1.word[i] & bv2.word[i];
00851         }
00852     } else {
00853         assert(res->firstAvailWd == 0);
00854         i = 0;
00855     }
00856 
00857     // zero out the rest (in case "res->numWords > minWds")
00858     for (/*SKIP*/; i < res->numWords; i++) {
00859         res->word[i] = Zero;
00860     }
00861 
00862     // reduce size if any high-order Zero words
00863     res->ReduceSz();
00864     return res;
00865 }
00866 
00867 BitVector& BitVector::operator &= (const BitVector& bv) throw ()
00868 {
00869     short wdCnt = WdCnt(this->sz);
00870     if (wdCnt > 0) {            // work only necessary if *this is non-empty
00871         // set sizes
00872         short wdCnt2 = WdCnt(bv.sz);
00873         this->sz = min(this->sz, bv.sz);
00874         this->firstAvailWd = min(this->firstAvailWd, bv.firstAvailWd);
00875 
00876         // compute conjunction for words in common
00877         short i, minWds = min(wdCnt, wdCnt2);
00878         for (i = this->firstAvailWd; i < minWds; i++) {
00879             this->word[i] &= bv.word[i];
00880         }
00881 
00882         // zero the rest (in case this->numWords > bv.numWords)
00883         for (/*SKIP*/; i < wdCnt; i++) {
00884             this->word[i] = Zero;
00885         }
00886         ReduceSz();
00887     }
00888     return *this;
00889 }
00890 
00891 BitVector* operator | (const BitVector& bv1, const BitVector& bv2) throw ()
00892 {
00893     int newSz = max(bv1.sz, bv2.sz);
00894     BitVector *res = NEW_CONSTR(BitVector, (newSz, /*doZero =*/ false));
00895 
00896     // initialize sizes
00897     res->sz = newSz;
00898     res->firstAvailWd = max(bv1.firstAvailWd, bv2.firstAvailWd);
00899     assert(res->firstAvailWd * BitsPerWd <= res->sz);
00900 
00901     short i, wdCnt1 = WdCnt(bv1.sz), wdCnt2 = WdCnt(bv2.sz);
00902     if (newSz > 0) { // work only necessary if either non-empty
00903         // set initial "firstAvailWd" words
00904         assert(res->firstAvailWd <= res->numWords);
00905         for (i = 0; i < res->firstAvailWd; i++) {
00906             res->word[i] = AllOnes;
00907         }
00908 
00909         // compute disjunction for words in common
00910         short minWds = min(wdCnt1, wdCnt2);
00911         assert(minWds <= res->numWords);
00912         for (/*SKIP*/; i < minWds; i++) {
00913             res->word[i] = bv1.word[i] | bv2.word[i];
00914         }
00915 
00916         // copy from longer bit-vector
00917         short maxWds = max(wdCnt1, wdCnt2);
00918         assert(maxWds <= res->numWords);
00919         Word *wds = (wdCnt1 > wdCnt2) ? bv1.word : bv2.word;
00920         for (/*SKIP*/; i < maxWds; i++) {
00921             res->word[i] = wds[i];
00922         }
00923     } else {
00924         assert(res->firstAvailWd == 0);
00925         i = 0;
00926     }
00927 
00928     // zero out the rest (in case "res->numWords > maxWds")
00929     for (/*SKIP*/; i < res->numWords; i++) {
00930         res->word[i] = Zero;
00931     }
00932     return res;
00933 }
00934 
00935 BitVector& BitVector::operator |= (const BitVector& bv) throw ()
00936 {
00937     short wdCnt2 = WdCnt(bv.sz);
00938     if (wdCnt2 > 0) {           // work only necessary if "bv" is non-empty
00939         // extend "word" array if necessary
00940         if (wdCnt2 > this->numWords) Extend(wdCnt2);
00941         assert(wdCnt2 <= this->numWords);
00942 
00943         // update sizes
00944         this->sz = max(this->sz, bv.sz);
00945         short i = this->firstAvailWd;
00946         this->firstAvailWd = max(this->firstAvailWd, bv.firstAvailWd);
00947 
00948         // set more "firstAvailWd" words if necessary
00949         for (/*SKIP*/; i < this->firstAvailWd; i++) {
00950             this->word[i] = AllOnes;
00951         }
00952 
00953         // compute disjunction for words in common
00954         short wdCnt = WdCnt(this->sz);
00955         short minWds = min(wdCnt, wdCnt2);
00956         for (/*SKIP*/; i < minWds; i++) {
00957             this->word[i] |= bv.word[i];
00958         }
00959 
00960         // copy from "bv" if it is longer
00961         for (/*SKIP*/; i < wdCnt2; i++) {
00962             this->word[i] = bv.word[i];
00963         }
00964     }
00965     return *this;
00966 }
00967 
00968 BitVector* operator ^ (const BitVector& bv1, const BitVector& bv2) throw ()
00969 {
00970     int newSz = max(bv1.sz, bv2.sz);
00971     BitVector *res = NEW_CONSTR(BitVector, (newSz, /*doZero =*/ false));
00972 
00973     // initialize sizes
00974     res->sz = newSz;
00975     res->firstAvailWd = 0;
00976 
00977     short i;
00978     if (newSz > 0) {
00979         // compute exclusive-OR over common words
00980         short wdCnt1 = WdCnt(bv1.sz), wdCnt2 = WdCnt(bv2.sz);
00981         short minWds = min(wdCnt1, wdCnt2);
00982         for (i = 0; i < minWds; i++) {
00983             res->word[i] = bv1.word[i] ^ bv2.word[i];
00984         }
00985 
00986         // copy remaining words of longer vector
00987         if (wdCnt1 > wdCnt2) {
00988             assert(wdCnt1 <= res->numWords);
00989             for (/*SKIP*/; i < wdCnt1; i++) {
00990                 res->word[i] = bv1.word[i];
00991             }
00992         } else if (wdCnt2 > wdCnt1) {
00993             assert(wdCnt2 <= res->numWords);
00994             for (/*SKIP*/; i < wdCnt2; i++) {
00995                 res->word[i] = bv2.word[i];
00996             }
00997         }
00998     } else {
00999         i = 0;
01000     }
01001 
01002     // zero out the rest (in case constructor allocates more than necessary)
01003     for (/*SKIP*/; i < res->numWords; i++) {
01004         res->word[i] = Zero;
01005     }
01006     return res;
01007 }
01008 
01009 BitVector& BitVector::operator ^= (const BitVector& bv) throw ()
01010 {
01011     short wdCnt2 = WdCnt(bv.sz);
01012     if (wdCnt2 > 0) {           // work only necessary if "bv" is non-empty
01013         // extend "word" array if necessary
01014         if (wdCnt2 > this->numWords) Extend(wdCnt2);
01015         assert(wdCnt2 <= this->numWords);
01016 
01017         // initialize sizes
01018         this->sz = max(this->sz, bv.sz);
01019         this->firstAvailWd = 0;
01020 
01021         // compute XOR of words in common
01022         short i, wdCnt = WdCnt(this->sz);
01023         short minWds = min(wdCnt, wdCnt2);
01024         for (i = 0; i < minWds; i++) {
01025             this->word[i] ^= bv.word[i];
01026         }
01027 
01028         // if "bv" is longer, copy its words
01029         for (/*SKIP*/; i < wdCnt2; i++) {
01030             this->word[i] = bv.word[i];
01031         }
01032     }
01033     return *this;
01034 }
01035 
01036 BitVector* operator - (const BitVector& bv1, const BitVector& bv2) throw ()
01037 {
01038     int newSz = bv1.sz;   // the result is the same size as "bv1"
01039     BitVector *res = NEW_CONSTR(BitVector, (newSz, /*doZero =*/ false));
01040 
01041     // initialize sizes
01042     res->sz = newSz;
01043     res->firstAvailWd = 0;
01044 
01045     // subtract where they have words in common
01046     short i, wdCnt2 = WdCnt(bv2.sz);
01047     if (newSz > 0) {            // work only necessary if "bv1" is non-empty
01048         short wdCnt1 = WdCnt(bv1.sz);
01049         short minWds = min(wdCnt1, wdCnt2);
01050         assert(wdCnt1 <= res->numWords);
01051         for (i = 0; i < minWds; i++) {
01052             res->word[i] = bv1.word[i] & ~(bv2.word[i]);
01053         }
01054 
01055         // copy the rest from "bv1" (if any)
01056         for (/*SKIP*/; i < wdCnt1; i++) {
01057             res->word[i] = bv1.word[i];
01058         }
01059     } else {
01060         i = 0;
01061     }
01062 
01063     // zero out the rest (in case "res->numWords > wdCnt1")
01064     for (/*SKIP*/; i < res->numWords; i++) {
01065         res->word[i] = Zero;
01066     }
01067 
01068     // reduce size if any high-order Zero words
01069     res->ReduceSz();
01070     return res;
01071 }
01072 
01073 BitVector& BitVector::operator -= (const BitVector& bv) throw ()
01074 {
01075     short wdCnt2 = WdCnt(bv.sz);
01076     if (this->sz > 0 && wdCnt2 > 0) { // work only necessary if both non-empty
01077         // initialize sizes
01078         short wdCnt = WdCnt(this->sz);
01079         // this->sz is unchanged
01080         this->firstAvailWd = 0;
01081 
01082         // subtract where there are words in common
01083         short minWds = min(wdCnt, wdCnt2);
01084         for (short i = 0; i < minWds; i++) {
01085             this->word[i] &= ~(bv.word[i]);
01086         }
01087 
01088         // reduce size if any high-order Zero words
01089         this->ReduceSz();
01090     }
01091     return *this;
01092 }
01093 
01094 // I/O methods ----------------------------------------------------------------
01095 
01096 void BitVector::Log(VestaLog &log) const throw (VestaLog::Error)
01097 {
01098     // NB: only as many words as necessary are written
01099     short numUsedWords = WdCnt(this->sz);
01100     log.write((char *)(&numUsedWords), sizeof(numUsedWords));
01101     if (numUsedWords > 0) {
01102         log.write((char *)(&(this->firstAvailWd)), sizeof(this->firstAvailWd));
01103         log.write((char *)(&(this->sz)), sizeof(this->sz));
01104         log.write((char *)(this->word), numUsedWords * BytesPerWd);
01105     }
01106 }
01107 
01108 void BitVector::Recover(RecoveryReader &rd)
01109   throw (VestaLog::Error, VestaLog::Eof)
01110 {
01111     rd.readAll((char *)(&(this->numWords)), sizeof(this->numWords));
01112     if (this->numWords > 0) {
01113         rd.readAll((char *)(&(this->firstAvailWd)),sizeof(this->firstAvailWd));
01114         rd.readAll((char *)(&(this->sz)), sizeof(this->sz));
01115         this->word = NEW_PTRFREE_ARRAY(Word, this->numWords);
01116         rd.readAll((char *)(this->word), this->numWords * BytesPerWd);
01117     } else {
01118         this->firstAvailWd = 0;
01119         this->sz = 0;
01120         this->word = (Word *)NULL;
01121     }
01122 }
01123 
01124 void BitVector::Write(std::ostream &ofs) const throw (FS::Failure)
01125 {
01126     // NB: only as many words as necessary are written
01127     short numUsedWords = WdCnt(this->sz);
01128     FS::Write(ofs, (char *)(&numUsedWords), sizeof(numUsedWords));
01129     if (numUsedWords > 0) {
01130         FS::Write(ofs, (char *)(&(this->firstAvailWd)),
01131                   sizeof(this->firstAvailWd));
01132         FS::Write(ofs, (char *)(&(this->sz)), sizeof(this->sz));
01133         FS::Write(ofs, (char *)(this->word), numUsedWords * BytesPerWd);
01134     }
01135 }
01136 
01137 void BitVector::Read(std::istream &ifs) throw (FS::EndOfFile, FS::Failure)
01138 {
01139     FS::Read(ifs, (char *)(&(this->numWords)), sizeof(this->numWords));
01140     if (this->numWords > 0) {
01141         FS::Read(ifs, (char *)(&(this->firstAvailWd)),
01142                  sizeof(this->firstAvailWd));
01143         FS::Read(ifs, (char *)(&(this->sz)), sizeof(this->sz));
01144         this->word = NEW_PTRFREE_ARRAY(Word, this->numWords);
01145         FS::Read(ifs, (char *)(this->word), this->numWords * BytesPerWd);
01146     } else {
01147         this->firstAvailWd = 0;
01148         this->sz = 0;
01149         this->word = (Word *)NULL;
01150     }
01151 }
01152 
01153 void BitVector::Send(SRPC &srpc) const throw (SRPC::failure)
01154 {
01155     // NB: only as many words as necessary are written
01156     short numUsedWords = WdCnt(this->sz);
01157     srpc.send_short(numUsedWords);
01158     if (numUsedWords > 0) {
01159         srpc.send_short(this->firstAvailWd);
01160         srpc.send_int(this->sz);
01161         srpc.send_int64_array((const Basics::int64 *) this->word,
01162                               numUsedWords);
01163     }
01164 }
01165 
01166 void BitVector::Recv(SRPC &srpc) throw (SRPC::failure)
01167 {
01168     this->numWords = srpc.recv_short();
01169     if (this->numWords > 0) {
01170         this->firstAvailWd = srpc.recv_short();
01171         this->sz = srpc.recv_int();
01172         int len;
01173         this->word = (Word *) srpc.recv_int64_array(len);
01174         assert(this->numWords == len);
01175     } else {
01176         this->firstAvailWd = 0;
01177         this->sz = 0;
01178         this->word = (Word *)NULL;
01179     }
01180 }
01181 
01182 void BitVector::Print(std::ostream &os, int maxWidth) const throw ()
01183 // The output is written in hexidecimal, one byte at a time...
01184 {
01185     assert(maxWidth >= 30); // just to be safe
01186 
01187     // account for " (####### total)" at end of line
01188     maxWidth -= 16;
01189 
01190     short maxWd = WdCnt(this->sz);
01191     int widthWd = maxWidth / (2 * BytesPerWd);
01192     bool elided = (widthWd < maxWd);
01193     if (elided) {
01194         // recompute # of words to print, subtracting out space for
01195         // trailing "..."
01196         maxWidth -= 3;
01197         widthWd = maxWidth / (2 * BytesPerWd);
01198         maxWd = min(maxWd, widthWd);
01199     }
01200     if (maxWd == 0) { os << "<<Empty>>"; return; }
01201     for (short i = 0; i < maxWd; i++) {
01202         Word w = this->word[i];
01203         for (int j = 0; j < BytesPerWd; j++) {
01204             char buff[3];
01205             int printLen = sprintf(buff, "%02x", (unsigned int)(w & 0xff));
01206             assert(printLen == 2);
01207             os << buff;
01208             w >>= 8;
01209         }
01210     }
01211     if (elided) os << "...";
01212     os << " (" << this->Cardinality() << " total)";
01213 }
01214 
01215 inline void Indent(std::ostream &os, int indent) throw ()
01216 {
01217     for (int i = 0; i < indent; i++) os << ' ';
01218 }
01219 
01220 void ExtendRow(std::ostream &os, int indent, int maxWidth,
01221                const char *s, /*INOUT*/ int &col) throw ()
01222 {
01223   int s_len = strlen(s);
01224   if (col + s_len > maxWidth) {
01225     os << endl;
01226     Indent(os, indent);
01227     col = indent;
01228   }
01229   os << s << ' ';
01230   col += (s_len + 1);
01231 }
01232 
01233 void BitVector::PrintAll(std::ostream &os, int indent, int maxWidth) const throw ()
01234 {
01235   int lo = -2, prev = -2, curr, col = indent;
01236   BVIter iter(*this);
01237   Indent(os, indent);
01238   while (iter.Next(/*OUT*/ curr)) {
01239     // produce output if 'curr' does not extend a run
01240     if (curr > prev + 1) {
01241       // see if there is anything to print
01242       if (lo >= 0) {
01243         OBufStream s;
01244         s << lo;
01245         if (prev > lo) s << '-' << prev;
01246         s << ',';
01247         ExtendRow(os, indent, maxWidth, s.str(), /*INOUT*/ col);
01248       }
01249       // start a new potential run
01250       lo = curr;
01251     }
01252     prev = curr;
01253   }
01254   // clean up
01255   if (prev < 0) {
01256     os << "<<Empty>>";
01257   } else {
01258     // print last buffered element(s)
01259     OBufStream s;
01260     s << lo;
01261     if (prev > lo) s << '-' << prev;
01262     ExtendRow(os, indent, maxWidth, s.str(), /*INOUT*/ col);
01263   }
01264   os << endl;
01265 }
01266 
01267 // BVIter methods -------------------------------------------------------------
01268 
01269 bool BVIter::Next(/*OUT*/ int& res) throw ()
01270 {
01271     while (this->bitIndex < this->bv->sz) {
01272         Word wd = this->bv->word[this->wordIndex];
01273         if (wd == Zero) {
01274             this->bitIndex += BitsPerWd;
01275         } else {
01276             while (this->mask != Zero) {
01277                 if (this->mask & wd) {
01278                     this->mask <<= 1;
01279                     res = this->bitIndex++;
01280                     return true;
01281                 }
01282                 this->bitIndex++;
01283                 this->mask <<= 1;
01284             }
01285         }
01286         this->wordIndex++;
01287         this->mask = One;
01288     }
01289     return false;
01290 }

Generated on Mon May 8 00:48:31 2006 for Vesta by  doxygen 1.4.2