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 Tue Aug 3 13:08:10 EDT 2004 by ken@xorian.net 00020 // modified on Mon Apr 12 08:56:33 PDT 1999 by heydon 00021 00022 // BitVector -- a zero-based indexable vector of bits 00023 // 00024 // A bit vector is a (zero-based) vector of Boolean values. There is no limit 00025 // to the size of a bit vector, but their implementation was not designed to 00026 // represent sparse vectors efficiently. In particular, the memory 00027 // requirements for a bit vector "bv" are "O(sz)", where "sz" is the result 00028 // returned by the method call "bv.Size()". 00029 // 00030 // Every bit in a bit vector has an index; the index of the least significant 00031 // bit is 0. There are operations for reading the value of a bit at a given 00032 // index, and for setting or resetting a bit at a specified index. 00033 // 00034 // The set bit with largest index is called the vector's most-significant bit. 00035 // A bit is "valid" if its index is at most that of the most-significant bit. 00036 // Setting a bit at an index larger than that of the vector's current 00037 // most-significant bit automatically grows the vector, and resets any bits 00038 // between the old and new most-significant bits. 00039 // 00040 // The methods of a "BitVector" are unmonitored. The read-only methods are 00041 // denoted "const". 00042 00043 #ifndef _BIT_VECTOR_H 00044 #define _BIT_VECTOR_H 00045 00046 #include <Basics.H> 00047 #include <FS.H> 00048 #include <SRPC.H> 00049 #include <VestaLog.H> 00050 #include <Recovery.H> 00051 00052 class BVIter; 00053 00054 class BitVector { 00055 public: 00056 BitVector(int sizeHint = 0) throw () 00057 : numWords(0), sz(0), firstAvailWd(0), word((Word *)NULL) 00058 { Init(sizeHint, /*doZero =*/ true); } 00059 /* Initialize a new bit vector. If supplied, "sizeHint" is a hint for the 00060 number of bits the vector is expected to contain. It is a checked 00061 run-time error for "sizeHint < 0". */ 00062 00063 BitVector(const BitVector *bv) throw (); 00064 /* Initialize a new bit vector to be a copy of "*bv". Notice that this is 00065 different from a copy constructor, but it provides a similar 00066 functionality. The true copy constructor is still private, so clients 00067 will not have it invisibly invoked by accident. */ 00068 00069 BitVector(RecoveryReader &rd) throw (VestaLog::Error, VestaLog::Eof) 00070 { Recover(rd); } 00071 00072 BitVector(std::istream &ifs) throw (FS::EndOfFile, FS::Failure) 00073 { Read(ifs); } 00074 00075 BitVector(SRPC &srpc) throw (SRPC::failure) 00076 { Recv(srpc); } 00077 00078 ~BitVector() throw () { if (word != (Word *)NULL) delete word; } 00079 /* De-allocate any space used by the bit vector. */ 00080 00081 bool IsEmpty() const throw (); 00082 /* Return "true" iff the bit vector has no set bits. */ 00083 00084 int Size() const throw () { return this->sz; } 00085 /* Return an upper bound on the bit vector's number of valid bits. Reading 00086 any bit with an index at least as large as the result is guaranteed to 00087 return "false". This operation takes O(1) time. */ 00088 00089 int Cardinality() const throw (); 00090 /* Return the number of set bits in this bit vector. This operation takes 00091 "O(sz)" time, where "sz" is the result returned by the "Size" method. */ 00092 00093 bool Read(int i) const throw (); 00094 /* Return the state of the vector's "i"'th bit. If the "i"th bit is 00095 invalid, return "false". If "i" is negative, the result is undefined, 00096 and a run-time error may result. This operation takes O(1) time. */ 00097 00098 inline bool Write(int i, bool val) throw () 00099 { if (val) return Set(i); else return Reset(i); } 00100 /* Set the value of the "i"'th bit to "val". If the "i"'th bit was 00101 previously invalid and "val" is "true", extend the vector so that "i" 00102 is the new index of the vector's most-significant bit, and so that all 00103 of the other new bits are reset. Returns the value of bit "i" before 00104 it was written to "val". 00105 00106 It is an unchecked run-time error for "i" to be negative. This 00107 operation takes O(1) time. */ 00108 00109 bool Set(int i) throw (); 00110 bool Reset(int i) throw (); 00111 /* These are equivalent to "Write(i, true)" and "Write(i, false)", 00112 respectively, but may be implemented more efficiently. */ 00113 00114 Word ReadWord(int start, short len) const throw (); 00115 /* Read the "len" consecutive bits starting at index "start", and return 00116 them as the low-order "len" bits of a "Word". It is a checked run-time 00117 error for "len" to exceed the number of bits in a "Word". */ 00118 00119 void WriteWord(int start, short len, Word val) throw (); 00120 /* Write the "len" low-order bits of "val" to the bit vector starting at 00121 index "start". It is a checked run-time error for "len" to exceed the 00122 number of bits in a "Word". */ 00123 00124 void WriteInterval(int lo, int hi, bool val) throw () 00125 { if (val) SetInterval(lo, hi); else ResetInterval(lo, hi); } 00126 /* Set all of the bits in the closed interval "[lo, hi]" to the value 00127 "val". It is an unchecked run-time error for "hi < lo" or for "lo" or 00128 "hi" to be negative. */ 00129 00130 void SetInterval(int lo, int hi) throw (); 00131 void ResetInterval(int lo, int hi) throw (); 00132 /* These are equivalent to "WriteInterval(lo, hi, true)" and 00133 "WriteInterval(lo, hi, false)", respectively, but may be implemented 00134 more efficiently. */ 00135 00136 void ResetAll(bool freeMem = false) throw (); 00137 /* Reset all the bits in the bit vector. If "freeMem" is true, then any 00138 memory allocated for the current bit vector will be freed. This is 00139 worthwhile if the current bit vector is large and is not expected to 00140 grow so large in the future. */ 00141 00142 int NextAvailExcept(BitVector *except = (BitVector *)NULL, 00143 bool setIt = true) throw (); 00144 /* Return the index of the least significant unset bit that is also unset 00145 in "except"; if "setIt" is true (the default), then also set that bit 00146 in this bit vector. If "except" is "NULL" (the default), it is as if it 00147 is a bit vector of all unset bits. */ 00148 00149 int NextAvail(bool setIt = true) throw () 00150 { return NextAvailExcept((BitVector *)NULL, setIt); } 00151 /* Return the index of the least significant unset bit; if "setIt" is 00152 "true" (the default), then also set that bit in this bit vector. */ 00153 00154 int MSB() const throw (); 00155 /* Return the index of this bit vector's most-significant bit, 00156 or -1 if it is empty. */ 00157 00158 void Pack(const BitVector &mask) throw (); 00159 /* REQUIRES SELF <= mask */ 00160 /* to be written */ 00161 00162 void Pack(const BitVector *mask) throw () 00163 { if (mask != (BitVector *)NULL) Pack(*mask); } 00164 /* REQUIRES (mask != NULL) => (SELF <= *mask) */ 00165 /* If "mask" is non-NULL, pack this bit vector according to "mask"; see 00166 the other "Pack" method above. */ 00167 00168 void Log(VestaLog &log) const throw (VestaLog::Error); 00169 /* Append this bit vector to "log", which must be in the "logging" 00170 state. */ 00171 00172 void Recover(RecoveryReader &rd) throw (VestaLog::Error, VestaLog::Eof); 00173 /* Recover this bit vector from "rd". */ 00174 00175 // write/read 00176 void Write(std::ostream &ofs) const throw (FS::Failure); 00177 void Read(std::istream &ifs) throw (FS::EndOfFile, FS::Failure); 00178 00179 // send/recv 00180 void Send(SRPC &srpc) const throw (SRPC::failure); 00181 void Recv(SRPC &srpc) throw (SRPC::failure); 00182 00183 // print 00184 friend std::ostream& operator << (std::ostream &os, const BitVector &fv) throw () 00185 { fv.Print(os); return os; } 00186 void Print(std::ostream &s, int maxWidth = 64) const throw (); 00187 /* Write a (partial) representation of the bit vector to "s". If writing 00188 the complete representation would take more than "maxWidth" characters, 00189 "..." is written to indicate that the output is only partial. */ 00190 void PrintAll(std::ostream &s, int indent = 0, int maxWidth = 70) const throw (); 00191 /* Write the complete contents of this bit vector to "s", indenting each 00192 output line by "indent" spaces. Each line is wrapped at a total of at 00193 most "maxWidth" characters. */ 00194 00195 // assignment operator 00196 BitVector& operator = (const BitVector& bv) throw (); 00197 00198 // bitwise comparisons 00199 friend bool operator == (const BitVector& bv1, const BitVector& bv2) 00200 throw (); 00201 friend bool operator != (const BitVector& bv1, const BitVector& bv2) 00202 throw () { return !(bv1 == bv2); } 00203 friend bool operator <= (const BitVector& bv1, const BitVector& bv2) 00204 throw (); 00205 friend bool operator >= (const BitVector& bv1, const BitVector& bv2) 00206 throw () { return (bv2 <= bv1); } 00207 friend bool operator < (const BitVector& bv1, const BitVector& bv2) 00208 throw (); 00209 friend bool operator > (const BitVector& bv1, const BitVector& bv2) 00210 throw () { return (bv2 < bv1); } 00211 00212 // bitwise operations 00213 friend BitVector* operator & (const BitVector& bv1, const BitVector& bv2) 00214 throw (); 00215 friend BitVector* operator | (const BitVector& bv1, const BitVector& bv2) 00216 throw (); 00217 friend BitVector* operator ^ (const BitVector& bv1, const BitVector& bv2) 00218 throw (); 00219 friend BitVector* operator - (const BitVector& bv1, const BitVector& bv2) 00220 throw (); 00221 /* These routines allocate and return a pointer to a new bit vector whose 00222 bits are the bitwise AND, OR, XOR, and difference of "bv1" and "bv2", 00223 respectively. */ 00224 00225 // destructive bitwise operations 00226 BitVector& operator &= (const BitVector& bv) throw (); 00227 BitVector& operator |= (const BitVector& bv) throw (); 00228 BitVector& operator ^= (const BitVector& bv) throw (); 00229 BitVector& operator -= (const BitVector& bv) throw (); 00230 00231 friend class BVIter; 00232 00233 private: 00234 Basics::int16 numWords; // size of "word" array 00235 Basics::int16 firstAvailWd; // see I4 below 00236 Basics::int32 sz; // upper bound on number of valid bits 00237 Word *word; // array of words 00238 00239 /* A newly constructed bit vector has "sz == 0". The following 00240 invariants hold for an initialized bit vector: 00241 00242 | I0. numWords >= 0 00243 | I1. numWords > 0 <==> word != NULL <==> numWords == NUMBER(*word) 00244 | I2. 0 <= sz <= (numWords * bitsPerWd) 00245 | I3. (forall i: sz <= i < (numWords * bitsPerWd): !bit(word, i)) 00246 | I4. (forall i: 0 <= i < (firstAvailWd * bitsPerWd): bit(word, i)) 00247 | I5. 0 <= firstAvailWd <= numWords 00248 00249 where "bitsPerWd" is the number of bits per Word, and "bit(word, i)" 00250 is "true" iff the "i"th bit of the "word" array is set (where the 00251 index of the least significant bit is 0). 00252 00253 By I1, the only words that can be read/written are those with indices 00254 in the interval "[0, numWords-1]". 00255 00256 By I3, the bits in the "word" array that can possibly be non-zero are 00257 those with indices in the interval "[0, sz-1]". 00258 00259 By I4, "firstAvailWd" is the index of the first word that may possibly 00260 contain bits that are not all set. Notice, however, that I4 does not 00261 in any way require "firstAvailWd" to be maximal. For example, I4 is 00262 satisfied trivially when "firstAvailWd == 0". 00263 00264 By I3 and I4, we have: "firstAvailWd * bitsPerWd <= sz". */ 00265 00266 BitVector(int sizeHint, bool doZero) throw () 00267 : numWords(0U), firstAvailWd(0U), sz(0U), word((Word *)NULL) 00268 { Init(sizeHint, doZero); } 00269 /* See "Init" below. */ 00270 00271 void Init(int sizeHint, bool doZero) throw (); 00272 /* Initialize a new bit vector. If supplied, "sizeHint" is a hint for the 00273 number of bits the vector is expected to contain. It is a checked 00274 run-time error for "sizeHint < 0". If "doZero" is "false", then the 00275 words of the bit vector are not zeroed; it is the client's 00276 responsibility to ensure that all invariants (especially I3) are 00277 satisfied. */ 00278 00279 void Extend(short wordCnt, bool doPreserve = true) throw (); 00280 /* REQUIRES wordCnt > this->numWords */ 00281 /* Extend the bit vector to include at least a total of "wordCnt" 00282 words. If "doPreserve" is "true", the contents of the bit vector 00283 are preserved, and all bits in the new words above the significant 00284 ones are guaranteed to be reset according to I3. Otherwise, the 00285 contents of the words are unspecified. 00286 00287 This method may be called on a vector for which "numWords == 0" and 00288 "word == NULL", in which case it does the necessary allocation. */ 00289 00290 void ExpandSz(int i, short wx) throw (); 00291 /* Augment "sz" (and "word" if necessary) so as to contain bit "i"; "wx" 00292 must be the word containing that bit. */ 00293 00294 void ReduceSz() throw (); 00295 /* Reduce "sz" if any of the high-order words of the "word" array are 00296 zero. It's wise to perform this operation after possibly resetting 00297 some of the high-order bits of a bit-vector. */ 00298 00299 // make copy constructor inaccessible to clients 00300 BitVector(const BitVector& bv); 00301 }; 00302 00303 // BVIter -- An object for iterating over the set bits of a BitVector 00304 // 00305 // A "BVIter" object can be used to iterate over the set bits of a 00306 // "BitVector". If "bv" is a "BitVector", then "BVIter(bv)" is a new 00307 // iterator on the bit vector "bv"; it's "Next()" method can be used 00308 // to return the indices of the set bits in "bv" in increasing order. 00309 // The result of the "Next()" method is undefined if the iterator's 00310 // underlying bit vector is changed after the iterator was constructed. 00311 00312 class BVIter { 00313 public: 00314 BVIter(const BitVector& bv) throw () 00315 : bv(&bv), bitIndex(0), wordIndex(0), mask(1UL) { /*SKIP*/ } 00316 /* Initialize a new iterator on the bit vector "bv". */ 00317 00318 bool Next(/*OUT*/ int& res) throw (); 00319 /* Set "res" to the index of the next set bit in the iterator's bit vector 00320 if one exists, and return "true". Otherwise, leave "res" unchanged and 00321 return "false". */ 00322 00323 private: 00324 const BitVector *bv; // the underlying bit vector 00325 int bitIndex; // overall bit index 00326 int wordIndex; // index into BitVector "word" array 00327 Word mask; // bit mask 00328 }; 00329 00330 #endif // _BIT_VECTOR_H