blob: cc18af572fa0f5c636392fe957ec424d50987ebd (
plain) (
tree)
|
|
#pragma once
#include "traits.h"
#include <bit>
template <typename T>
class TBitIterator {
public:
using TWord = T;
using TTraits = TBitSeqTraits<TWord>;
public:
TBitIterator(const T* data = nullptr)
: Current(0)
, Mask(0)
, Data(data)
{
}
/// Get the word next to the one we are currenlty iterating over.
const TWord* NextWord() const {
return Data;
}
/// Get the next bit without moving the iterator.
bool Peek() const {
return Mask ? (Current & Mask) : (*Data & 1);
}
/// Get the next bit and move forward.
/// TODO: Implement inversed iteration as well.
bool Next() {
if (!Mask) {
Current = *Data++;
Mask = 1;
}
const bool bit = Current & Mask;
Mask <<= 1;
return bit;
}
/// Get the next count bits without moving the iterator.
TWord Peek(ui8 count) const {
if (!count)
return 0;
Y_DEBUG_ABORT_UNLESS(count <= TTraits::NumBits);
if (!Mask)
return *Data & TTraits::ElemMask(count);
auto usedBits = (size_t)std::popcount(Mask - 1u);
TWord result = Current >> usedBits;
auto leftInCurrent = TTraits::NumBits - usedBits;
if (count <= leftInCurrent)
return result & TTraits::ElemMask(count);
count -= leftInCurrent;
result |= (*Data & TTraits::ElemMask(count)) << leftInCurrent;
return result;
}
/// Get the next count bits and move forward by count bits.
TWord Read(ui8 count) {
if (!count)
return 0;
Y_DEBUG_ABORT_UNLESS(count <= TTraits::NumBits);
if (!Mask) {
Current = *Data++;
Mask = 1 << count;
return Current & TTraits::ElemMask(count);
}
auto usedBits = (size_t)std::popcount(Mask - 1u);
TWord result = Current >> usedBits;
auto leftInCurrent = TTraits::NumBits - usedBits;
if (count < leftInCurrent) {
Mask <<= count;
return result & TTraits::ElemMask(count);
}
count -= leftInCurrent;
if (count) {
Current = *Data++;
Mask = 1 << count;
result |= (Current & TTraits::ElemMask(count)) << leftInCurrent;
} else {
Mask = 0;
}
return result;
}
/// Move the iterator forward by count bits.
void Forward(int count) {
if (!count)
return;
int leftInCurrent = std::popcount(static_cast<TWord>(~(Mask - 1u)));
if (count < leftInCurrent) {
Mask <<= count;
return;
}
count -= leftInCurrent;
Data += count >> TTraits::DivShift;
auto remainder = count & TTraits::ModMask;
if (remainder) {
Current = *Data++;
Mask = 1 << remainder;
} else {
Current = 0;
Mask = 0;
}
}
/// Skip trailing bits of the current word and move by count words forward.
void Align(int count = 0) {
Current = 0;
if (Mask)
Mask = 0;
Data += count;
}
/// Initialize the iterator.
void Reset(const TWord* data) {
Current = 0;
Mask = 0;
Data = data;
}
private:
TWord Current;
TWord Mask;
const TWord* Data;
};
|