diff options
author | udovichenko-r <udovichenko-r@yandex-team.ru> | 2022-02-10 16:49:22 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:49:22 +0300 |
commit | a6f6b22bda21d53d07bd2e0ff63a2b2abf69ede9 (patch) | |
tree | 5d5cb817648f650d76cf1076100726fd9b8448e8 /util/generic/bitmap.h | |
parent | d7e4eaec9d325e188dabb3eb1949a32a5229e9ce (diff) | |
download | ydb-a6f6b22bda21d53d07bd2e0ff63a2b2abf69ede9.tar.gz |
Restoring authorship annotation for <udovichenko-r@yandex-team.ru>. Commit 2 of 2.
Diffstat (limited to 'util/generic/bitmap.h')
-rw-r--r-- | util/generic/bitmap.h | 1222 |
1 files changed, 611 insertions, 611 deletions
diff --git a/util/generic/bitmap.h b/util/generic/bitmap.h index d8611b9e69b..f77d1824607 100644 --- a/util/generic/bitmap.h +++ b/util/generic/bitmap.h @@ -3,16 +3,16 @@ #include "fwd.h" #include "ptr.h" #include "bitops.h" -#include "typetraits.h" +#include "typetraits.h" #include "algorithm.h" -#include "utility.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 { +namespace NBitMapPrivate { // Returns number of bits set; result is in most significatnt byte inline ui64 ByteSums(ui64 x) { ui64 byteSums = x - ((x & 0xAAAAAAAAAAAAAAAAULL) >> 1); @@ -33,34 +33,34 @@ namespace NBitMapPrivate { 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_) +#if defined(_big_endian_) ::ReverseCopy(c.SmallData, c.SmallData + Y_ARRAY_SIZE(c.SmallData), target); -#else +#else ::Copy(c.SmallData, c.SmallData + Y_ARRAY_SIZE(c.SmallData), target); -#endif +#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) { @@ -69,43 +69,43 @@ namespace NBitMapPrivate { 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_) +#if defined(_big_endian_) ::ReverseCopy(source, source + BLOCK_SIZE, c.SmallData); -#else +#else ::Copy(source, source + BLOCK_SIZE, c.SmallData); -#endif +#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_) +#if defined(_big_endian_) ::ReverseCopy(source, source + count, c.SmallData); -#else +#else ::Copy(source, source + count, c.SmallData); -#endif +#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) { @@ -118,9 +118,9 @@ namespace NBitMapPrivate { 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) { @@ -131,91 +131,91 @@ namespace NBitMapPrivate { 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_VERIFY(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) @@ -229,7 +229,7 @@ namespace NBitMapPrivate { Data[i] = 0; } } - + template <typename TOtherChunk> TDynamicStorage(const TOtherChunk* data, size_t size) : Size(1) @@ -238,7 +238,7 @@ namespace NBitMapPrivate { { ExpandBitSize(size * sizeof(TOtherChunk) * 8, false); CopyData(Data, Size, data, size); - } + } Y_FORCE_INLINE void Swap(TDynamicStorage<TChunkType>& st) { DoSwap(Size, st.Size); @@ -246,20 +246,20 @@ namespace NBitMapPrivate { 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); + size = Max(size, Size * 2); TArrayHolder<TChunk> newData(new TChunk[size]); if (keepData) { for (size_t i = 0; i < Size; ++i) { @@ -268,140 +268,140 @@ namespace NBitMapPrivate { 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; }; - + } - -template <size_t BitCount, typename TChunkType> -struct TFixedBitMapTraits { + +template <size_t BitCount, typename TChunkType> +struct TFixedBitMapTraits { using TChunk = TChunkType; using TStorage = NBitMapPrivate::TFixedStorage<BitCount, TChunkType>; -}; - -template <typename TChunkType> -struct TDynamicBitMapTraits { +}; + +template <typename TChunkType> +struct TDynamicBitMapTraits { using TChunk = TChunkType; using TStorage = NBitMapPrivate::TDynamicStorage<TChunkType>; -}; - -template <class TTraits> -class TBitMapOps { +}; + +template <class TTraits> +class TBitMapOps { public: using TChunk = typename TTraits::TChunk; using TThis = TBitMapOps<TTraits>; - -private: + +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 + + // 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: + + 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 + if (val) + *Chunk |= static_cast<TChunk>(1) << Offset; + else *Chunk &= ~(static_cast<TChunk>(1) << Offset); - - return *this; - } - + + 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; - } - + 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)); - } - + return 0 == (*Chunk & (static_cast<TChunk>(1) << Offset)); + } + Y_FORCE_INLINE operator bool() const { - return 0 != (*Chunk & (static_cast<TChunk>(1) << Offset)); - } - + return 0 != (*Chunk & (static_cast<TChunk>(1) << Offset)); + } + Y_FORCE_INLINE TReference& Flip() { - *Chunk ^= static_cast<TChunk>(1) << Offset; - return *this; - } - }; - -private: - struct TSetOp { + *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 { + 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; - + 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; @@ -409,76 +409,76 @@ private: updateMask ^= FullChunk << endBitOffset; if (!updateMask) break; - } + } Mask.Data[chunk] = TUpdateOp::Op(Mask.Data[chunk], updateMask); bitOffset = 0; - } - } - -public: + } + } + +public: TBitMapOps() = default; TBitMapOps(TChunk val) { - Mask.Data[0] = val; - Mask.Sanitize(); + 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> + TBitMapOps(const TBitMapOps<T>& bitmap) + : Mask(bitmap.Mask.Data, bitmap.Mask.GetChunkCapacity()) + { + Mask.Sanitize(); } - template <class T> + template <class T> Y_FORCE_INLINE bool operator==(const TBitMapOps<T>& bitmap) const { - return Equal(bitmap); - } - + return Equal(bitmap); + } + Y_FORCE_INLINE TThis& operator=(const TThis& bitmap) { - if (this != &bitmap) { - TThis bm(bitmap); - Swap(bm); - } - return *this; - } - - template <class T> + 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> + TThis bm(bitmap); + Swap(bm); + return *this; + } + + template <class T> Y_FORCE_INLINE TThis& operator&=(const TBitMapOps<T>& bitmap) { - return And(bitmap); - } - + return And(bitmap); + } + Y_FORCE_INLINE TThis& operator&=(const TChunk& val) { - return And(val); - } - - template <class T> + return And(val); + } + + template <class T> Y_FORCE_INLINE TThis& operator|=(const TBitMapOps<T>& bitmap) { - return Or(bitmap); - } - + return Or(bitmap); + } + Y_FORCE_INLINE TThis& operator|=(const TChunk& val) { - return Or(val); - } - - template <class T> + return Or(val); + } + + template <class T> Y_FORCE_INLINE TThis& operator^=(const TBitMapOps<T>& bitmap) { - return Xor(bitmap); - } - + return Xor(bitmap); + } + Y_FORCE_INLINE TThis& operator^=(const TChunk& val) { - return Xor(val); - } - + return Xor(val); + } + template <class T> Y_FORCE_INLINE TThis& operator-=(const TBitMapOps<T>& bitmap) { return SetDifference(bitmap); @@ -490,81 +490,81 @@ public: 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); - } - + return TThis(*this).LShift(pos); + } + Y_FORCE_INLINE TThis operator>>(size_t pos) const { - return TThis(*this).RShift(pos); - } - + return TThis(*this).RShift(pos); + } + Y_FORCE_INLINE bool operator[](size_t pos) const { - return Get(pos); - } - + 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); - } - + return TReference(&Mask.Data[pos >> DivCount], ModMask & pos); + } + Y_FORCE_INLINE void Swap(TThis& bitmap) { - DoSwap(Mask, bitmap.Mask); - } - + 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) { + 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; - } - + 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) { + 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()) { + if (start < end && (start >> DivCount) < Mask.GetChunkCapacity()) { UpdateRange<TResetOp>(start, Min(end, Mask.GetBitCapacity())); - } - return *this; - } - + } + 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; - } - + 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; - } - + 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"); @@ -593,152 +593,152 @@ public: } Y_FORCE_INLINE TThis& Push(bool val) { - LShift(1); - return val ? Set(0) : *this; + LShift(1); + return val ? Set(0) : *this; } Y_FORCE_INLINE bool Pop() { - bool val = Get(0); - return RShift(1), val; + bool val = Get(0); + return RShift(1), val; } - // Clear entire bitmap. Current capacity is kept unchanged + // 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; + for (size_t i = 0; i < Mask.GetChunkCapacity(); ++i) { + Mask.Data[i] = 0; + } + return *this; } - // Returns bits capacity + // Returns bits capacity Y_FORCE_INLINE constexpr size_t Size() const noexcept { - return Mask.GetBitCapacity(); - } - + return Mask.GetBitCapacity(); + } + Y_FORCE_INLINE void Reserve(size_t bitCount) { Y_VERIFY(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] + 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]) + 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> + 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)); - } - + 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> + 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)); - } - + 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> + 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)); + 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> + 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)); - } - + 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) { + 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> + 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)); - } - + return Xor(TThis(bitmap)); + } + Y_FORCE_INLINE TThis& Xor(const TChunk& val) { - Mask.Data[0] ^= val; - Mask.Sanitize(); - return *this; - } - + 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]; @@ -756,204 +756,204 @@ public: } 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; - } + 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> + 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> + 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 + return Compare(TThis(bitmap)); + } + + // For backward compatibility Y_FORCE_INLINE static int Compare(const TThis& l, const TThis& r) { - return l.Compare(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)) { - // ... - // } + 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 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)); + 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])); } - // Continue with other chunks - ++i; } - - for (; i < Mask.GetChunkCapacity(); ++i) { - if (Mask.Data[i]) { - return BitsPerChunk * i + CountTrailingZeroBits(TIntType(Mask.Data[i])); - } - } } - return Size(); + return Size(); } Y_FORCE_INLINE size_t Count() const { size_t count = 0; - for (size_t i = 0; i < Mask.GetChunkCapacity(); ++i) + for (size_t i = 0; i < Mask.GetChunkCapacity(); ++i) count += ::NBitMapPrivate::CountBitsPrivate(Mask.Data[i]); return count; } @@ -983,7 +983,7 @@ public: if (chunkCount < Mask.GetChunkCapacity()) { ::memset(Mask.Data + chunkCount, 0, (Mask.GetChunkCapacity() - chunkCount) * sizeof(TChunk)); } - Mask.Sanitize(); + Mask.Sanitize(); } inline size_t Hash() const { @@ -1009,58 +1009,58 @@ public: return Mask.GetChunkCapacity(); } }; - -template <class X, class Y> + +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> + 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> + 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> + 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> + 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> + 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> + 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> + 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> + 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); -} - + 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> +template <class X> inline TBitMapOps<X> operator-(const TBitMapOps<X>& x, const typename TBitMapOps<X>::TChunk& y) { return TBitMapOps<X>(x).SetDifference(y); } @@ -1072,38 +1072,38 @@ inline TBitMapOps<X> operator-(const typename TBitMapOps<X>::TChunk& x, const TB template <class X> inline TBitMapOps<X> operator~(const TBitMapOps<X>& x) { - return TBitMapOps<X>(x).Flip(); -} - -/////////////////// Specialization /////////////////////////// - + return TBitMapOps<X>(x).Flip(); +} + +/////////////////// Specialization /////////////////////////// + template <size_t BitCount, typename TChunkType /*= ui64*/> class TBitMap: public TBitMapOps<TFixedBitMapTraits<BitCount, TChunkType>> { -private: +private: using TBase = TBitMapOps<TFixedBitMapTraits<BitCount, TChunkType>>; -public: - TBitMap() - : TBase() - { - } - - TBitMap(typename TBase::TChunk val) - : TBase(val) - { - } - +public: + TBitMap() + : TBase() + { + } + + TBitMap(typename TBase::TChunk val) + : TBase(val) + { + } + TBitMap(const TBitMap<BitCount, TChunkType>&) = default; - - template <class T> - TBitMap(const TBitMapOps<T>& bitmap) - : TBase(bitmap) - { - } -}; - + + 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> |