bitarray.h

Go to the documentation of this file.
00001 /**********************************************************************
00002 *<
00003 FILE: bitarray.h
00004 
00005 DESCRIPTION:
00006 
00007 CREATED BY: Dan Silva
00008 
00009 HISTORY:
00010 
00011 *>   Copyright (c) 1994, All Rights Reserved.
00012 **********************************************************************/
00013 
00014 #pragma once
00015 
00016 #include "GeomExport.h"
00017 #include "maxheap.h"
00018 #include <wtypes.h>
00019 #include <limits.h>
00020 #include "maxtypes.h"
00021 #include "assert1.h"
00022 
00023 // forward declarations
00024 class ILoad;
00025 class ISave;
00026 
00032 class BitArrayCallback: public MaxHeapOperators
00033 {
00034 public:
00040     virtual void proc(int n)=0;
00041 };
00042 
00043 // Direction indicators for BitArray::Rotate and BitArray::Shift
00044 enum
00045 {
00046     LEFT_BITSHIFT  = 0,
00047     RIGHT_BITSHIFT = 1,
00048 };
00049 
00050 // Generate statistics on bitarrays created.  Requires a complete rebuild to toggle
00051 // on and off.
00052 // #define DL_BITARRAY_STATS
00053 
00060 class BitArray: public MaxHeapOperators {
00061     enum
00062     {
00063         kMAX_LOCALBITS = CHAR_BIT * sizeof(DWORD_PTR),
00064     };
00065 
00066     union
00067     {
00068         // numBits cannot be put into a DWORD_PTR so memory had to be allocated.
00069         DWORD_PTR*  bits;
00070 
00071         // bits fit into a DWORD_PTR object; no memory allocation needed.
00072         DWORD_PTR   localBits;
00073     };
00074 
00075     long numBits;
00076 
00077 public:
00078     class NumberSetProxy : public MaxHeapOperators
00079     {
00080     public:
00081         inline operator bool() const           // if( array.NumberSet() )
00082         {
00083             return !mArray.IsEmpty();
00084         }
00085 
00086         inline bool operator !() const         // if( !array.NumberSet() )
00087         {
00088             return mArray.IsEmpty();
00089         }
00090 
00091         inline operator int() const            // int n = array.NumberSet();
00092         {
00093             return mArray.NumberSetImpl();
00094         }
00095 
00096         inline operator DWORD_PTR() const
00097         {
00098             return mArray.NumberSetImpl();
00099         }
00100 
00101         inline operator float() const
00102         {
00103             return (float)mArray.NumberSetImpl();
00104         }
00105 
00106 #ifdef WIN64
00107         inline operator DWORD() const
00108         {
00109             return mArray.NumberSetImpl();
00110         }
00111 #endif
00112 
00113         inline bool operator <(int n) const    // if( array.NumberSet() < 3 )
00114         {
00115             // if( NumberSet() < 0 ) or a negative, always returns false.
00116             // if( NumberSet() < 1 ), basically mean "IsEmpty()".
00117             // if( NumberSet() < n ), we use !(NumberSet() >= n)
00118             return (n <= 0) ? false : ((n == 1) ? mArray.IsEmpty() : !mArray.NumberSetAtLeastImpl(n));
00119         }
00120 
00121         inline bool operator <=(int n) const   // if( array.NumberSet() <= 3 )
00122         {
00123             // if( x <= n ) ==> if( !(x >= (n+1)) )
00124             return !mArray.NumberSetAtLeastImpl(n+1);
00125         }
00126 
00127         inline bool operator >(int n) const    // if( array.NumberSet() > 3 )
00128         {
00129             // if( x > 0 ) ==> !IsEmpty()
00130             // if( x > n ) ==> if( x >= (n+1) )
00131             return n ? mArray.NumberSetAtLeastImpl(n+1) : !mArray.IsEmpty();
00132         }
00133 
00134         inline bool operator >=(int n) const   // if( array.NumberSet() >= 3 )
00135         {
00136             return mArray.NumberSetAtLeastImpl(n);
00137         }
00138 
00139         inline bool operator ==(int n) const   // if( array.NumberSet() == 3 )
00140         {
00141             return mArray.NumberSetEqualImpl(n);
00142         }
00143 
00144         inline bool operator !=(int n) const   // if( array.NumberSet() != 3 )
00145         {
00146             return !mArray.NumberSetEqualImpl(n);
00147         }
00148 
00149         inline int operator +(int n) const         // int n = array.NumberSet() + 3;
00150         {
00151             return mArray.NumberSetImpl() + n;
00152         }
00153 
00154         inline int operator -(int n) const         // int n = array.NumberSet() + 3;
00155         {
00156             return mArray.NumberSetImpl() - n;
00157         }
00158 
00159         inline int operator *(int n) const         // int n = array.NumberSet() * 3;
00160         {
00161             return mArray.NumberSetImpl() * n;
00162         }
00163 
00164         inline int operator /(int n) const         // int n = array.NumberSet() / 3;
00165         {
00166             return mArray.NumberSetImpl() / n;
00167         }
00168 
00169         inline int operator %(int n) const         // int n = array.NumberSet() % 3;
00170         {
00171             return mArray.NumberSetImpl() % n;
00172         }
00173 
00174         inline int operator +(const NumberSetProxy& proxy) const
00175         {
00176             return mArray.NumberSetImpl() + int(proxy);
00177         }
00178 
00179         inline int operator -(const NumberSetProxy& proxy) const
00180         {
00181             return mArray.NumberSetImpl() - int(proxy);
00182         }
00183 
00184         inline int operator *(const NumberSetProxy& proxy) const
00185         {
00186             return mArray.NumberSetImpl() * int(proxy);
00187         }
00188 
00189     private:
00190         const BitArray& mArray;
00191 
00192         friend class BitArray;
00193         // Can only be created by the BitArray itself.
00194         inline NumberSetProxy(const BitArray& a) : mArray(a) {}
00195         NumberSetProxy& operator = (const NumberSetProxy& rhs);
00196     };
00197 
00198     friend class NumberSetProxy;
00199 
00200 public:
00202     inline BitArray() { bits = NULL; numBits = 0; BitArrayAllocated(); }
00207     inline BitArray(int n)
00208     {
00209         DbgAssert( n >= 0 );
00210         if (n < 0)
00211         {
00212             n = 0;
00213         }
00214         if( UseLocalBits(n) )
00215         {
00216             numBits     = n;
00217             localBits   = 0;
00218 
00219             BitArrayAllocated();
00220         }
00221         else
00222         {
00223             CreateBitArrayImpl(n);
00224         }
00225     }
00230     inline BitArray(const BitArray& b)
00231     {
00232         if( b.UseLocalBits() )
00233         {
00234             localBits   = b.localBits;
00235             numBits     = b.numBits;
00236 
00237             BitArrayAllocated();
00238         }
00239         else
00240         {
00241             SetBitsFromImpl(b);
00242         }
00243     }
00244 
00245     inline ~BitArray()
00246     { 
00247         if( !UseLocalBits() ) 
00248             FreeBitsImpl(); 
00249         else 
00250             BitArrayDeallocated();
00251     }
00252 
00257     GEOMEXPORT void SetSize(int n, int save=0);  // save=1:preserve old bit values
00258 
00260     inline int  GetSize() const { return numBits; }
00261 
00263     inline void ClearAll()
00264     {
00265         UseLocalBits() ? localBits = 0 : ClearAllImpl();
00266     }
00267 
00269     inline void SetAll() // Only set used bits; leave the others at zero.
00270     {
00271         UseLocalBits() ? localBits = BitMask(numBits) - 1 : SetAllImpl();
00272     }
00273 
00276     inline void Set(int i)
00277     {
00278         DbgAssert(i>-1 && i<numBits);
00279         if ((i > -1) && (i < numBits))
00280         {
00281             UseLocalBits() ? localBits |= BitMask(i) : SetImpl(i);
00282         }
00283     }
00284 
00289     inline void Clear(int i)
00290     {
00291         DbgAssert(i>-1 && i<numBits);
00292         if ((i > -1) && (i < numBits))
00293         {
00294             UseLocalBits() ? localBits &= ~BitMask(i) : ClearImpl(i);
00295         }
00296     }
00297 
00301     inline void Set(int i, int b) { b ? Set(i) : Clear(i); }
00302 
00305     inline int operator[](int i) const
00306     {
00307         DbgAssert (i>-1);
00308         DbgAssert (i<numBits);
00309         if ((i > -1) && (i < numBits))
00310             return UseLocalBits() ? (localBits & BitMask(i) ? 1 : 0) : GetNthBitImpl(i);
00311         else
00312             return 0;
00313     }
00314 
00317     inline bool IsEmpty() const   { return UseLocalBits() ? !localBits : IsEmptyImpl(); }
00318     inline bool AnyBitSet() const { return !IsEmpty(); }
00319 
00323     inline NumberSetProxy NumberSet() const
00324     {
00325         return NumberSetProxy(*this);
00326     }
00327 
00328 
00329 
00332     GEOMEXPORT void Compress();
00335     GEOMEXPORT void Expand();
00340     GEOMEXPORT void Reverse(BOOL keepZero = FALSE);  // keepZero=TRUE keeps zero bit where it is
00347     GEOMEXPORT void Rotate(int direction, int count);            // With wraparound
00367     GEOMEXPORT void Shift(int direction, int count, int where=0);   // Without wraparound
00373     GEOMEXPORT void EnumSet(BitArrayCallback &cb);  // enumerates elements that are 1's
00390     GEOMEXPORT void DeleteSet (BitArray & dset, int mult=1);
00392     GEOMEXPORT IOResult Save(ISave* isave);
00396     GEOMEXPORT IOResult Load(ILoad* iload);
00397 
00405     inline bool operator==(const BitArray& b) const
00406     {
00407         return (numBits == b.numBits) && (UseLocalBits() ? (localBits == b.localBits) : CompareBitsImpl(b));
00408     }
00409 
00410     // Assignment operators
00412     GEOMEXPORT BitArray& operator=(const BitArray& b);
00413 
00414     // Assignment operators: These require arrays of the same size!
00416     GEOMEXPORT BitArray& operator&=(const BitArray& b);  // AND=
00418     GEOMEXPORT BitArray& operator|=(const BitArray& b);  // OR=
00420     GEOMEXPORT BitArray& operator^=(const BitArray& b);  // XOR=
00421 
00422     // Binary operators: These require arrays of the same size!
00424     GEOMEXPORT BitArray operator&(const BitArray&) const; // AND
00426     GEOMEXPORT BitArray operator|(const BitArray&) const; // OR
00428     GEOMEXPORT BitArray operator^(const BitArray&) const; // XOR
00429 
00430     // Unary operators
00432     inline BitArray operator~() const
00433     {
00434         return UseLocalBits() ? BitArray(~localBits, numBits, true) : OperatorNotImpl();
00435     }
00436 
00438 
00449     GEOMEXPORT void Swap(BitArray& other);
00450 private:
00451     inline BitArray(DWORD_PTR localBits_, long numBits_, bool zeroHighBits = false) :
00452     localBits(localBits_), numBits(numBits_)
00453     {
00454         DbgAssert( UseLocalBits() );
00455 
00456         if( zeroHighBits )
00457             ZeroUnusedBitsImpl();
00458 
00459         BitArrayAllocated();
00460     }
00461 
00462     inline bool UseLocalBits() const { return numBits <= kMAX_LOCALBITS; }
00463     inline bool UseLocalBits(int n) const { return n <= kMAX_LOCALBITS; }
00464     inline DWORD_PTR BitMask(int i) const
00465         // NOTE: Shifting by kMAX_LOCALBITS will give an undefined behavior; the
00466         // chip actually limits the shift from 0 to kMAX_LOCALBITS-1, so most likely
00467         // you simply return '1' when what you wanted was zero.
00468     { return (i < kMAX_LOCALBITS) ? (DWORD_PTR(1) << i) : DWORD_PTR(0); }
00469 
00470     // Used internally to treat the bit array the same way whether it's new'ed or
00471     // simply local.
00472     inline const DWORD_PTR* GetBitPtr() const
00473     {
00474         return UseLocalBits() ? &localBits : bits;
00475     }
00476 
00477     inline DWORD_PTR* GetBitPtr()
00478     {
00479         return UseLocalBits() ? &localBits : bits;
00480     }
00481 
00482     // Called from the ctor only; initializes an array filled with zeroes.
00483     GEOMEXPORT void CreateBitArrayImpl(int n);
00484     // Called from the ctor only; initializes from an array of bits.
00485     GEOMEXPORT void SetBitsFromImpl(const BitArray&);
00486 
00487     GEOMEXPORT void ClearAllImpl();
00488     GEOMEXPORT void SetAllImpl();
00489 
00490     GEOMEXPORT void SetImpl(int i);
00491     GEOMEXPORT void ClearImpl(int i);
00492 
00493     GEOMEXPORT void SetImpl(int i, int b);
00494     GEOMEXPORT int  GetNthBitImpl(int i) const;
00495     GEOMEXPORT int  NumberSetImpl() const;
00496     GEOMEXPORT bool IsEmptyImpl() const;
00497 
00498     GEOMEXPORT BitArray OperatorNotImpl() const;
00499     GEOMEXPORT bool CompareBitsImpl(const BitArray&) const;
00500 
00501     GEOMEXPORT void FreeBitsImpl();
00502 
00503 #ifndef DL_BITARRAY_STATS
00504     inline void BitArrayAllocated() {}
00505     inline void BitArrayDeallocated() {}
00506 #else
00507     class BitArrayStats;
00508     friend class BitArrayStats;
00509 
00510     GEOMEXPORT void BitArrayAllocated();
00511     GEOMEXPORT void BitArrayDeallocated();
00512 #endif
00513 
00514     GEOMEXPORT bool NumberSetImpl(int n) const;         // Exhaustive count; can be dead slow
00515     GEOMEXPORT bool NumberSetEqualImpl(int n) const;    // Stops as soon as count will be higher
00516     GEOMEXPORT bool NumberSetAtLeastImpl(int n) const;  // Stops as soon as count reaches limit.
00517 
00518     // Zeroes out bits over numBits so we can always use fast comparisons (memcmp,
00519     // ==, etc) without having to mask out the last chunk.
00520     GEOMEXPORT void ZeroUnusedBitsImpl();
00521 };
00522 
00523 // Help the compiler out when the array.NumberSet is on the right-hand of the equation
00524 template <typename T> inline T operator +(T n, const BitArray::NumberSetProxy& proxy)
00525 {
00526     return n + proxy.operator int();
00527 }
00528 
00529 template <typename T> inline T operator -(T n, const BitArray::NumberSetProxy& proxy)
00530 {
00531     return n - proxy.operator int();
00532 }
00533 
00534 template <typename T> inline T operator *(T n, const BitArray::NumberSetProxy& proxy)
00535 {
00536     return proxy.operator *(n);
00537 }
00538 
00539 template <typename T> inline T operator /(T n, const BitArray::NumberSetProxy& proxy)
00540 {
00541     return n / proxy.operator int();
00542 }
00543 
00544 template <typename T> inline T operator %(T n, const BitArray::NumberSetProxy& proxy)
00545 {
00546     return n % proxy.operator int();
00547 }
00548 
00549 template <typename T> inline bool operator <=(T n, const BitArray::NumberSetProxy& proxy)
00550 {
00551     return proxy.operator >=(n);
00552 }
00553 
00554 template <typename T> inline bool operator <(T n, const BitArray::NumberSetProxy& proxy)
00555 {
00556     return proxy.operator >(n);
00557 }
00558 
00559 template <typename T> inline bool operator >(T n, const BitArray::NumberSetProxy& proxy)
00560 {
00561     return proxy.operator <(n);
00562 }
00563 
00564 template <typename T> inline bool operator >=(T n, const BitArray::NumberSetProxy& proxy)
00565 {
00566     return proxy.operator <=(n);
00567 }
00568 
00569 template <typename T> inline bool operator ==(T n, const BitArray::NumberSetProxy& proxy)
00570 {
00571     return proxy.operator ==(n);
00572 }
00573 
00574 template <typename T> inline bool operator !=(T n, const BitArray::NumberSetProxy& proxy)
00575 {
00576     return proxy.operator !=(n);
00577 }
00578 
00579 template <typename T> inline void operator +=(T& n, const BitArray::NumberSetProxy& proxy)
00580 {
00581     n += proxy.operator int();
00582 }
00583 
00584 template <typename T> inline void operator -=(T& n, const BitArray::NumberSetProxy& proxy)
00585 {
00586     n -= proxy.operator int();
00587 }
00588