FixedBitVector.h 21 KB

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