1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144 |
- #pragma once
- #include "fwd.h"
- #include "ptr.h"
- #include "bitops.h"
- #include "typetraits.h"
- #include "algorithm.h"
- #include "utility.h"
- #include <util/system/yassert.h>
- #include <util/system/defaults.h>
- #include <util/str_stl.h>
- #include <util/ysaveload.h>
- namespace NBitMapPrivate {
- // Returns number of bits set; result is in most significatnt byte
- inline ui64 ByteSums(ui64 x) {
- ui64 byteSums = x - ((x & 0xAAAAAAAAAAAAAAAAULL) >> 1);
- byteSums = (byteSums & 0x3333333333333333ULL) + ((byteSums >> 2) & 0x3333333333333333ULL);
- byteSums = (byteSums + (byteSums >> 4)) & 0x0F0F0F0F0F0F0F0FULL;
- return byteSums * 0x0101010101010101ULL;
- }
- // better than intrinsics without -mpopcnt
- template <typename T>
- static unsigned CountBitsPrivate(T v) noexcept {
- return static_cast<unsigned>(ByteSums(v) >> 56);
- }
- template <typename TChunkType, size_t ExtraBits>
- struct TSanitizeMask {
- static constexpr TChunkType Value = ~((~TChunkType(0)) << ExtraBits);
- };
- template <typename TChunkType>
- struct TSanitizeMask<TChunkType, 0> {
- static constexpr TChunkType Value = (TChunkType)~TChunkType(0u);
- };
- template <typename TTargetChunk, typename TSourceChunk>
- struct TBigToSmallDataCopier {
- static_assert(sizeof(TTargetChunk) < sizeof(TSourceChunk), "expect sizeof(TTargetChunk) < sizeof(TSourceChunk)");
- static_assert(0 == sizeof(TSourceChunk) % sizeof(TTargetChunk), "expect 0 == sizeof(TSourceChunk) % sizeof(TTargetChunk)");
- static constexpr size_t BLOCK_SIZE = sizeof(TSourceChunk) / sizeof(TTargetChunk);
- union TCnv {
- TSourceChunk BigData;
- TTargetChunk SmallData[BLOCK_SIZE];
- };
- static inline void CopyChunk(TTargetChunk* target, TSourceChunk source) {
- TCnv c;
- c.BigData = source;
- #if defined(_big_endian_)
- ::ReverseCopy(c.SmallData, c.SmallData + Y_ARRAY_SIZE(c.SmallData), target);
- #else
- ::Copy(c.SmallData, c.SmallData + Y_ARRAY_SIZE(c.SmallData), target);
- #endif
- }
- static inline void Copy(TTargetChunk* target, size_t targetSize, const TSourceChunk* source, size_t sourceSize) {
- Y_ASSERT(targetSize >= sourceSize * BLOCK_SIZE);
- if (targetSize > sourceSize * BLOCK_SIZE) {
- ::Fill(target + sourceSize * BLOCK_SIZE, target + targetSize, 0);
- }
- for (size_t i = 0; i < sourceSize; ++i) {
- CopyChunk(target + i * BLOCK_SIZE, source[i]);
- }
- }
- };
- template <typename TTargetChunk, typename TSourceChunk>
- struct TSmallToBigDataCopier {
- static_assert(sizeof(TTargetChunk) > sizeof(TSourceChunk), "expect sizeof(TTargetChunk) > sizeof(TSourceChunk)");
- static_assert(0 == sizeof(TTargetChunk) % sizeof(TSourceChunk), "expect 0 == sizeof(TTargetChunk) % sizeof(TSourceChunk)");
- static constexpr size_t BLOCK_SIZE = sizeof(TTargetChunk) / sizeof(TSourceChunk);
- union TCnv {
- TSourceChunk SmallData[BLOCK_SIZE];
- TTargetChunk BigData;
- };
- static inline TTargetChunk CopyFullChunk(const TSourceChunk* source) {
- TCnv c;
- #if defined(_big_endian_)
- ::ReverseCopy(source, source + BLOCK_SIZE, c.SmallData);
- #else
- ::Copy(source, source + BLOCK_SIZE, c.SmallData);
- #endif
- return c.BigData;
- }
- static inline TTargetChunk CopyPartChunk(const TSourceChunk* source, size_t count) {
- Y_ASSERT(count <= BLOCK_SIZE);
- TCnv c;
- c.BigData = 0;
- #if defined(_big_endian_)
- ::ReverseCopy(source, source + count, c.SmallData);
- #else
- ::Copy(source, source + count, c.SmallData);
- #endif
- return c.BigData;
- }
- static inline void Copy(TTargetChunk* target, size_t targetSize, const TSourceChunk* source, size_t sourceSize) {
- Y_ASSERT(targetSize * BLOCK_SIZE >= sourceSize);
- if (targetSize * BLOCK_SIZE > sourceSize) {
- ::Fill(target + sourceSize / BLOCK_SIZE, target + targetSize, 0);
- }
- size_t i = 0;
- for (; i < sourceSize / BLOCK_SIZE; ++i) {
- target[i] = CopyFullChunk(source + i * BLOCK_SIZE);
- }
- if (0 != sourceSize % BLOCK_SIZE) {
- target[i] = CopyPartChunk(source + i * BLOCK_SIZE, sourceSize % BLOCK_SIZE);
- }
- }
- };
- template <typename TChunk>
- struct TUniformDataCopier {
- static inline void Copy(TChunk* target, size_t targetSize, const TChunk* source, size_t sourceSize) {
- Y_ASSERT(targetSize >= sourceSize);
- for (size_t i = 0; i < sourceSize; ++i) {
- target[i] = source[i];
- }
- for (size_t i = sourceSize; i < targetSize; ++i) {
- target[i] = 0;
- }
- }
- };
- template <typename TFirst, typename TSecond>
- struct TIsSmaller {
- enum {
- Result = sizeof(TFirst) < sizeof(TSecond)
- };
- };
- template <typename TTargetChunk, typename TSourceChunk>
- struct TDataCopier: public std::conditional_t<std::is_same<TTargetChunk, TSourceChunk>::value, TUniformDataCopier<TTargetChunk>, std::conditional_t<TIsSmaller<TTargetChunk, TSourceChunk>::Result, TBigToSmallDataCopier<TTargetChunk, TSourceChunk>, TSmallToBigDataCopier<TTargetChunk, TSourceChunk>>> {
- };
- template <typename TTargetChunk, typename TSourceChunk>
- inline void CopyData(TTargetChunk* target, size_t targetSize, const TSourceChunk* source, size_t sourceSize) {
- TDataCopier<TTargetChunk, TSourceChunk>::Copy(target, targetSize, source, sourceSize);
- }
- template <size_t BitCount, typename TChunkType>
- struct TFixedStorage {
- using TChunk = TChunkType;
- static constexpr size_t Size = (BitCount + 8 * sizeof(TChunk) - 1) / (8 * sizeof(TChunk));
- TChunk Data[Size];
- TFixedStorage() {
- Zero(Data);
- }
- TFixedStorage(const TFixedStorage<BitCount, TChunkType>& st) {
- for (size_t i = 0; i < Size; ++i) {
- Data[i] = st.Data[i];
- }
- }
- template <typename TOtherChunk>
- TFixedStorage(const TOtherChunk* data, size_t size) {
- Y_ABORT_UNLESS(Size * sizeof(TChunk) >= size * sizeof(TOtherChunk), "Exceeding bitmap storage capacity");
- CopyData(Data, Size, data, size);
- }
- Y_FORCE_INLINE void Swap(TFixedStorage<BitCount, TChunkType>& st) {
- for (size_t i = 0; i < Size; ++i) {
- DoSwap(Data[i], st.Data[i]);
- }
- }
- Y_FORCE_INLINE static constexpr size_t GetBitCapacity() noexcept {
- return BitCount;
- }
- Y_FORCE_INLINE static constexpr size_t GetChunkCapacity() noexcept {
- return Size;
- }
- // Returns true if the resulting storage capacity is enough to fit the requested size
- Y_FORCE_INLINE static constexpr bool ExpandBitSize(const size_t bitSize) noexcept {
- return bitSize <= BitCount;
- }
- Y_FORCE_INLINE void Sanitize() {
- Data[Size - 1] &= TSanitizeMask<TChunk, BitCount % (8 * sizeof(TChunk))>::Value;
- }
- };
- // Dynamically expanded storage.
- // It uses "on stack" realization with no allocation for one chunk spaces
- template <typename TChunkType>
- struct TDynamicStorage {
- using TChunk = TChunkType;
- size_t Size;
- TChunk StackData;
- TArrayHolder<TChunk> ArrayData;
- TChunk* Data;
- TDynamicStorage()
- : Size(1)
- , StackData(0)
- , Data(&StackData)
- {
- }
- TDynamicStorage(const TDynamicStorage<TChunk>& st)
- : Size(1)
- , StackData(0)
- , Data(&StackData)
- {
- ExpandSize(st.Size, false);
- for (size_t i = 0; i < st.Size; ++i) {
- Data[i] = st.Data[i];
- }
- for (size_t i = st.Size; i < Size; ++i) {
- Data[i] = 0;
- }
- }
- template <typename TOtherChunk>
- TDynamicStorage(const TOtherChunk* data, size_t size)
- : Size(1)
- , StackData(0)
- , Data(&StackData)
- {
- ExpandBitSize(size * sizeof(TOtherChunk) * 8, false);
- CopyData(Data, Size, data, size);
- }
- Y_FORCE_INLINE void Swap(TDynamicStorage<TChunkType>& st) {
- DoSwap(Size, st.Size);
- DoSwap(StackData, st.StackData);
- DoSwap(ArrayData, st.ArrayData);
- Data = 1 == Size ? &StackData : ArrayData.Get();
- st.Data = 1 == st.Size ? &st.StackData : st.ArrayData.Get();
- }
- Y_FORCE_INLINE size_t GetBitCapacity() const {
- return Size * 8 * sizeof(TChunk);
- }
- Y_FORCE_INLINE size_t GetChunkCapacity() const {
- return Size;
- }
- // Returns true if the resulting storage capacity is enough to fit the requested size
- Y_FORCE_INLINE bool ExpandSize(size_t size, bool keepData = true) {
- if (size > Size) {
- size = Max(size, Size * 2);
- TArrayHolder<TChunk> newData(new TChunk[size]);
- if (keepData) {
- for (size_t i = 0; i < Size; ++i) {
- newData[i] = Data[i];
- }
- for (size_t i = Size; i < size; ++i) {
- newData[i] = 0;
- }
- }
- DoSwap(ArrayData, newData);
- Data = ArrayData.Get();
- Size = size;
- }
- return true;
- }
- Y_FORCE_INLINE bool ExpandBitSize(size_t bitSize, bool keepData = true) {
- return ExpandSize((bitSize + 8 * sizeof(TChunk) - 1) / (8 * sizeof(TChunk)), keepData);
- }
- Y_FORCE_INLINE void Sanitize() {
- }
- };
- template <size_t num>
- struct TDivCount {
- static constexpr size_t Value = 1 + TDivCount<(num >> 1)>::Value;
- };
- template <>
- struct TDivCount<0> {
- static constexpr size_t Value = 0;
- };
- } // namespace NBitMapPrivate
- template <size_t BitCount, typename TChunkType>
- struct TFixedBitMapTraits {
- using TChunk = TChunkType;
- using TStorage = NBitMapPrivate::TFixedStorage<BitCount, TChunkType>;
- };
- template <typename TChunkType>
- struct TDynamicBitMapTraits {
- using TChunk = TChunkType;
- using TStorage = NBitMapPrivate::TDynamicStorage<TChunkType>;
- };
- template <class TTraits>
- class TBitMapOps {
- public:
- using TChunk = typename TTraits::TChunk;
- using TThis = TBitMapOps<TTraits>;
- private:
- static_assert(std::is_unsigned<TChunk>::value, "expect std::is_unsigned<TChunk>::value");
- static constexpr size_t BitsPerChunk = 8 * sizeof(TChunk);
- static constexpr TChunk ModMask = static_cast<TChunk>(BitsPerChunk - 1);
- static constexpr size_t DivCount = NBitMapPrivate::TDivCount<BitsPerChunk>::Value - 1;
- static constexpr TChunk FullChunk = (TChunk)~TChunk(0);
- template <class>
- friend class TBitMapOps;
- using TStorage = typename TTraits::TStorage;
- // The smallest unsigned type, which can be used in bit ops
- using TIntType = std::conditional_t<sizeof(TChunk) < sizeof(unsigned int), unsigned int, TChunk>;
- TStorage Mask;
- public:
- class TReference {
- private:
- friend class TBitMapOps<TTraits>;
- TChunk* Chunk;
- size_t Offset;
- TReference(TChunk* c, size_t offset)
- : Chunk(c)
- , Offset(offset)
- {
- }
- public:
- ~TReference() = default;
- Y_FORCE_INLINE TReference& operator=(bool val) {
- if (val) {
- *Chunk |= static_cast<TChunk>(1) << Offset;
- } else {
- *Chunk &= ~(static_cast<TChunk>(1) << Offset);
- }
- return *this;
- }
- Y_FORCE_INLINE TReference& operator=(const TReference& ref) {
- if (ref) {
- *Chunk |= static_cast<TChunk>(1) << Offset;
- } else {
- *Chunk &= ~(static_cast<TChunk>(1) << Offset);
- }
- return *this;
- }
- Y_FORCE_INLINE bool operator~() const {
- return 0 == (*Chunk & (static_cast<TChunk>(1) << Offset));
- }
- Y_FORCE_INLINE operator bool() const {
- return 0 != (*Chunk & (static_cast<TChunk>(1) << Offset));
- }
- Y_FORCE_INLINE TReference& Flip() {
- *Chunk ^= static_cast<TChunk>(1) << Offset;
- return *this;
- }
- };
- private:
- struct TSetOp {
- static constexpr TChunk Op(const TChunk src, const TChunk mask) noexcept {
- return src | mask;
- }
- };
- struct TResetOp {
- static constexpr TChunk Op(const TChunk src, const TChunk mask) noexcept {
- return src & ~mask;
- }
- };
- template <class TUpdateOp>
- void UpdateRange(size_t start, size_t end) {
- const size_t startChunk = start >> DivCount;
- const size_t startBitOffset = start & ModMask;
- const size_t endChunk = end >> DivCount;
- const size_t endBitOffset = end & ModMask;
- size_t bitOffset = startBitOffset;
- for (size_t chunk = startChunk; chunk <= endChunk; ++chunk) {
- TChunk updateMask = FullChunk << bitOffset;
- if (chunk == endChunk) {
- updateMask ^= FullChunk << endBitOffset;
- if (!updateMask) {
- break;
- }
- }
- Mask.Data[chunk] = TUpdateOp::Op(Mask.Data[chunk], updateMask);
- bitOffset = 0;
- }
- }
- public:
- TBitMapOps() = default;
- TBitMapOps(TChunk val) {
- Mask.Data[0] = val;
- Mask.Sanitize();
- }
- TBitMapOps(const TThis&) = default;
- template <class T>
- TBitMapOps(const TBitMapOps<T>& bitmap)
- : Mask(bitmap.Mask.Data, bitmap.Mask.GetChunkCapacity())
- {
- Mask.Sanitize();
- }
- template <class T>
- Y_FORCE_INLINE bool operator==(const TBitMapOps<T>& bitmap) const {
- return Equal(bitmap);
- }
- Y_FORCE_INLINE TThis& operator=(const TThis& bitmap) {
- if (this != &bitmap) {
- TThis bm(bitmap);
- Swap(bm);
- }
- return *this;
- }
- template <class T>
- Y_FORCE_INLINE TThis& operator=(const TBitMapOps<T>& bitmap) {
- TThis bm(bitmap);
- Swap(bm);
- return *this;
- }
- template <class T>
- Y_FORCE_INLINE TThis& operator&=(const TBitMapOps<T>& bitmap) {
- return And(bitmap);
- }
- Y_FORCE_INLINE TThis& operator&=(const TChunk& val) {
- return And(val);
- }
- template <class T>
- Y_FORCE_INLINE TThis& operator|=(const TBitMapOps<T>& bitmap) {
- return Or(bitmap);
- }
- Y_FORCE_INLINE TThis& operator|=(const TChunk& val) {
- return Or(val);
- }
- template <class T>
- Y_FORCE_INLINE TThis& operator^=(const TBitMapOps<T>& bitmap) {
- return Xor(bitmap);
- }
- Y_FORCE_INLINE TThis& operator^=(const TChunk& val) {
- return Xor(val);
- }
- template <class T>
- Y_FORCE_INLINE TThis& operator-=(const TBitMapOps<T>& bitmap) {
- return SetDifference(bitmap);
- }
- Y_FORCE_INLINE TThis& operator-=(const TChunk& val) {
- return SetDifference(val);
- }
- Y_FORCE_INLINE TThis& operator<<=(size_t pos) {
- return LShift(pos);
- }
- Y_FORCE_INLINE TThis& operator>>=(size_t pos) {
- return RShift(pos);
- }
- Y_FORCE_INLINE TThis operator<<(size_t pos) const {
- return TThis(*this).LShift(pos);
- }
- Y_FORCE_INLINE TThis operator>>(size_t pos) const {
- return TThis(*this).RShift(pos);
- }
- Y_FORCE_INLINE bool operator[](size_t pos) const {
- return Get(pos);
- }
- Y_FORCE_INLINE TReference operator[](size_t pos) {
- const bool fitStorage = Mask.ExpandBitSize(pos + 1);
- Y_ASSERT(fitStorage);
- return TReference(&Mask.Data[pos >> DivCount], ModMask & pos);
- }
- Y_FORCE_INLINE void Swap(TThis& bitmap) {
- DoSwap(Mask, bitmap.Mask);
- }
- Y_FORCE_INLINE TThis& Set(size_t pos) {
- const bool fitStorage = Mask.ExpandBitSize(pos + 1);
- Y_ASSERT(fitStorage);
- Mask.Data[pos >> DivCount] |= static_cast<TChunk>(1) << (pos & ModMask);
- return *this;
- }
- // Fills the specified [start, end) bit range by the 1. Other bits are kept unchanged
- TThis& Set(size_t start, size_t end) {
- Y_ASSERT(start <= end);
- if (start < end) {
- Reserve(end);
- UpdateRange<TSetOp>(start, end);
- }
- return *this;
- }
- Y_FORCE_INLINE TThis& Reset(size_t pos) {
- if ((pos >> DivCount) < Mask.GetChunkCapacity()) {
- Mask.Data[pos >> DivCount] &= ~(static_cast<TChunk>(1) << (pos & ModMask));
- }
- return *this;
- }
- // Clears the specified [start, end) bit range. Other bits are kept unchanged
- TThis& Reset(size_t start, size_t end) {
- Y_ASSERT(start <= end);
- if (start < end && (start >> DivCount) < Mask.GetChunkCapacity()) {
- UpdateRange<TResetOp>(start, Min(end, Mask.GetBitCapacity()));
- }
- return *this;
- }
- Y_FORCE_INLINE TThis& Flip(size_t pos) {
- const bool fitStorage = Mask.ExpandBitSize(pos + 1);
- Y_ASSERT(fitStorage);
- Mask.Data[pos >> DivCount] ^= static_cast<TChunk>(1) << (pos & ModMask);
- return *this;
- }
- Y_FORCE_INLINE bool Get(size_t pos) const {
- if ((pos >> DivCount) < Mask.GetChunkCapacity()) {
- return Mask.Data[pos >> DivCount] & (static_cast<TChunk>(1) << (pos & ModMask));
- }
- return false;
- }
- template <class TTo>
- void Export(size_t pos, TTo& to) const {
- static_assert(std::is_unsigned<TTo>::value, "expect std::is_unsigned<TTo>::value");
- to = 0;
- size_t chunkpos = pos >> DivCount;
- if (chunkpos >= Mask.GetChunkCapacity()) {
- return;
- }
- if ((pos & ModMask) == 0) {
- if (sizeof(TChunk) >= sizeof(TTo)) {
- to = (TTo)Mask.Data[chunkpos];
- } else { // if (sizeof(TChunk) < sizeof(TTo))
- NBitMapPrivate::CopyData(&to, 1, Mask.Data + chunkpos, Min(((sizeof(TTo) * 8) >> DivCount), Mask.GetChunkCapacity() - chunkpos));
- }
- } else if ((pos & (sizeof(TTo) * 8 - 1)) == 0 && sizeof(TChunk) >= 2 * sizeof(TTo)) {
- to = (TTo)(Mask.Data[chunkpos] >> (pos & ModMask));
- } else {
- static constexpr size_t copyToSize = (sizeof(TChunk) >= sizeof(TTo)) ? (sizeof(TChunk) / sizeof(TTo)) + 2 : 3;
- TTo temp[copyToSize] = {0, 0};
- // or use non defined by now TBitmap<copyToSize, TTo>::CopyData,RShift(pos & ModMask),Export(0,to)
- NBitMapPrivate::CopyData(temp, copyToSize, Mask.Data + chunkpos, Min((sizeof(TTo) / sizeof(TChunk)) + 1, Mask.GetChunkCapacity() - chunkpos));
- to = (temp[0] >> (pos & ModMask)) | (temp[1] << (8 * sizeof(TTo) - (pos & ModMask)));
- }
- }
- Y_FORCE_INLINE bool Test(size_t n) const {
- return Get(n);
- }
- Y_FORCE_INLINE TThis& Push(bool val) {
- LShift(1);
- return val ? Set(0) : *this;
- }
- Y_FORCE_INLINE bool Pop() {
- bool val = Get(0);
- return RShift(1), val;
- }
- // Clear entire bitmap. Current capacity is kept unchanged
- Y_FORCE_INLINE TThis& Clear() {
- for (size_t i = 0; i < Mask.GetChunkCapacity(); ++i) {
- Mask.Data[i] = 0;
- }
- return *this;
- }
- // Returns bits capacity
- Y_FORCE_INLINE constexpr size_t Size() const noexcept {
- return Mask.GetBitCapacity();
- }
- Y_FORCE_INLINE void Reserve(size_t bitCount) {
- Y_ABORT_UNLESS(Mask.ExpandBitSize(bitCount), "Exceeding bitmap storage capacity");
- }
- Y_FORCE_INLINE size_t ValueBitCount() const {
- size_t nonZeroChunk = Mask.GetChunkCapacity() - 1;
- while (nonZeroChunk != 0 && !Mask.Data[nonZeroChunk]) {
- --nonZeroChunk;
- }
- return nonZeroChunk || Mask.Data[nonZeroChunk]
- ? nonZeroChunk * BitsPerChunk + GetValueBitCount(TIntType(Mask.Data[nonZeroChunk]))
- : 0;
- }
- Y_PURE_FUNCTION Y_FORCE_INLINE bool Empty() const {
- for (size_t i = 0; i < Mask.GetChunkCapacity(); ++i) {
- if (Mask.Data[i]) {
- return false;
- }
- }
- return true;
- }
- bool HasAny(const TThis& bitmap) const {
- for (size_t i = 0; i < Min(Mask.GetChunkCapacity(), bitmap.Mask.GetChunkCapacity()); ++i) {
- if (0 != (Mask.Data[i] & bitmap.Mask.Data[i])) {
- return true;
- }
- }
- return false;
- }
- template <class T>
- Y_FORCE_INLINE bool HasAny(const TBitMapOps<T>& bitmap) const {
- return HasAny(TThis(bitmap));
- }
- Y_FORCE_INLINE bool HasAny(const TChunk& val) const {
- return 0 != (Mask.Data[0] & val);
- }
- bool HasAll(const TThis& bitmap) const {
- for (size_t i = 0; i < Min(Mask.GetChunkCapacity(), bitmap.Mask.GetChunkCapacity()); ++i) {
- if (bitmap.Mask.Data[i] != (Mask.Data[i] & bitmap.Mask.Data[i])) {
- return false;
- }
- }
- for (size_t i = Mask.GetChunkCapacity(); i < bitmap.Mask.GetChunkCapacity(); ++i) {
- if (bitmap.Mask.Data[i] != 0) {
- return false;
- }
- }
- return true;
- }
- template <class T>
- Y_FORCE_INLINE bool HasAll(const TBitMapOps<T>& bitmap) const {
- return HasAll(TThis(bitmap));
- }
- Y_FORCE_INLINE bool HasAll(const TChunk& val) const {
- return (Mask.Data[0] & val) == val;
- }
- TThis& And(const TThis& bitmap) {
- // Don't expand capacity here, because resulting bits in positions,
- // which are greater then size of one of these bitmaps, will be zero
- for (size_t i = 0; i < Min(bitmap.Mask.GetChunkCapacity(), Mask.GetChunkCapacity()); ++i) {
- Mask.Data[i] &= bitmap.Mask.Data[i];
- }
- // Clear bits if current bitmap size is greater than AND-ed one
- for (size_t i = bitmap.Mask.GetChunkCapacity(); i < Mask.GetChunkCapacity(); ++i) {
- Mask.Data[i] = 0;
- }
- return *this;
- }
- template <class T>
- Y_FORCE_INLINE TThis& And(const TBitMapOps<T>& bitmap) {
- return And(TThis(bitmap));
- }
- Y_FORCE_INLINE TThis& And(const TChunk& val) {
- Mask.Data[0] &= val;
- for (size_t i = 1; i < Mask.GetChunkCapacity(); ++i) {
- Mask.Data[i] = 0;
- }
- return *this;
- }
- TThis& Or(const TThis& bitmap) {
- const size_t valueBitCount = bitmap.ValueBitCount();
- if (valueBitCount) {
- // Memory optimization: expand size only for non-zero bits
- Reserve(valueBitCount);
- for (size_t i = 0; i < Min(bitmap.Mask.GetChunkCapacity(), Mask.GetChunkCapacity()); ++i) {
- Mask.Data[i] |= bitmap.Mask.Data[i];
- }
- }
- return *this;
- }
- template <class T>
- Y_FORCE_INLINE TThis& Or(const TBitMapOps<T>& bitmap) {
- return Or(TThis(bitmap));
- }
- Y_FORCE_INLINE TThis& Or(const TChunk& val) {
- Mask.Data[0] |= val;
- Mask.Sanitize();
- return *this;
- }
- TThis& Xor(const TThis& bitmap) {
- Reserve(bitmap.Size());
- for (size_t i = 0; i < bitmap.Mask.GetChunkCapacity(); ++i) {
- Mask.Data[i] ^= bitmap.Mask.Data[i];
- }
- return *this;
- }
- template <class T>
- Y_FORCE_INLINE TThis& Xor(const TBitMapOps<T>& bitmap) {
- return Xor(TThis(bitmap));
- }
- Y_FORCE_INLINE TThis& Xor(const TChunk& val) {
- Mask.Data[0] ^= val;
- Mask.Sanitize();
- return *this;
- }
- TThis& SetDifference(const TThis& bitmap) {
- for (size_t i = 0; i < Min(bitmap.Mask.GetChunkCapacity(), Mask.GetChunkCapacity()); ++i) {
- Mask.Data[i] &= ~bitmap.Mask.Data[i];
- }
- return *this;
- }
- template <class T>
- Y_FORCE_INLINE TThis& SetDifference(const TBitMapOps<T>& bitmap) {
- return SetDifference(TThis(bitmap));
- }
- Y_FORCE_INLINE TThis& SetDifference(const TChunk& val) {
- Mask.Data[0] &= ~val;
- return *this;
- }
- Y_FORCE_INLINE TThis& Flip() {
- for (size_t i = 0; i < Mask.GetChunkCapacity(); ++i) {
- Mask.Data[i] = ~Mask.Data[i];
- }
- Mask.Sanitize();
- return *this;
- }
- TThis& LShift(size_t shift) {
- if (shift != 0) {
- const size_t valueBitCount = ValueBitCount();
- // Do nothing for empty bitmap
- if (valueBitCount != 0) {
- const size_t eshift = shift / BitsPerChunk;
- const size_t offset = shift % BitsPerChunk;
- const size_t subOffset = BitsPerChunk - offset;
- // Don't verify expand result, so l-shift of fixed bitmap will work in the same way as for unsigned integer.
- Mask.ExpandBitSize(valueBitCount + shift);
- if (offset == 0) {
- for (size_t i = Mask.GetChunkCapacity() - 1; i >= eshift; --i) {
- Mask.Data[i] = Mask.Data[i - eshift];
- }
- } else {
- for (size_t i = Mask.GetChunkCapacity() - 1; i > eshift; --i) {
- Mask.Data[i] = (Mask.Data[i - eshift] << offset) | (Mask.Data[i - eshift - 1] >> subOffset);
- }
- if (eshift < Mask.GetChunkCapacity()) {
- Mask.Data[eshift] = Mask.Data[0] << offset;
- }
- }
- for (size_t i = 0; i < Min(eshift, Mask.GetChunkCapacity()); ++i) {
- Mask.Data[i] = 0;
- }
- // Cleanup extra high bits in the storage
- Mask.Sanitize();
- }
- }
- return *this;
- }
- TThis& RShift(size_t shift) {
- if (shift != 0) {
- const size_t eshift = shift / BitsPerChunk;
- const size_t offset = shift % BitsPerChunk;
- if (eshift >= Mask.GetChunkCapacity()) {
- Clear();
- } else {
- const size_t limit = Mask.GetChunkCapacity() - eshift - 1;
- if (offset == 0) {
- for (size_t i = 0; i <= limit; ++i) {
- Mask.Data[i] = Mask.Data[i + eshift];
- }
- } else {
- const size_t subOffset = BitsPerChunk - offset;
- for (size_t i = 0; i < limit; ++i) {
- Mask.Data[i] = (Mask.Data[i + eshift] >> offset) | (Mask.Data[i + eshift + 1] << subOffset);
- }
- Mask.Data[limit] = Mask.Data[Mask.GetChunkCapacity() - 1] >> offset;
- }
- for (size_t i = limit + 1; i < Mask.GetChunkCapacity(); ++i) {
- Mask.Data[i] = 0;
- }
- }
- }
- return *this;
- }
- // Applies bitmap at the specified offset using OR operator.
- // This method is optimized combination of Or() and LShift(), which allows reducing memory allocation
- // when combining long dynamic bitmaps.
- TThis& Or(const TThis& bitmap, size_t offset) {
- if (0 == offset) {
- return Or(bitmap);
- }
- const size_t otherValueBitCount = bitmap.ValueBitCount();
- // Continue only if OR-ed bitmap have non-zero bits
- if (otherValueBitCount) {
- const size_t chunkShift = offset / BitsPerChunk;
- const size_t subShift = offset % BitsPerChunk;
- const size_t subOffset = BitsPerChunk - subShift;
- Reserve(otherValueBitCount + offset);
- if (subShift == 0) {
- for (size_t i = chunkShift; i < Min(bitmap.Mask.GetChunkCapacity() + chunkShift, Mask.GetChunkCapacity()); ++i) {
- Mask.Data[i] |= bitmap.Mask.Data[i - chunkShift];
- }
- } else {
- Mask.Data[chunkShift] |= bitmap.Mask.Data[0] << subShift;
- size_t i = chunkShift + 1;
- for (; i < Min(bitmap.Mask.GetChunkCapacity() + chunkShift, Mask.GetChunkCapacity()); ++i) {
- Mask.Data[i] |= (bitmap.Mask.Data[i - chunkShift] << subShift) | (bitmap.Mask.Data[i - chunkShift - 1] >> subOffset);
- }
- if (i < Mask.GetChunkCapacity()) {
- Mask.Data[i] |= bitmap.Mask.Data[i - chunkShift - 1] >> subOffset;
- }
- }
- }
- return *this;
- }
- bool Equal(const TThis& bitmap) const {
- if (Mask.GetChunkCapacity() > bitmap.Mask.GetChunkCapacity()) {
- for (size_t i = bitmap.Mask.GetChunkCapacity(); i < Mask.GetChunkCapacity(); ++i) {
- if (0 != Mask.Data[i]) {
- return false;
- }
- }
- } else if (Mask.GetChunkCapacity() < bitmap.Mask.GetChunkCapacity()) {
- for (size_t i = Mask.GetChunkCapacity(); i < bitmap.Mask.GetChunkCapacity(); ++i) {
- if (0 != bitmap.Mask.Data[i]) {
- return false;
- }
- }
- }
- size_t size = Min(Mask.GetChunkCapacity(), bitmap.Mask.GetChunkCapacity());
- for (size_t i = 0; i < size; ++i) {
- if (Mask.Data[i] != bitmap.Mask.Data[i]) {
- return false;
- }
- }
- return true;
- }
- template <class T>
- Y_FORCE_INLINE bool Equal(const TBitMapOps<T>& bitmap) const {
- return Equal(TThis(bitmap));
- }
- int Compare(const TThis& bitmap) const {
- size_t size = Min(Mask.GetChunkCapacity(), bitmap.Mask.GetChunkCapacity());
- int res = ::memcmp(Mask.Data, bitmap.Mask.Data, size * sizeof(TChunk));
- if (0 != res || Mask.GetChunkCapacity() == bitmap.Mask.GetChunkCapacity()) {
- return res;
- }
- if (Mask.GetChunkCapacity() > bitmap.Mask.GetChunkCapacity()) {
- for (size_t i = bitmap.Mask.GetChunkCapacity(); i < Mask.GetChunkCapacity(); ++i) {
- if (0 != Mask.Data[i]) {
- return 1;
- }
- }
- } else {
- for (size_t i = Mask.GetChunkCapacity(); i < bitmap.Mask.GetChunkCapacity(); ++i) {
- if (0 != bitmap.Mask.Data[i]) {
- return -1;
- }
- }
- }
- return 0;
- }
- template <class T>
- Y_FORCE_INLINE int Compare(const TBitMapOps<T>& bitmap) const {
- return Compare(TThis(bitmap));
- }
- // For backward compatibility
- Y_FORCE_INLINE static int Compare(const TThis& l, const TThis& r) {
- return l.Compare(r);
- }
- size_t FirstNonZeroBit() const {
- for (size_t i = 0; i < Mask.GetChunkCapacity(); ++i) {
- if (Mask.Data[i]) {
- // CountTrailingZeroBits() expects unsigned types not smaller than unsigned int. So, convert before calling
- return BitsPerChunk * i + CountTrailingZeroBits(TIntType(Mask.Data[i]));
- }
- }
- return Size();
- }
- // Returns position of the next non-zero bit, which offset is greater than specified pos
- // Typical loop for iterating bits:
- // for (size_t pos = bits.FirstNonZeroBit(); pos != bits.Size(); pos = bits.NextNonZeroBit(pos)) {
- // ...
- // }
- // See Y_FOR_EACH_BIT macro definition at the bottom
- size_t NextNonZeroBit(size_t pos) const {
- size_t i = (pos + 1) >> DivCount;
- if (i < Mask.GetChunkCapacity()) {
- const size_t offset = (pos + 1) & ModMask;
- // Process the current chunk
- if (offset) {
- // Zero already iterated trailing bits using mask
- const TChunk val = Mask.Data[i] & ((~TChunk(0)) << offset);
- if (val) {
- return BitsPerChunk * i + CountTrailingZeroBits(TIntType(val));
- }
- // Continue with other chunks
- ++i;
- }
- for (; i < Mask.GetChunkCapacity(); ++i) {
- if (Mask.Data[i]) {
- return BitsPerChunk * i + CountTrailingZeroBits(TIntType(Mask.Data[i]));
- }
- }
- }
- return Size();
- }
- Y_FORCE_INLINE size_t Count() const {
- size_t count = 0;
- for (size_t i = 0; i < Mask.GetChunkCapacity(); ++i) {
- count += ::NBitMapPrivate::CountBitsPrivate(Mask.Data[i]);
- }
- return count;
- }
- void Save(IOutputStream* out) const {
- ::Save(out, ui8(sizeof(TChunk)));
- ::Save(out, ui64(Size()));
- ::SavePodArray(out, Mask.Data, Mask.GetChunkCapacity());
- }
- void Load(IInputStream* inp) {
- ui8 chunkSize = 0;
- ::Load(inp, chunkSize);
- Y_ABORT_UNLESS(size_t(chunkSize) == sizeof(TChunk), "Chunk size is not the same");
- ui64 bitCount64 = 0;
- ::Load(inp, bitCount64);
- size_t bitCount = size_t(bitCount64);
- Reserve(bitCount);
- size_t chunkCount = 0;
- if (bitCount > 0) {
- chunkCount = ((bitCount - 1) >> DivCount) + 1;
- ::LoadPodArray(inp, Mask.Data, chunkCount);
- }
- if (chunkCount < Mask.GetChunkCapacity()) {
- ::memset(Mask.Data + chunkCount, 0, (Mask.GetChunkCapacity() - chunkCount) * sizeof(TChunk));
- }
- Mask.Sanitize();
- }
- inline size_t Hash() const {
- THash<TChunk> chunkHasher;
- size_t hash = chunkHasher(0);
- bool tailSkipped = false;
- for (size_t i = Mask.GetChunkCapacity(); i > 0; --i) {
- if (tailSkipped || Mask.Data[i - 1]) {
- hash = ::CombineHashes(hash, chunkHasher(Mask.Data[i - 1]));
- tailSkipped = true;
- }
- }
- return hash;
- }
- inline const TChunk* GetChunks() const {
- return Mask.Data;
- }
- constexpr size_t GetChunkCount() const noexcept {
- return Mask.GetChunkCapacity();
- }
- };
- template <class X, class Y>
- inline TBitMapOps<X> operator&(const TBitMapOps<X>& x, const TBitMapOps<Y>& y) {
- return TBitMapOps<X>(x).And(y);
- }
- template <class X>
- inline TBitMapOps<X> operator&(const TBitMapOps<X>& x, const typename TBitMapOps<X>::TChunk& y) {
- return TBitMapOps<X>(x).And(y);
- }
- template <class X>
- inline TBitMapOps<X> operator&(const typename TBitMapOps<X>::TChunk& x, const TBitMapOps<X>& y) {
- return TBitMapOps<X>(x).And(y);
- }
- template <class X, class Y>
- inline TBitMapOps<X> operator|(const TBitMapOps<X>& x, const TBitMapOps<Y>& y) {
- return TBitMapOps<X>(x).Or(y);
- }
- template <class X>
- inline TBitMapOps<X> operator|(const TBitMapOps<X>& x, const typename TBitMapOps<X>::TChunk& y) {
- return TBitMapOps<X>(x).Or(y);
- }
- template <class X>
- inline TBitMapOps<X> operator|(const typename TBitMapOps<X>::TChunk& x, const TBitMapOps<X>& y) {
- return TBitMapOps<X>(x).Or(y);
- }
- template <class X, class Y>
- inline TBitMapOps<X> operator^(const TBitMapOps<X>& x, const TBitMapOps<Y>& y) {
- return TBitMapOps<X>(x).Xor(y);
- }
- template <class X>
- inline TBitMapOps<X> operator^(const TBitMapOps<X>& x, const typename TBitMapOps<X>::TChunk& y) {
- return TBitMapOps<X>(x).Xor(y);
- }
- template <class X>
- inline TBitMapOps<X> operator^(const typename TBitMapOps<X>::TChunk& x, const TBitMapOps<X>& y) {
- return TBitMapOps<X>(x).Xor(y);
- }
- template <class X, class Y>
- inline TBitMapOps<X> operator-(const TBitMapOps<X>& x, const TBitMapOps<Y>& y) {
- return TBitMapOps<X>(x).SetDifference(y);
- }
- template <class X>
- inline TBitMapOps<X> operator-(const TBitMapOps<X>& x, const typename TBitMapOps<X>::TChunk& y) {
- return TBitMapOps<X>(x).SetDifference(y);
- }
- template <class X>
- inline TBitMapOps<X> operator-(const typename TBitMapOps<X>::TChunk& x, const TBitMapOps<X>& y) {
- return TBitMapOps<X>(x).SetDifference(y);
- }
- template <class X>
- inline TBitMapOps<X> operator~(const TBitMapOps<X>& x) {
- return TBitMapOps<X>(x).Flip();
- }
- /////////////////// Specialization ///////////////////////////
- template <size_t BitCount, typename TChunkType /*= ui64*/>
- class TBitMap: public TBitMapOps<TFixedBitMapTraits<BitCount, TChunkType>> {
- private:
- using TBase = TBitMapOps<TFixedBitMapTraits<BitCount, TChunkType>>;
- public:
- TBitMap()
- : TBase()
- {
- }
- TBitMap(typename TBase::TChunk val)
- : TBase(val)
- {
- }
- TBitMap(const TBitMap&) = default;
- TBitMap& operator=(const TBitMap&) = default;
- template <class T>
- TBitMap(const TBitMapOps<T>& bitmap)
- : TBase(bitmap)
- {
- }
- };
- using TDynBitMap = TBitMapOps<TDynamicBitMapTraits<ui64>>;
- #define Y_FOR_EACH_BIT(var, bitmap) for (size_t var = (bitmap).FirstNonZeroBit(); var != (bitmap).Size(); var = (bitmap).NextNonZeroBit(var))
- template <typename TTraits>
- struct THash<TBitMapOps<TTraits>> {
- size_t operator()(const TBitMapOps<TTraits>& elem) const {
- return elem.Hash();
- }
- };
|