29 #include "CoreMinimal.h"
31 #include "BitMask.generated.h"
36 USTRUCT(BlueprintType)
45 typedef uint64 GroupType;
50 static const int32 GroupSizeBits =
sizeof(GroupType) * 8;
55 static const int32 GroupShift = 6;
60 static const int32 GroupBitIndexMask = GroupSizeBits - 1;
70 UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category =
"Bit Mask",
71 Meta = (AllowPrivateAccess =
"true"))
77 UPROPERTY(VisibleAnywhere, Category =
"Bit Mask",
78 Meta = (AllowPrivateAccess =
"true"))
79 TArray<uint64> BitGroups;
85 FORCEINLINE GroupType GetBitGroup(int32 index)
const
87 checkf(index >= 0, TEXT(
"An index can't be negative: %d"), index);
88 if (index >= BitGroups.Num())
90 return BitGroups[index];
93 friend class StaticConstructor;
95 struct StaticConstructor
97 FORCEINLINE StaticConstructor()
99 for (
size_t i = 0; i < bitsCountLUTSize; ++i)
102 for (int32 j = 0; j < 8; ++j)
104 if (((i >> j) & 1) != 0)
112 static StaticConstructor staticConstructor;
117 static const int32 bitsCountLUTSize = 256;
122 static int32 bitsCountLUT[bitsCountLUTSize];
127 FORCEINLINE
static int32 GetOneBitsCount(GroupType bg)
129 return bitsCountLUT[0xff & bg] + bitsCountLUT[0xff & (bg >> 8)] +
130 bitsCountLUT[0xff & (bg >> 16)] +
131 bitsCountLUT[0xff & (bg >> 24)] +
132 bitsCountLUT[0xff & (bg >> 32)] +
133 bitsCountLUT[0xff & (bg >> 40)] +
134 bitsCountLUT[0xff & (bg >> 48)] +
135 bitsCountLUT[0xff & (bg >> 56)];
138 FORCEINLINE
bool FastAt(
const int32 Index)
const {
139 checkf(Index >= 0, TEXT(
"An index must be non-negative: %d"),
142 checkf(Index < Count,
143 TEXT(
"FastAt can work only with indexes less than Count: %d >= %d"), Index, Count);
145 const GroupType bg = BitGroups[Index >> GroupShift];
146 return (bg & (((GroupType)1) << (Index & GroupBitIndexMask))) !=
150 friend uint32 GetTypeHash(
const FBitMask &bm);
156 FORCEINLINE int32
Num()
const {
return Count; }
161 FORCEINLINE int32
GetCount()
const {
return Count; }
165 FORCEINLINE
FBitMask(
const int32 Capacity) { EnsureBitGroups(Capacity); }
167 FORCEINLINE
bool operator[](
const int32 Index)
const {
return At(Index); }
176 FORCEINLINE
bool At(
const int32 Index)
const
178 checkf(Index >= 0, TEXT(
"An index must be non-negative: %d"),
184 return FastAt(Index);
187 FORCEINLINE
void Set(
const int32 Index,
const bool value)
189 checkf(Index >= 0, TEXT(
"An index must be non-negative: %d"),
192 auto gi = Index >> GroupShift;
198 EnsureBitGroups(Index);
201 BitGroups[gi] |= (((GroupType)1) << (Index & GroupBitIndexMask));
205 if (gi < BitGroups.Num())
207 ~(((GroupType)1) << (Index & GroupBitIndexMask));
216 BitGroups = BitMask.BitGroups;
217 Count = BitMask.Count;
229 int32 DifferencesCount(
const FBitMask &BitMask)
const;
234 int32 InclusionsCount(
const FBitMask &BitMask)
const;
243 for (int32 gi = 0; gi < BitMask.BitGroups.
Num(); ++gi)
245 const GroupType bitGroup = GetBitGroup(gi);
246 const GroupType otherBitGroup = BitMask.BitGroups[gi];
248 const GroupType masked = otherBitGroup & bitGroup;
249 if (masked != otherBitGroup)
262 int32 Size = FMath::Min(BitGroups.Num(), BitMask.BitGroups.
Num());
263 if (Size == 0)
return false;
264 for (int32 gi = 0; gi < Size; ++gi)
266 const GroupType bitGroup = BitGroups[gi];
267 const GroupType otherBitGroup = BitMask.BitGroups[gi];
269 const GroupType masked = otherBitGroup & bitGroup;
270 if (masked != (GroupType)0)
279 bool Contains(
const bool bit)
const;
298 FORCEINLINE
bool next() {
return (++index) < owner.Count; }
302 return &owner == &i.
owner && index == i.
index;
307 return &owner != &i.
owner || index != i.
index;
320 int32 IndexOf(
const bool bit)
const;
327 BitGroups.Reserve(Groups);
329 while (BitGroups.Num() < Groups)
338 auto gi = index >> GroupShift;
339 EnsureBitGroupsCount(gi + 1);
350 FORCEINLINE int32
Max()
const {
return BitGroups.Max() << GroupShift; }
355 FORCEINLINE
void Reserve(
const int32 Capacity)
357 BitGroups.Reserve(Capacity >> GroupShift);
363 void Add(
const bool Bit);
371 FORCEINLINE
void Empty(
const int32 Slack = 0)
373 checkf(Slack >= 0, TEXT(
"A Slack must be non-negative: %d"), Slack);
376 BitGroups.Empty(Slack >> GroupShift);
386 FORCEINLINE
void Reset(
const int32 NewSize = 0)
388 checkf(NewSize >= 0, TEXT(
"A NewSize must be non-negative: %d"), NewSize);
391 BitGroups.Reset(NewSize >> GroupShift);
398 FORCEINLINE
void CopyTo(
bool *Array, int32 ArrayIndex)
const
400 for (int32 i = 0; i < Count; ++i)
402 Array[ArrayIndex + i] = FastAt(i);
409 void Insert(
const int32 Index,
const bool Bit);
414 void Remove(
const bool Bit);
421 void RemoveAt(
const int32 Index);
428 FORCEINLINE
void Erase(
const int32 Index)
430 checkf(Index >= 0 && Index < Count,
431 TEXT(
"An index is out of range: %d"), Index);
433 if (Index == --Count)
435 this->Set(Index,
false);
439 for (
auto s = Index; s < Count; ++s)
441 this->Set(s, this->At(s + 1));
449 FORCEINLINE
void CopyTo(TArray<bool> &array,
const int32 index = 0)
451 for (int32 i = 0; i < Count; ++i)
453 array[index + i] = this->FastAt(i);
462 int32 Size = FMath::Min(BitGroups.Num(), mask.BitGroups.
Num());
463 EnsureBitGroupsCount(Size);
465 for (int32 i = 0; i < Size; ++i)
467 BitGroups[i] &= mask.BitGroups[i];
470 this->Count = FMath::Min(this->Count, mask.Count);
480 int32 Size = FMath::Max(BitGroups.Num(), mask.BitGroups.
Num());
481 EnsureBitGroupsCount(Size);
483 for (int32 i = 0; i < mask.BitGroups.
Num(); ++i)
485 BitGroups[i] |= mask.BitGroups[i];
488 this->Count = FMath::Max(this->Count, mask.Count);
499 for (int32 i = 0; i < Count; ++i)
502 str += b ? TEXT(
"1") : TEXT(
"0");
513 if (std::addressof(a) == std::addressof(b))
516 const auto count = FMath::Max(a.BitGroups.
Num(), b.BitGroups.
Num());
517 for (int32 gi = 0; gi < count; ++gi)
519 if (a.GetBitGroup(gi) != b.GetBitGroup(gi))
527 if (std::addressof(a) == std::addressof(b))
530 const auto count = FMath::Max(a.BitGroups.
Num(), b.BitGroups.
Num());
531 for (int32 gi = 0; gi < count; ++gi)
533 if (a.GetBitGroup(gi) != b.GetBitGroup(gi))
541 auto count = FMath::Min(a.BitGroups.
Num(), b.BitGroups.
Num());
543 r.EnsureBitGroupsCount(count);
544 for (int32 i = 0; i < count; ++i)
546 r.BitGroups[i] = a.BitGroups[i] & b.BitGroups[i];
548 r.Count = FMath::Min(a.Count, b.Count);
554 auto count = FMath::Max(a.BitGroups.
Num(), b.BitGroups.
Num());
556 r.EnsureBitGroupsCount(count);
557 for (int32 i = 0; i < count; ++i)
559 r.BitGroups[i] = a.GetBitGroup(i) | b.GetBitGroup(i);
561 r.Count = FMath::Max(a.Count, b.Count);
567 auto hashCode = 1799407316;
568 hashCode = hashCode * -1521134295 + bm.Count;
569 for (
auto bg : bm.BitGroups)
571 hashCode = hashCode * -1521134295 + (int32)(bg >> 32);
572 hashCode = hashCode * -1521134295 + (int32)(bg & 0xFFFFFFFF);
The bit mask iterator.
Definition: BitMask.h:285
Iterator(const FBitMask &o, int32 i=0)
Definition: BitMask.h:290
bool operator*() const
Definition: BitMask.h:296
bool operator==(const Iterator &i) const
Definition: BitMask.h:300
const FBitMask & owner
Definition: BitMask.h:288
int32 index
Definition: BitMask.h:286
bool next()
Definition: BitMask.h:298
bool operator!=(const Iterator &i) const
Definition: BitMask.h:305
A memory-efficient bit mask.
Definition: BitMask.h:38
void EnsureBitGroups(const int32 index)
Ensure that there is enough bit groups for an index.
Definition: BitMask.h:336
void CopyTo(bool *Array, int32 ArrayIndex) const
Copy the bits to an array, with a specified offset.
Definition: BitMask.h:398
FBitMask & operator=(const FBitMask &BitMask)
Definition: BitMask.h:220
Iterator begin()
Definition: BitMask.h:313
void Reset(const int32 NewSize=0)
Same as empty, but doesn't change memory allocations, unless the new size is larger than the current ...
Definition: BitMask.h:386
friend std::ostream & operator<<(std::ostream &Str, const FBitMask &v)
void Reserve(const int32 Capacity)
Reserve space for a given number of bits.
Definition: BitMask.h:355
int32 Max() const
Get the current maximum number of bits that can be stored without the new allocations.
Definition: BitMask.h:350
int32 Num() const
The current number of bits in the mask.
Definition: BitMask.h:156
FBitMask & AndWith(const FBitMask &mask)
And the bitmask with a given mask.
Definition: BitMask.h:460
void Set(const FBitMask &BitMask)
Set this bit mask equal to another bit mask.
Definition: BitMask.h:214
void Empty(const int32 Slack=0)
Empties the array.
Definition: BitMask.h:371
bool operator[](const int32 Index) const
Definition: BitMask.h:167
void Set(const int32 Index, const bool value)
Definition: BitMask.h:187
bool At(const int32 Index) const
Get the bit flag at the specified index.
Definition: BitMask.h:176
Iterator end()
Definition: BitMask.h:315
friend Iterator
Definition: BitMask.h:311
FBitMask(const int32 Capacity)
Definition: BitMask.h:165
FString ToString() const
Convert the bit mask to a string representation.
Definition: BitMask.h:496
bool IncludesPartially(const FBitMask &BitMask) const
Check if the mask has any of the bits set in the supplied mask.
Definition: BitMask.h:260
FBitMask & OrWith(const FBitMask &mask)
Or the bitmask with a given mask.
Definition: BitMask.h:478
bool Includes(const FBitMask &BitMask) const
Does the mask has all of the bits set in the supplied mask.
Definition: BitMask.h:241
void Erase(const int32 Index)
Remove an element at the specified index.
Definition: BitMask.h:428
FBitMask()
Definition: BitMask.h:163
void EnsureBitGroupsCount(int32 Groups)
Ensure a bit group count.
Definition: BitMask.h:325
void CopyTo(TArray< bool > &array, const int32 index=0)
Copy to an array with a supplied offset.
Definition: BitMask.h:449
int32 GetCount() const
Get the current number of bits in the mask.
Definition: BitMask.h:161