bititerator.h 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. #pragma once
  2. #include "traits.h"
  3. #include <library/cpp/pop_count/popcount.h>
  4. template <typename T>
  5. class TBitIterator {
  6. public:
  7. using TWord = T;
  8. using TTraits = TBitSeqTraits<TWord>;
  9. public:
  10. TBitIterator(const T* data = nullptr)
  11. : Current(0)
  12. , Mask(0)
  13. , Data(data)
  14. {
  15. }
  16. /// Get the word next to the one we are currenlty iterating over.
  17. const TWord* NextWord() const {
  18. return Data;
  19. }
  20. /// Get the next bit without moving the iterator.
  21. bool Peek() const {
  22. return Mask ? (Current & Mask) : (*Data & 1);
  23. }
  24. /// Get the next bit and move forward.
  25. /// TODO: Implement inversed iteration as well.
  26. bool Next() {
  27. if (!Mask) {
  28. Current = *Data++;
  29. Mask = 1;
  30. }
  31. const bool bit = Current & Mask;
  32. Mask <<= 1;
  33. return bit;
  34. }
  35. /// Get the next count bits without moving the iterator.
  36. TWord Peek(ui8 count) const {
  37. if (!count)
  38. return 0;
  39. Y_DEBUG_ABORT_UNLESS(count <= TTraits::NumBits);
  40. if (!Mask)
  41. return *Data & TTraits::ElemMask(count);
  42. auto usedBits = (size_t)PopCount(Mask - 1);
  43. TWord result = Current >> usedBits;
  44. auto leftInCurrent = TTraits::NumBits - usedBits;
  45. if (count <= leftInCurrent)
  46. return result & TTraits::ElemMask(count);
  47. count -= leftInCurrent;
  48. result |= (*Data & TTraits::ElemMask(count)) << leftInCurrent;
  49. return result;
  50. }
  51. /// Get the next count bits and move forward by count bits.
  52. TWord Read(ui8 count) {
  53. if (!count)
  54. return 0;
  55. Y_DEBUG_ABORT_UNLESS(count <= TTraits::NumBits);
  56. if (!Mask) {
  57. Current = *Data++;
  58. Mask = 1 << count;
  59. return Current & TTraits::ElemMask(count);
  60. }
  61. auto usedBits = (size_t)PopCount(Mask - 1);
  62. TWord result = Current >> usedBits;
  63. auto leftInCurrent = TTraits::NumBits - usedBits;
  64. if (count < leftInCurrent) {
  65. Mask <<= count;
  66. return result & TTraits::ElemMask(count);
  67. }
  68. count -= leftInCurrent;
  69. if (count) {
  70. Current = *Data++;
  71. Mask = 1 << count;
  72. result |= (Current & TTraits::ElemMask(count)) << leftInCurrent;
  73. } else {
  74. Mask = 0;
  75. }
  76. return result;
  77. }
  78. /// Move the iterator forward by count bits.
  79. void Forward(int count) {
  80. if (!count)
  81. return;
  82. int leftInCurrent = (size_t)PopCount(~(Mask - 1));
  83. if (count < leftInCurrent) {
  84. Mask <<= count;
  85. return;
  86. }
  87. count -= leftInCurrent;
  88. Data += count >> TTraits::DivShift;
  89. auto remainder = count & TTraits::ModMask;
  90. if (remainder) {
  91. Current = *Data++;
  92. Mask = 1 << remainder;
  93. } else {
  94. Current = 0;
  95. Mask = 0;
  96. }
  97. }
  98. /// Skip trailing bits of the current word and move by count words forward.
  99. void Align(int count = 0) {
  100. Current = 0;
  101. if (Mask)
  102. Mask = 0;
  103. Data += count;
  104. }
  105. /// Initialize the iterator.
  106. void Reset(const TWord* data) {
  107. Current = 0;
  108. Mask = 0;
  109. Data = data;
  110. }
  111. private:
  112. TWord Current;
  113. TWord Mask;
  114. const TWord* Data;
  115. };