Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
382 changes: 382 additions & 0 deletions PolyEngine/Core/Src/Collections/BitMask.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,382 @@
#include "CorePCH.hpp"

#include <climits>

constexpr u64 ZERO = 0UL;

using namespace Poly;

constexpr BitMask::DataType TYPE_BIT = CHAR_BIT * sizeof(BitMask::DataType);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

constexpr size_t TYPE_BIT = CHAR_BIT * sizeof(BitMask::DataType);


BitMask::BitMask(size_t size)
: BitsNumber(size)
{
size_t arraySize = 0;

if (size%TYPE_BIT)
arraySize = size / TYPE_BIT + 1;
else
arraySize = size / TYPE_BIT;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change this whole block to arraySize = (size + TYPE_BIT - 1) / TYPE_BIT;


for (size_t i = 0; i < arraySize; i++)
BitList.PushBack(ZERO);
}

bool BitMask::Reset()
{
BitList.Clear();
BitsNumber = 0;
return true;
}

bool BitMask::Toggle(size_t index)
{
HEAVY_ASSERTE(index <= BitsNumber, "Out of bounds");
BitList[index / TYPE_BIT] ^= 1UL << index%TYPE_BIT;
return true;
}

bool BitMask::operator[](size_t index) const
{
DataType tempChar = BitList[index / TYPE_BIT];
tempChar = (tempChar >> index%TYPE_BIT) & 1UL;
return tempChar != 0;
}

bool BitMask::Set(size_t index, bool state)
{
HEAVY_ASSERTE(index<=BitsNumber, "Out of bounds");

size_t bitListIndex = index / TYPE_BIT;
size_t bitPosition = index % TYPE_BIT;

if (state)
BitList[bitListIndex] |= (1UL << bitPosition);
else
BitList[bitListIndex] &= ~(1UL << bitPosition);
return true;
}

