FixedBitVector.h 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #pragma once
  6. #define FOREACH_BITSET_IN_FIXEDBV(index, bv) \
  7. { \
  8. BVIndex index; \
  9. for(JsUtil::FBVEnumerator _bvenum = bv->BeginSetBits(); \
  10. !_bvenum.End(); \
  11. _bvenum++) \
  12. { \
  13. index = _bvenum.GetCurrent(); \
  14. #define NEXT_BITSET_IN_FIXEDBV }}
  15. class BVFixed
  16. {
  17. // Data
  18. protected:
  19. BVIndex len;
  20. BVUnit data[];
  21. private:
  22. BVFixed(BVFixed * initBv);
  23. BVFixed(BVIndex length, bool initialSet = false);
  24. void ClearEnd();
  25. // Creation Factory
  26. public:
  27. template <typename TAllocator>
  28. static BVFixed * New(TAllocator* alloc, BVFixed * initBv);
  29. template <typename TAllocator>
  30. static BVFixed * New(DECLSPEC_GUARD_OVERFLOW BVIndex length, TAllocator* alloc, bool initialSet = false);
  31. template <typename TAllocator>
  32. static BVFixed * NewNoThrow(DECLSPEC_GUARD_OVERFLOW BVIndex length, TAllocator* alloc, bool initialSet = false);
  33. template <typename TAllocator>
  34. void Delete(TAllocator * alloc);
  35. // For preallocated memory
  36. static size_t GetAllocSize(BVIndex length);
  37. void Init(BVIndex length);
  38. // Implementation
  39. protected:
  40. void AssertRange(BVIndex i) const;
  41. void AssertBV(const BVFixed * bv) const;
  42. static BVIndex WordCount(BVIndex length);
  43. const BVUnit * BitsFromIndex(BVIndex i) const;
  44. BVUnit * BitsFromIndex(BVIndex i);
  45. const BVUnit * BeginUnit() const;
  46. BVUnit * BeginUnit();
  47. const BVUnit * EndUnit() const;
  48. BVUnit * EndUnit();
  49. template<class Fn>
  50. inline void for_each(const BVFixed *bv2, const Fn callback)
  51. {
  52. AssertMsg(this->len == bv2->len, "Fatal: The 2 bitvectors should have had the same length.");
  53. BVUnit * i;
  54. const BVUnit * j;
  55. for(i = this->BeginUnit(), j = bv2->BeginUnit();
  56. i != this->EndUnit() ;
  57. i++, j++)
  58. {
  59. (i->*callback)(*j);
  60. }
  61. }
  62. // Methods
  63. public:
  64. void Set(BVIndex i)
  65. {
  66. AssertRange(i);
  67. this->BitsFromIndex(i)->Set(BVUnit::Offset(i));
  68. }
  69. void Clear(BVIndex i)
  70. {
  71. AssertRange(i);
  72. this->BitsFromIndex(i)->Clear(BVUnit::Offset(i));
  73. }
  74. void Compliment(BVIndex i)
  75. {
  76. AssertRange(i);
  77. this->BitsFromIndex(i)->Complement(BVUnit::Offset(i));
  78. }
  79. BOOLEAN Test(BVIndex i) const
  80. {
  81. AssertRange(i);
  82. return this->BitsFromIndex(i)->Test(BVUnit::Offset(i));
  83. }
  84. BOOLEAN operator[](BVIndex i) const;
  85. BVIndex GetNextBit(BVIndex i) const;
  86. BOOLEAN TestAndSet(BVIndex i);
  87. BOOLEAN TestAndClear(BVIndex i);
  88. void OrComplimented(const BVFixed * bv);
  89. void Or(const BVFixed *bv);
  90. uint DiffCount(const BVFixed* bv) const;
  91. void And(const BVFixed *bv);
  92. void Minus(const BVFixed *bv);
  93. void Copy(const BVFixed *bv);
  94. void CopyBits(const BVFixed * bv, BVIndex i);
  95. void ComplimentAll();
  96. void SetAll();
  97. void ClearAll();
  98. BVIndex Count() const;
  99. BVIndex Length() const;
  100. JsUtil::FBVEnumerator BeginSetBits();
  101. BVIndex WordCount() const;
  102. bool IsAllClear() const;
  103. template<typename Container>
  104. Container GetRange(BVIndex start, BVIndex len) const;
  105. template<typename Container>
  106. void SetRange(Container* value, BVIndex start, BVIndex len);
  107. BVUnit* GetData() const
  108. {
  109. return (BVUnit*)data;
  110. }
  111. #if DBG_DUMP
  112. void Dump() const;
  113. #endif
  114. };
  115. template <typename TAllocator>
  116. BVFixed * BVFixed::New(TAllocator * alloc, BVFixed * initBv)
  117. {
  118. BVIndex length = initBv->Length();
  119. BVFixed *result = AllocatorNewPlusLeaf(TAllocator, alloc, sizeof(BVUnit) * BVFixed::WordCount(length), BVFixed, initBv);
  120. return result;
  121. }
  122. template <typename TAllocator>
  123. BVFixed * BVFixed::New(DECLSPEC_GUARD_OVERFLOW BVIndex length, TAllocator * alloc, bool initialSet)
  124. {
  125. BVFixed *result = AllocatorNewPlusLeaf(TAllocator, alloc, sizeof(BVUnit) * BVFixed::WordCount(length), BVFixed, length, initialSet);
  126. return result;
  127. }
  128. template <typename TAllocator>
  129. BVFixed * BVFixed::NewNoThrow(DECLSPEC_GUARD_OVERFLOW BVIndex length, TAllocator * alloc, bool initialSet)
  130. {
  131. BVFixed *result = AllocatorNewNoThrowNoRecoveryPlus(TAllocator, alloc, sizeof(BVUnit) * BVFixed::WordCount(length), BVFixed, length, initialSet);
  132. return result;
  133. }
  134. template <typename TAllocator>
  135. void BVFixed::Delete(TAllocator * alloc)
  136. {
  137. AllocatorDeletePlus(TAllocator, alloc, sizeof(BVUnit) * this->WordCount(), this);
  138. }
  139. template<typename Container>
  140. Container BVFixed::GetRange(BVIndex start, BVIndex len) const
  141. {
  142. AssertRange(start);
  143. if (len == 0)
  144. {
  145. return Container(0);
  146. }
  147. Assert(len <= sizeof(Container) * MachBits);
  148. AssertMsg(len <= 64, "Currently doesn't support range bigger than 64 bits");
  149. BVIndex end = start + len - 1;
  150. AssertRange(end);
  151. BVIndex iStart = BVUnit::Position(start);
  152. BVIndex iEnd = BVUnit::Position(end);
  153. BVIndex oStart = BVUnit::Offset(start);
  154. BVIndex oEnd = BVUnit::Offset(end);
  155. // Simply using uint64 because it is much easier than to juggle with BVUnit::BVUnitTContainer's size
  156. // Special case, if oEnd == 63, 1 << 64 == 1. Therefore the result is incorrect
  157. uint64 mask = oEnd < 63 ? (((uint64)1 << (oEnd + 1)) - 1) : 0xFFFFFFFFFFFFFFFF;
  158. uint64 range;
  159. // Trivial case
  160. if (iStart == iEnd)
  161. {
  162. // remove the bits after oEnd with mask, then remove the bits before start with shift
  163. range = (mask & this->data[iStart].GetWord()) >> oStart;
  164. }
  165. // Still simple enough
  166. else if (iStart + 1 == iEnd)
  167. {
  168. auto startWord = this->data[iStart].GetWord();
  169. auto endWord = this->data[iEnd].GetWord();
  170. // remove the bits before start with shift
  171. range = startWord >> oStart;
  172. // remove the bits after oEnd with mask then position it after start bits
  173. range |= (mask & endWord) << (BVUnit::BitsPerWord - oStart);
  174. }
  175. // Spans over multiple value, need to loop
  176. else
  177. {
  178. // Get the first bits and move them to the beginning
  179. range = this->data[iStart].GetWord() >> oStart;
  180. // track how many bits have been read so far
  181. int nBitsUsed = BVUnit::BitsPerWord - oStart;
  182. for (uint i = iStart + 1; i < iEnd; ++i)
  183. {
  184. // put all bits from the data in the mid-range. Use the tracked read bits to position them
  185. range |= ((uint64)(this->data[i].GetWord())) << nBitsUsed;
  186. nBitsUsed += BVUnit::BitsPerWord;
  187. }
  188. // Read the last bits and remove those after oEnd with mask
  189. range |= (mask & this->data[iEnd].GetWord()) << nBitsUsed;
  190. }
  191. return Container(range);
  192. }
  193. // the NO_SANITIZE_ADDRESS_CHECK ifdef is to work around a bug in some VC versions
  194. template<typename Container>
  195. #ifdef NO_SANITIZE_ADDRESS_CHECK
  196. NO_SANITIZE_ADDRESS
  197. #endif
  198. void BVFixed::SetRange(Container* value, BVIndex start, BVIndex len)
  199. {
  200. AssertRange(start);
  201. if (len == 0)
  202. {
  203. return;
  204. }
  205. Assert(len <= sizeof(Container) * MachBits);
  206. BVIndex end = start + len - 1;
  207. AssertRange(end);
  208. BVIndex iStart = BVUnit::Position(start);
  209. BVIndex iEnd = BVUnit::Position(end);
  210. BVIndex oStart = BVUnit::Offset(start);
  211. BVIndex oEnd = BVUnit::Offset(end);
  212. BVUnit::BVUnitTContainer temp;
  213. BVUnit::BVUnitTContainer* bits;
  214. static_assert(sizeof(Container) == 1 || sizeof(Container) == sizeof(BVUnit::BVUnitTContainer),
  215. "Container is not suitable to represent the calculated value");
  216. if (sizeof(BVUnit::BVUnitTContainer) == 1)
  217. {
  218. temp = *((BVUnit::BVUnitTContainer*)value);
  219. bits = &temp;
  220. }
  221. else
  222. {
  223. bits = (BVUnit::BVUnitTContainer*)value;
  224. }
  225. const int oStartComplement = BVUnit::BitsPerWord - oStart;
  226. static_assert((BVUnit::BVUnitTContainer)BVUnit::AllOnesMask > 0, "Container type of BVFixed must be unsigned");
  227. //When making the mask, check the special case when we need all bits
  228. #define MAKE_MASK(start, end) ( ((end) == BVUnit::BitsPerWord ? BVUnit::AllOnesMask : (((BVUnit::BVUnitTContainer)1 << ((end) - (start))) - 1)) << (start))
  229. // Or the value to set the bits to 1. And the value to set the bits to 0
  230. // The mask is used to make sure we don't modify the bits outside the range
  231. #define SET_RANGE(i, value, mask) \
  232. this->data[i].Or((value) & mask);\
  233. this->data[i].And((value) | ~mask);
  234. BVUnit::BVUnitTContainer bitsToSet;
  235. // Fast Path
  236. if (iEnd == iStart)
  237. {
  238. const BVUnit::BVUnitTContainer mask = MAKE_MASK(oStart, oEnd + 1);
  239. // Shift to position the bits
  240. bitsToSet = (*bits << oStart);
  241. SET_RANGE(iStart, bitsToSet, mask);
  242. }
  243. // TODO: case iEnd == iStart + 1 to avoid a loop
  244. else if (oStart == 0)
  245. {
  246. // Simpler case where we don't have to shift the bits around
  247. for (uint i = iStart; i < iEnd; ++i)
  248. {
  249. SET_RANGE(i, *bits, BVUnit::AllOnesMask);
  250. ++bits;
  251. }
  252. // We still need to use a mask to remove the unused bits
  253. const BVUnit::BVUnitTContainer mask = MAKE_MASK(0, oEnd + 1);
  254. SET_RANGE(iEnd, *bits, mask);
  255. }
  256. else
  257. {
  258. // Default case. We need to process everything 1 at a time
  259. {
  260. // First set the first bits
  261. CLANG_WNO_BEGIN("-Wtautological-compare")
  262. const BVUnit::BVUnitTContainer mask = MAKE_MASK(oStart, BVUnit::BitsPerWord);
  263. CLANG_WNO_END
  264. SET_RANGE(iStart, *bits << oStart, mask);
  265. }
  266. // Set the bits in the middle
  267. for (uint i = iStart + 1; i < iEnd; ++i)
  268. {
  269. bitsToSet = *bits >> oStartComplement;
  270. ++bits;
  271. bitsToSet |= *bits << oStart;
  272. SET_RANGE(i, bitsToSet, BVUnit::AllOnesMask);
  273. }
  274. // Set the last bits
  275. bitsToSet = *bits >> oStartComplement;
  276. ++bits;
  277. bitsToSet |= *bits << oStart;
  278. {
  279. const BVUnit::BVUnitTContainer mask = MAKE_MASK(0, oEnd + 1);
  280. SET_RANGE(iEnd, bitsToSet, mask);
  281. }
  282. }
  283. if (sizeof(Container) == 1)
  284. {
  285. // Calculation above might overflow the original container.
  286. // normalize the overflow value. LE only
  287. temp = (*((char*)bits)) + (*(((char*)bits) + 1));
  288. memcpy(value, bits, 1);
  289. }
  290. #undef MAKE_MASK
  291. #undef SET_RANGE
  292. }
  293. template <size_t bitCount>
  294. class BVStatic
  295. {
  296. public:
  297. // Made public to allow for compile-time use
  298. static const size_t wordCount = ((bitCount - 1) >> BVUnit::ShiftValue) + 1;
  299. // Data
  300. private:
  301. Field(BVUnit) data[wordCount];
  302. public:
  303. // Break on member changes. We rely on the layout of this class being static so we can
  304. // use initializer lists to generate collections of BVStatic.
  305. BVStatic()
  306. {
  307. Assert(sizeof(BVStatic<bitCount>) == sizeof(data));
  308. Assert((void*)this == (void*)&this->data);
  309. }
  310. // Implementation
  311. private:
  312. void AssertRange(BVIndex i) const { Assert(i < bitCount); }
  313. const BVUnit * BitsFromIndex(BVIndex i) const { AssertRange(i); return &this->data[BVUnit::Position(i)]; }
  314. BVUnit * BitsFromIndex(BVIndex i) { AssertRange(i); return &this->data[BVUnit::Position(i)]; }
  315. const BVUnit * BeginUnit() const { return &this->data[0]; }
  316. BVUnit * BeginUnit() { return &this->data[0]; }
  317. const BVUnit * EndUnit() const { return &this->data[wordCount]; }
  318. BVUnit * EndUnit() { return &this->data[wordCount]; }
  319. template<class Fn>
  320. inline void for_each(const BVStatic *bv2, const Fn callback)
  321. {
  322. BVUnit * i;
  323. const BVUnit * j;
  324. for(i = this->BeginUnit(), j = bv2->BeginUnit();
  325. i != this->EndUnit() ;
  326. i++, j++)
  327. {
  328. (i->*callback)(*j);
  329. }
  330. }
  331. template<class Fn>
  332. static bool MapUntil(const BVStatic *bv1, const BVStatic *bv2, const Fn callback)
  333. {
  334. const BVUnit * i;
  335. const BVUnit * j;
  336. for(i = bv1->BeginUnit(), j = bv2->BeginUnit();
  337. i != bv1->EndUnit() ;
  338. i++, j++)
  339. {
  340. if (!callback(*i, *j))
  341. {
  342. return false;
  343. }
  344. }
  345. return true;
  346. }
  347. void ClearEnd()
  348. {
  349. uint offset = BVUnit::Offset(bitCount);
  350. if (offset != 0)
  351. {
  352. this->data[wordCount - 1].And((1 << offset) - 1);
  353. }
  354. }
  355. // Methods
  356. public:
  357. void Set(BVIndex i)
  358. {
  359. AssertRange(i);
  360. this->BitsFromIndex(i)->Set(BVUnit::Offset(i));
  361. }
  362. void Clear(BVIndex i)
  363. {
  364. AssertRange(i);
  365. this->BitsFromIndex(i)->Clear(BVUnit::Offset(i));
  366. }
  367. void Compliment(BVIndex i)
  368. {
  369. AssertRange(i);
  370. this->BitsFromIndex(i)->Complement(BVUnit::Offset(i));
  371. }
  372. BOOLEAN Equal(BVStatic<bitCount> const * o)
  373. {
  374. return MapUntil(this, o, [](BVUnit const& i, BVUnit const &j) { return i.Equal(j); });
  375. }
  376. BOOLEAN Test(BVIndex i) const
  377. {
  378. AssertRange(i);
  379. return this->BitsFromIndex(i)->Test(BVUnit::Offset(i));
  380. }
  381. BOOLEAN TestAndSet(BVIndex i)
  382. {
  383. AssertRange(i);
  384. return PlatformAgnostic::_BitTestAndSet((LONG *)this->data, (LONG) i);
  385. }
  386. BOOLEAN TestIntrinsic(BVIndex i) const
  387. {
  388. AssertRange(i);
  389. return PlatformAgnostic::_BitTest((LONG *)this->data, (LONG) i);
  390. }
  391. BOOLEAN TestAndSetInterlocked(BVIndex i)
  392. {
  393. AssertRange(i);
  394. return PlatformAgnostic::_InterlockedBitTestAndSet((LONG *)this->data, (LONG) i);
  395. }
  396. BOOLEAN TestAndClear(BVIndex i)
  397. {
  398. AssertRange(i);
  399. BVUnit * bvUnit = this->BitsFromIndex(i);
  400. BVIndex offset = BVUnit::Offset(i);
  401. BOOLEAN bit = bvUnit->Test(offset);
  402. bvUnit->Clear(offset);
  403. return bit;
  404. }
  405. BOOLEAN TestAndClearInterlocked(BVIndex i)
  406. {
  407. AssertRange(i);
  408. return PlatformAgnostic::_InterlockedBitTestAndReset((LONG *)this->data, (LONG)i);
  409. }
  410. void OrComplimented(const BVStatic * bv) { this->for_each(bv, &BVUnit::OrComplimented); ClearEnd(); }
  411. void Or(const BVStatic *bv) { this->for_each(bv, &BVUnit::Or); }
  412. void And(const BVStatic *bv) { this->for_each(bv, &BVUnit::And); }
  413. void Minus(const BVStatic *bv) { this->for_each(bv, &BVUnit::Minus); }
  414. void Copy(const BVStatic *bv) { js_memcpy_s(&this->data[0], wordCount * sizeof(BVUnit), &bv->data[0], wordCount * sizeof(BVUnit)); }
  415. void SetAll() { memset(&this->data[0], -1, wordCount * sizeof(BVUnit)); ClearEnd(); }
  416. void ClearAll() { memset(&this->data[0], 0, wordCount * sizeof(BVUnit)); }
  417. void ComplimentAll()
  418. {
  419. for (BVIndex i = 0; i < wordCount; i++)
  420. {
  421. this->data[i].ComplimentAll();
  422. }
  423. ClearEnd();
  424. }
  425. BVIndex Count() const
  426. {
  427. BVIndex sum = 0;
  428. for (BVIndex i = 0; i < wordCount; i++)
  429. {
  430. sum += this->data[i].Count();
  431. }
  432. Assert(sum <= bitCount);
  433. return sum;
  434. }
  435. BVIndex Length() const
  436. {
  437. return bitCount;
  438. }
  439. JsUtil::FBVEnumerator BeginSetBits() { return JsUtil::FBVEnumerator(this->BeginUnit(), this->EndUnit()); }
  440. BVIndex GetNextBit(BVIndex i) const
  441. {
  442. AssertRange(i);
  443. const BVUnit * chunk = BitsFromIndex(i);
  444. BVIndex base = BVUnit::Floor(i);
  445. BVIndex offset = chunk->GetNextBit(BVUnit::Offset(i));
  446. if (-1 != offset)
  447. {
  448. return base + offset;
  449. }
  450. while (++chunk != this->EndUnit())
  451. {
  452. base += BVUnit::BitsPerWord;
  453. offset = chunk->GetNextBit();
  454. if (-1 != offset)
  455. {
  456. return base + offset;
  457. }
  458. }
  459. return BVInvalidIndex;
  460. }
  461. const BVUnit * GetRawData() const { return data; }
  462. template <size_t rangeSize>
  463. BVStatic<rangeSize> * GetRange(BVIndex startOffset) const
  464. {
  465. AssertRange(startOffset);
  466. AssertRange(startOffset + rangeSize - 1);
  467. // Start offset and size must be word-aligned
  468. Assert(BVUnit::Offset(startOffset) == 0);
  469. Assert(BVUnit::Offset(rangeSize) == 0);
  470. return (BVStatic<rangeSize> *)BitsFromIndex(startOffset);
  471. }
  472. BOOLEAN TestRange(const BVIndex index, uint length) const
  473. {
  474. AssertRange(index);
  475. AssertRange(index + length - 1);
  476. const BVUnit * bvUnit = BitsFromIndex(index);
  477. uint offset = BVUnit::Offset(index);
  478. if (offset + length <= BVUnit::BitsPerWord)
  479. {
  480. // Bit range is in a single word
  481. return bvUnit->TestRange(offset, length);
  482. }
  483. // Bit range spans words.
  484. // Test the first word, from start offset to end of word
  485. if (!bvUnit->TestRange(offset, (BVUnit::BitsPerWord - offset)))
  486. {
  487. return FALSE;
  488. }
  489. bvUnit++;
  490. length -= (BVUnit::BitsPerWord - offset);
  491. // Test entire words until we are at the last word
  492. while (length >= BVUnit::BitsPerWord)
  493. {
  494. if (!bvUnit->IsFull())
  495. {
  496. return FALSE;
  497. }
  498. bvUnit++;
  499. length -= BVUnit::BitsPerWord;
  500. }
  501. // Test last word (unless we already ended on a word boundary)
  502. if (length > 0)
  503. {
  504. if (!bvUnit->TestRange(0, length))
  505. {
  506. return FALSE;
  507. }
  508. }
  509. return TRUE;
  510. }
  511. void SetRange(const BVIndex index, uint length)
  512. {
  513. AssertRange(index);
  514. AssertRange(index + length - 1);
  515. BVUnit * bvUnit = BitsFromIndex(index);
  516. uint offset = BVUnit::Offset(index);
  517. if (offset + length <= BVUnit::BitsPerWord)
  518. {
  519. // Bit range is in a single word
  520. return bvUnit->SetRange(offset, length);
  521. }
  522. // Bit range spans words.
  523. // Set the first word, from start offset to end of word
  524. bvUnit->SetRange(offset, (BVUnit::BitsPerWord - offset));
  525. bvUnit++;
  526. length -= (BVUnit::BitsPerWord - offset);
  527. // Set entire words until we are at the last word
  528. while (length >= BVUnit::BitsPerWord)
  529. {
  530. bvUnit->SetAll();
  531. bvUnit++;
  532. length -= BVUnit::BitsPerWord;
  533. }
  534. // Set last word (unless we already ended on a word boundary)
  535. if (length > 0)
  536. {
  537. bvUnit->SetRange(0, length);
  538. }
  539. }
  540. void ClearRange(const BVIndex index, uint length)
  541. {
  542. AssertRange(index);
  543. AssertRange(index + length - 1);
  544. BVUnit * bvUnit = BitsFromIndex(index);
  545. uint offset = BVUnit::Offset(index);
  546. if (offset + length <= BVUnit::BitsPerWord)
  547. {
  548. // Bit range is in a single word
  549. return bvUnit->ClearRange(offset, length);
  550. }
  551. // Bit range spans words.
  552. // Clear the first word, from start offset to end of word
  553. bvUnit->ClearRange(offset, (BVUnit::BitsPerWord - offset));
  554. bvUnit++;
  555. length -= (BVUnit::BitsPerWord - offset);
  556. // Set entire words until we are at the last word
  557. while (length >= BVUnit::BitsPerWord)
  558. {
  559. bvUnit->ClearAll();
  560. bvUnit++;
  561. length -= BVUnit::BitsPerWord;
  562. }
  563. // Set last word (unless we already ended on a word boundary)
  564. if (length > 0)
  565. {
  566. bvUnit->ClearRange(0, length);
  567. }
  568. }
  569. bool IsAllClear()
  570. {
  571. for (BVIndex i = 0; i < wordCount; i++)
  572. {
  573. if (!this->data[i].IsEmpty())
  574. {
  575. return false;
  576. }
  577. }
  578. return true;
  579. }
  580. bool IsAllSet() const
  581. {
  582. for (BVIndex i = 0; i < this->wordCount; i++)
  583. {
  584. if (i == this->wordCount - 1 && Length() % BVUnit::BitsPerWord != 0)
  585. {
  586. return this->data[i].Count() == Length() % BVUnit::BitsPerWord;
  587. }
  588. else if (!this->data[i].IsFull())
  589. {
  590. return false;
  591. }
  592. }
  593. return true;
  594. }
  595. #if DBG_DUMP
  596. void Dump() const
  597. {
  598. bool hasBits = false;
  599. Output::Print(_u("[ "));
  600. for (BVIndex i = 0; i < wordCount; i++)
  601. {
  602. hasBits = this->data[i].Dump(i * BVUnit::BitsPerWord, hasBits);
  603. }
  604. Output::Print(_u("]\n"));
  605. }
  606. #endif
  607. };