csutil/bitarray.h
Go to the documentation of this file.00001 /* 00002 Copyright (C) 2000 by Andrew Kirmse 00003 00004 This library is free software; you can redistribute it and/or 00005 modify it under the terms of the GNU Library General Public 00006 License as published by the Free Software Foundation; either 00007 version 2 of the License, or (at your option) any later version. 00008 00009 This library is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 Library General Public License for more details. 00013 00014 You should have received a copy of the GNU Library General Public 00015 License along with this library; if not, write to the Free 00016 Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00017 */ 00018 00019 // A one-dimensional array of bits, similar to STL bitset. 00020 // 00021 // Copyright 2000 Andrew Kirmse. All rights reserved. 00022 // 00023 // Permission is granted to use this code for any purpose, as long as this 00024 // copyright message remains intact. 00025 00026 #ifndef __CS_BITARRAY_H__ 00027 #define __CS_BITARRAY_H__ 00028 00033 #include "csextern.h" 00034 #include "allocator.h" 00035 #include "comparator.h" 00036 #include "hash.h" 00037 00038 #if defined(CS_COMPILER_MSVC) && (CS_PROCESSOR_SIZE == 64) 00039 /* long is 32 bit even on 64-bit MSVC, so use uint64 to utilize a storage in 00040 * 64 bit units. 00041 */ 00042 typedef uint64 csBitArrayStorageType; 00043 #else 00045 typedef unsigned long csBitArrayStorageType; 00046 #endif 00047 const size_t csBitArrayDefaultInlineBits = 00048 sizeof (csBitArrayStorageType) * 8; 00049 00050 00052 template<typename BitArray> 00053 class csComparatorBitArray 00054 { 00055 public: 00056 static int Compare (BitArray const& key1, BitArray const& key2) 00057 { 00058 csBitArrayStorageType const* p0 = key1.GetStore(); 00059 csBitArrayStorageType const* p1 = key2.GetStore(); 00060 size_t compareNum = MIN (key1.mLength, key2.mLength); 00061 size_t i = 0; 00062 for (; i < compareNum; i++) 00063 if (p0[i] != p1[i]) 00064 return (int)p0[i] - (int)p1[i]; 00065 if (key1.mLength > key2.mLength) 00066 { 00067 for (; i < key1.mLength; i++) 00068 if (p0[i] != 0) 00069 return (int)p0[i]; 00070 } 00071 else 00072 { 00073 for (; i < key2.mLength; i++) 00074 if (p1[i] != 0) 00075 return -((int)p1[i]); 00076 } 00077 return 0; 00078 } 00079 }; 00080 00081 00083 template<typename BitArray> 00084 class csHashComputerBitArray 00085 { 00086 public: 00087 static uint ComputeHash (BitArray const& key) 00088 { 00089 const size_t uintCount = sizeof (csBitArrayStorageType) / sizeof (uint); 00090 uint ui[uintCount]; 00091 uint hash = 0; 00092 csBitArrayStorageType const* p = key.GetStore(); 00093 // \todo Not very good. Find a better hash function; however, it should 00094 // return the same hash for two bit arrays that are the same except for 00095 // the amount of trailing zeros. (e.g. f(10010110) == f(100101100000...)) 00096 for (size_t i = 0; i < key.mLength; i++) 00097 { 00098 memcpy (ui, &p[i], sizeof (ui)); 00099 for (size_t j = 0; j < uintCount; j++) 00100 hash += ui[j]; 00101 } 00102 return hash; 00103 } 00104 }; 00105 00125 template<int InlinedBits = csBitArrayDefaultInlineBits, 00126 typename Allocator = CS::Memory::AllocatorMalloc> 00127 class csBitArrayTweakable 00128 { 00129 public: 00130 typedef csBitArrayTweakable<InlinedBits, Allocator> ThisType; 00131 typedef Allocator AllocatorType; 00132 00133 private: 00134 template<typename BitArray> friend class csComparatorBitArray; 00135 template<typename BitArray> friend class csHashComputerBitArray; 00136 00137 enum 00138 { 00139 cellSize = csBitArrayDefaultInlineBits, 00140 cellCount = (InlinedBits + (cellSize-1)) / cellSize 00141 }; 00142 00143 struct Storage : public Allocator 00144 { 00145 union 00146 { 00147 csBitArrayStorageType* heapStore; 00148 csBitArrayStorageType inlineStore[cellCount]; 00149 }; 00150 Storage() 00151 { 00152 memset (&inlineStore, 0, 00153 MAX(sizeof (heapStore), sizeof (inlineStore))); 00154 } 00155 }; 00156 Storage storage; 00158 size_t mLength; 00159 size_t mNumBits; 00160 00162 static size_t GetIndex (size_t bit_num) 00163 { 00164 return bit_num / cellSize; 00165 } 00166 00168 static size_t GetOffset (size_t bit_num) 00169 { 00170 return bit_num % cellSize; 00171 } 00172 00174 bool UseInlineStore () const 00175 { 00176 return mLength <= cellCount; 00177 } 00178 00183 csBitArrayStorageType const* GetStore() const 00184 { 00185 return UseInlineStore () ? storage.inlineStore : storage.heapStore; 00186 } 00187 00192 csBitArrayStorageType* GetStore() 00193 { 00194 return UseInlineStore () ? storage.inlineStore : storage.heapStore; 00195 } 00196 00198 void Trim() 00199 { 00200 size_t extra_bits = mNumBits % cellSize; 00201 if (mLength > 0 && extra_bits != 0) 00202 GetStore()[mLength - 1] &= ~((~(csBitArrayStorageType)0) << extra_bits); 00203 } 00204 00205 public: 00209 class BitProxy 00210 { 00211 private: 00212 csBitArrayTweakable& mArray; 00213 size_t mPos; 00214 public: 00216 BitProxy (csBitArrayTweakable& array, size_t pos): mArray(array), mPos(pos) 00217 {} 00218 00220 BitProxy &operator= (bool value) 00221 { 00222 mArray.Set (mPos, value); 00223 return *this; 00224 } 00225 00227 BitProxy &operator= (const BitProxy &that) 00228 { 00229 mArray.Set (mPos, that.mArray.IsBitSet (that.mPos)); 00230 return *this; 00231 } 00232 00234 operator bool() const 00235 { 00236 return mArray.IsBitSet (mPos); 00237 } 00238 00243 bool Flip() 00244 { 00245 mArray.FlipBit (mPos); 00246 return mArray.IsBitSet (mPos); 00247 } 00248 }; 00249 friend class BitProxy; 00250 00254 csBitArrayTweakable () : mLength(0), mNumBits(0) 00255 { 00256 SetSize (0); 00257 } 00258 00262 explicit csBitArrayTweakable (size_t size) : mLength(0), mNumBits(0) 00263 { 00264 SetSize (size); 00265 } 00266 00270 csBitArrayTweakable (const csBitArrayTweakable& that) : mLength(0), mNumBits(0) 00271 { 00272 *this = that; // Invokes this->operator=(). 00273 } 00274 00276 ~csBitArrayTweakable() 00277 { 00278 if (!UseInlineStore ()) 00279 storage.Free (storage.heapStore); 00280 } 00281 00283 size_t GetSize() const 00284 { 00285 return mNumBits; 00286 } 00287 00292 /*CS_DEPRECATED_METHOD_MSG("Use GetSize() instead.")*/ 00293 size_t Length () const 00294 { 00295 return GetSize(); 00296 } 00297 00302 /*CS_DEPRECATED_METHOD_MSG("Use SetSize() instead.")*/ 00303 void SetLength (size_t newSize) 00304 { 00305 SetSize (newSize); 00306 } 00307 00313 void SetSize (size_t newSize) 00314 { 00315 size_t newLength; 00316 if (newSize == 0) 00317 newLength = 0; 00318 else 00319 newLength = 1 + GetIndex (newSize - 1); 00320 00321 if (newLength != mLength) 00322 { 00323 // Avoid allocation if length is 1 (common case) 00324 csBitArrayStorageType* newStore; 00325 if (newLength <= cellCount) 00326 newStore = storage.inlineStore; 00327 else 00328 newStore = (csBitArrayStorageType*)storage.Alloc ( 00329 newLength * sizeof (csBitArrayStorageType)); 00330 00331 if (newLength > 0) 00332 { 00333 if (mLength > 0) 00334 { 00335 csBitArrayStorageType* oldStore = GetStore(); 00336 if (newStore != oldStore) 00337 { 00338 memcpy (newStore, oldStore, 00339 (MIN (mLength, newLength)) * sizeof (csBitArrayStorageType)); 00340 if (newLength > mLength) 00341 memset(newStore + mLength, 0, 00342 (newLength - mLength) * sizeof (csBitArrayStorageType)); 00343 if (!UseInlineStore ()) 00344 storage.Free (oldStore); 00345 } 00346 } 00347 else 00348 memset (newStore, 0, newLength * sizeof (csBitArrayStorageType)); 00349 } 00350 mLength = newLength; 00351 if (!UseInlineStore()) storage.heapStore = newStore; 00352 } 00353 00354 mNumBits = newSize; 00355 Trim(); 00356 } 00357 00358 // 00359 // Operators 00360 // 00361 00363 csBitArrayTweakable& operator=(const csBitArrayTweakable& that) 00364 { 00365 if (this != &that) 00366 { 00367 SetSize (that.mNumBits); 00368 memcpy (GetStore(), that.GetStore(), 00369 mLength * sizeof (csBitArrayStorageType)); 00370 } 00371 return *this; 00372 } 00373 00375 BitProxy operator[] (size_t pos) 00376 { 00377 CS_ASSERT (pos < mNumBits); 00378 return BitProxy(*this, pos); 00379 } 00380 00382 bool operator[] (size_t pos) const 00383 { 00384 return IsBitSet(pos); 00385 } 00386 00388 bool operator==(const csBitArrayTweakable& that) const 00389 { 00390 if (mNumBits != that.mNumBits) 00391 return false; 00392 00393 csBitArrayStorageType const* p0 = GetStore(); 00394 csBitArrayStorageType const* p1 = that.GetStore(); 00395 for (unsigned i = 0; i < mLength; i++) 00396 if (p0[i] != p1[i]) 00397 return false; 00398 return true; 00399 } 00400 00402 bool operator != (const csBitArrayTweakable& that) const 00403 { 00404 return !(*this == that); 00405 } 00406 00408 csBitArrayTweakable& operator &= (const csBitArrayTweakable &that) 00409 { 00410 CS_ASSERT (mNumBits == that.mNumBits); 00411 csBitArrayStorageType* p0 = GetStore(); 00412 csBitArrayStorageType const* p1 = that.GetStore(); 00413 for (size_t i = 0; i < mLength; i++) 00414 p0[i] &= p1[i]; 00415 return *this; 00416 } 00417 00419 csBitArrayTweakable operator |= (const csBitArrayTweakable& that) 00420 { 00421 CS_ASSERT (mNumBits == that.mNumBits); 00422 csBitArrayStorageType* p0 = GetStore(); 00423 csBitArrayStorageType const* p1 = that.GetStore(); 00424 for (size_t i = 0; i < mLength; i++) 00425 p0[i] |= p1[i]; 00426 return *this; 00427 } 00428 00430 csBitArrayTweakable operator ^= (const csBitArrayTweakable& that) 00431 { 00432 CS_ASSERT (mNumBits == that.mNumBits); 00433 csBitArrayStorageType* p0 = GetStore(); 00434 csBitArrayStorageType const* p1 = that.GetStore(); 00435 for (size_t i = 0; i < mLength; i++) 00436 p0[i] ^= p1[i]; 00437 return *this; 00438 } 00439 00441 csBitArrayTweakable operator~() const 00442 { 00443 return csBitArrayTweakable(*this).FlipAllBits(); 00444 } 00445 00447 friend csBitArrayTweakable operator& (const csBitArrayTweakable& a1, 00448 const csBitArrayTweakable& a2) 00449 { 00450 return csBitArrayTweakable (a1) &= a2; 00451 } 00452 00454 friend csBitArrayTweakable operator | (const csBitArrayTweakable& a1, 00455 const csBitArrayTweakable& a2) 00456 { 00457 return csBitArrayTweakable (a1) |= a2; 00458 } 00459 00461 friend csBitArrayTweakable operator ^ (const csBitArrayTweakable& a1, 00462 const csBitArrayTweakable& a2) 00463 { 00464 return csBitArrayTweakable (a1) ^= a2; 00465 } 00466 00467 // 00468 // Plain English interface 00469 // 00470 00472 void Clear() 00473 { 00474 memset (GetStore(), 0, mLength * sizeof(csBitArrayStorageType)); 00475 } 00476 00478 void SetBit (size_t pos) 00479 { 00480 CS_ASSERT (pos < mNumBits); 00481 GetStore()[GetIndex(pos)] |= ((csBitArrayStorageType)1) << GetOffset(pos); 00482 } 00483 00485 void ClearBit (size_t pos) 00486 { 00487 CS_ASSERT (pos < mNumBits); 00488 GetStore()[GetIndex(pos)] &= ~(((csBitArrayStorageType)1) << GetOffset(pos)); 00489 } 00490 00492 void FlipBit (size_t pos) 00493 { 00494 CS_ASSERT (pos < mNumBits); 00495 GetStore()[GetIndex(pos)] ^= ((csBitArrayStorageType)1) << GetOffset(pos); 00496 } 00497 00499 void Set (size_t pos, bool val = true) 00500 { 00501 if (val) 00502 SetBit(pos); 00503 else 00504 ClearBit(pos); 00505 } 00506 00508 bool IsBitSet (size_t pos) const 00509 { 00510 CS_ASSERT (pos < mNumBits); 00511 return (GetStore()[GetIndex(pos)] 00512 & (((csBitArrayStorageType)1) << GetOffset(pos))) != 0; 00513 } 00514 00516 bool AreSomeBitsSet (size_t pos, size_t count) const 00517 { 00518 CS_ASSERT (pos + count <= mNumBits); 00519 csBitArrayStorageType const* p = GetStore(); 00520 while (count > 0) 00521 { 00522 size_t index = GetIndex (pos); 00523 size_t offset = GetOffset (pos); 00524 size_t checkCount = MIN(count, cellSize - offset); 00525 csBitArrayStorageType mask = ((checkCount == cellSize) 00526 ? ~(csBitArrayStorageType)0 00527 : ((((csBitArrayStorageType)1) << checkCount) - 1)) << offset; 00528 if (p[index] & mask) 00529 return true; 00530 pos += checkCount; 00531 count -= checkCount; 00532 } 00533 return false; 00534 } 00535 00537 bool AllBitsFalse() const 00538 { 00539 csBitArrayStorageType const* p = GetStore(); 00540 for (size_t i = 0; i < mLength; i++) 00541 if (p[i] != 0) 00542 return false; 00543 return true; 00544 } 00545 00547 csBitArrayTweakable& FlipAllBits() 00548 { 00549 csBitArrayStorageType* p = GetStore(); 00550 for (size_t i = 0; i < mLength; i++) 00551 p[i] = ~p[i]; 00552 Trim(); 00553 return *this; 00554 } 00555 00560 void Delete(size_t pos, size_t count) 00561 { 00562 if (count > 0) 00563 { 00564 size_t dst = pos; 00565 size_t src = pos + count; 00566 CS_ASSERT(src <= mNumBits); 00567 size_t ntail = mNumBits - src; 00568 while (ntail-- > 0) 00569 Set(dst++, IsBitSet(src++)); 00570 SetSize(mNumBits - count); 00571 } 00572 } 00573 00578 csBitArrayTweakable Slice(size_t pos, size_t count) const 00579 { 00580 CS_ASSERT(pos + count <= mNumBits); 00581 csBitArrayTweakable a (count); 00582 for (size_t i = pos, o = 0; i < pos + count; i++) 00583 if (IsBitSet(i)) 00584 a.SetBit(o++); 00585 return a; 00586 } 00587 00589 csBitArrayStorageType* GetArrayBits() 00590 { 00591 return GetStore(); 00592 } 00593 }; 00594 00599 class csBitArray : public csBitArrayTweakable<> 00600 { 00601 public: 00603 csBitArray () { } 00605 explicit csBitArray (size_t size) : csBitArrayTweakable<> (size) { } 00607 csBitArray (const csBitArray& that) : csBitArrayTweakable<> (that) { } 00608 }; 00609 00610 00615 template<> 00616 class csComparator<csBitArray, csBitArray> : 00617 public csComparatorBitArray<csBitArray> { }; 00618 00619 00624 template<> 00625 class csHashComputer<csBitArray> : 00626 public csHashComputerBitArray<csBitArray> { }; 00627 00628 00629 #endif // __CS_BITARRAY_H__
Generated for Crystal Space by doxygen 1.4.7