BitMask BitMask::operator|(const BitMask& rhs) const
{
//Equal Dynarray sizes
if (BitList.GetSize() == rhs.BitList.GetSize())
{
size_t tempBitsNumber = 0;
if (BitsNumber > rhs.BitsNumber)
tempBitsNumber = BitsNumber;
else
tempBitsNumber = rhs.BitsNumber;

BitMask temp(tempBitsNumber);
for (size_t i = 0; i < BitList.GetSize(); i++)
temp.BitList[i] = BitList[i] | rhs.BitList[i];
return temp;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this blank line

else if (BitList.GetSize() > rhs.BitList.GetSize())
{
BitMask temp(BitsNumber);
for (size_t i = 0; i < rhs.BitList.GetSize(); i++)
temp.BitList[i] = BitList[i] | rhs.BitList[i];
for (size_t i = rhs.BitList.GetSize(); i < BitList.GetSize(); i++)
temp.BitList[i] = BitList[i];
return temp;
}

else if (BitList.GetSize() < rhs.BitList.GetSize())
{
BitMask temp(rhs.BitsNumber);
for (size_t i = 0; i < BitList.GetSize(); i++)
temp.BitList[i] = BitList[i] | rhs.BitList[i];
for (size_t i = BitList.GetSize(); i < rhs.BitList.GetSize(); i++)
temp.BitList[i] = rhs.BitList[i];
return temp;
}
return BitMask(0);
}

BitMask BitMask::operator^(const BitMask& rhs) const
{
if (BitList.GetSize() == rhs.BitList.GetSize())
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All three operators (&, |, ^) can be written much simpler. Core algorithm logic looks like this:

  1. newBitsNumber = max(BitsNumber, rhs.BitsNumber)
  2. Perform logic operation on values
  3. Trim returned BitMask to size == position of the leftmost bit set to 1.

We can discuss this further via pm.

{
size_t tempBitsNumber = 0;
if (BitsNumber > rhs.BitsNumber)
tempBitsNumber = BitsNumber;
else
tempBitsNumber = rhs.BitsNumber;

BitMask temp(tempBitsNumber);
for (size_t i = 0; i < BitList.GetSize(); i++)
temp.BitList[i] = BitList[i] ^ rhs.BitList[i];
return temp;
}
//Lhs size bigger than rhs size
else if (BitList.GetSize() > rhs.BitList.GetSize())
{
BitMask temp(BitsNumber);
for (size_t i = 0; i < rhs.BitList.GetSize(); i++)
temp.BitList[i] = BitList[i] ^ rhs.BitList[i];
for (size_t i = rhs.BitList.GetSize(); i < BitList.GetSize(); i++)
temp.BitList[i] = BitList[i];
return temp;
}
//rhs size bigger than lhs size
else if (BitList.GetSize() < rhs.BitList.GetSize())
{
BitMask temp(rhs.BitsNumber);
for (size_t i = 0; i < BitList.GetSize(); i++)
temp.BitList[i] = BitList[i] ^ rhs.BitList[i];
for (size_t i = BitList.GetSize(); i < rhs.BitList.GetSize(); i++)
temp.BitList[i] = rhs.BitList[i];
return temp;
}
return BitMask(0);
}

BitMask BitMask::operator&(const BitMask& rhs) const
{
if (BitList.GetSize() == rhs.BitList.GetSize())
{
size_t tempBitsNumber = 0;
if (BitsNumber > rhs.BitsNumber)
tempBitsNumber = BitsNumber;
else
tempBitsNumber = rhs.BitsNumber;

BitMask temp(tempBitsNumber);
for (size_t i = 0; i < BitList.GetSize(); i++)
temp.BitList[i] = BitList[i] & rhs.BitList[i];
return temp;
}
else if (BitList.GetSize() > rhs.BitList.GetSize())
{
BitMask temp(BitsNumber);
for (size_t i = 0; i < rhs.BitList.GetSize(); i++)
temp.BitList[i] = BitList[i] & rhs.BitList[i];
for (size_t i = rhs.BitList.GetSize(); i < BitList.GetSize(); i++)
temp.BitList[i] = ZERO;
return temp;
}
else if (BitList.GetSize() < rhs.BitList.GetSize())
{
BitMask temp(rhs.BitsNumber);
for (size_t i = 0; i < BitList.GetSize(); i++)
temp.BitList[i] = BitList[i] & rhs.BitList[i];
for (size_t i = BitList.GetSize(); i < rhs.BitList.GetSize(); i++)
temp.BitList[i] = ZERO;
return temp;
}
return BitMask(0);
}

BitMask& BitMask::operator~()
{
for (auto& x : BitList)
x = ~x;

return *this;
}


bool BitMask::Resize(const int offset)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resize should apply given size, not current size + offset. That way this method is simple
BitsNumber = size; BitList.Resize((size + TYPE_BIT - 1)/TYPE_BIT)

{
if (offset > 0)
{
if (BitsNumber + offset <= GetDynarraySize()*TYPE_BIT)
{
BitsNumber += offset;
return true;
}
else
{
size_t currentSize = BitList.GetSize();
size_t targetSize = 0;
if ((BitsNumber + offset) % TYPE_BIT)
targetSize = (BitsNumber + offset) / TYPE_BIT + 1;
else
targetSize = (BitsNumber + offset) / TYPE_BIT;

size_t pushBackCount = targetSize - currentSize;

for (size_t i = 0; i < pushBackCount; i++)
BitList.PushBack(ZERO);

BitsNumber += offset;
return true;
}
}

if (offset < 0)
{
HEAVY_ASSERTE(BitsNumber + offset<BitsNumber, "Out of bounds");
if (BitsNumber + offset >(GetDynarraySize() - 1)*TYPE_BIT)
{
BitsNumber += offset;
return true;
}
else
{
size_t currentSize = BitList.GetSize();
size_t targetSize = 0;
if (-1 * (BitsNumber + offset) % TYPE_BIT)
targetSize = (BitsNumber + offset) / TYPE_BIT + 1;
else
targetSize = (BitsNumber + offset) / TYPE_BIT;

size_t popBackCount = currentSize - targetSize;
for (size_t i = 0; i < popBackCount; i++)
BitList.PopBack();

BitsNumber += offset;
return true;
}
}


if (offset == 0)
{
return false;
}
return false;
}

size_t BitMask::BitListIndex(size_t index)
{
return index / TYPE_BIT;
}

BitMask& BitMask::operator|=(const BitMask& rhs)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to write this like that, simply write { *this = *this | rhs; }. Repeat this for other operators overloads.

{
//Equal Dynarray sizes
if (BitList.GetSize() == rhs.BitList.GetSize())
{
for (size_t i = 0; i < BitList.GetSize(); i++)
BitList[i] |= rhs.BitList[i];

if (rhs.BitsNumber > BitsNumber)
BitsNumber = rhs.BitsNumber;

return *this;
}

else if (BitList.GetSize() > rhs.BitList.GetSize())
{
for (size_t i = 0; i < rhs.BitList.GetSize(); i++)
BitList[i] |= rhs.BitList[i];

return *this;
}

else if (BitList.GetSize() < rhs.BitList.GetSize())
{
for (size_t i = 0; i < BitList.GetSize(); i++)
BitList[i] |= rhs.BitList[i];

size_t oldBitListSize = BitList.GetSize();

for (size_t i = 0; i < rhs.BitList.GetSize() - oldBitListSize; i++)
BitList.PushBack(ZERO);

for (size_t i = oldBitListSize; i < BitList.GetSize(); i++)
BitList[i] = rhs.BitList[i];

BitsNumber = rhs.BitsNumber;
return *this;
}
return *this;
}

BitMask& BitMask::operator^=(const BitMask& rhs)
{
if (BitList.GetSize() == rhs.BitList.GetSize())
{
for (size_t i = 0; i < BitList.GetSize(); i++)
BitList[i] ^= rhs.BitList[i];

if (rhs.BitsNumber > BitsNumber)
BitsNumber = rhs.BitsNumber;

return *this;
}
else if (BitList.GetSize() > rhs.BitList.GetSize())
{
for (size_t i = 0; i < rhs.BitList.GetSize(); i++)
BitList[i] ^= rhs.BitList[i];

return *this;
}
else if (BitList.GetSize() < rhs.BitList.GetSize())
{
for (size_t i = 0; i < BitList.GetSize(); i++)
BitList[i] ^= rhs.BitList[i];

size_t oldBitListSize = BitList.GetSize();

for (size_t i = 0; i < rhs.BitList.GetSize() - oldBitListSize; i++)
BitList.PushBack(ZERO);

for (size_t i = oldBitListSize; i < BitList.GetSize(); i++)
BitList[i] = rhs.BitList[i];

BitsNumber = rhs.BitsNumber;
return *this;
}
return *this;
}

BitMask& BitMask::operator&=(const BitMask& rhs)
{

if (BitList.GetSize() == rhs.BitList.GetSize())
{
for (size_t i = 0; i < BitList.GetSize(); i++)
BitList[i] &= rhs.BitList[i];

if (rhs.BitsNumber > BitsNumber)
BitsNumber = rhs.BitsNumber;

return *this;
}
else if (BitList.GetSize() > rhs.BitList.GetSize())
{
for (size_t i = 0; i < rhs.BitList.GetSize(); i++)
BitList[i] &= rhs.BitList[i];

for (size_t i = rhs.BitList.GetSize(); i < BitList.GetSize(); i++)
BitList[i] = ZERO;
return *this;
}
else if (BitList.GetSize() < rhs.BitList.GetSize())
{
for (size_t i = 0; i < BitList.GetSize(); i++)
BitList[i] &= rhs.BitList[i];

size_t oldBitListSize = BitList.GetSize();

for (size_t i = 0; i < rhs.BitList.GetSize() - oldBitListSize; i++)
BitList.PushBack(ZERO);

for (size_t i = oldBitListSize; i < BitList.GetSize(); i++)
BitList[i] = ZERO;

BitsNumber = rhs.BitsNumber;
return *this;
}
return *this;
}

bool BitMask::operator==(const BitMask rhs) const
{
if (BitsNumber != rhs.BitsNumber)
return false;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not necessarly, if one of the bitmasks is prefixed with a lot of zeroes this would still be true.
It would probably be helpfull to add method called Trim() which resizes BitMast to size == position of the leftmost bit set to 1. This way you can first trim, or get size after potential trim operation, and compare them to each other.


if (BitsNumber == rhs.BitsNumber)
{
for (size_t i = 0; i < BitList.GetSize(); i++)
if (BitList[i] != rhs.BitList[i])
return false;
return true;
}
return false;
}
Loading