From 00c2dc9e89f93fc2a08af117d610f71318b333cb Mon Sep 17 00:00:00 2001 From: Aleksander Jacukowicz Date: Tue, 8 May 2018 14:01:38 +0200 Subject: [PATCH 1/4] BitMask --- PolyEngine/Core/Src/Collections/BitMask.cpp | 389 ++++++++++++++++ PolyEngine/Core/Src/Collections/BitMask.hpp | 48 ++ PolyEngine/Core/Src/CorePCH.hpp | 1 + PolyEngine/UnitTests/Src/BitMaskTests.cpp | 477 ++++++++++++++++++++ 4 files changed, 915 insertions(+) create mode 100644 PolyEngine/Core/Src/Collections/BitMask.cpp create mode 100644 PolyEngine/Core/Src/Collections/BitMask.hpp create mode 100644 PolyEngine/UnitTests/Src/BitMaskTests.cpp diff --git a/PolyEngine/Core/Src/Collections/BitMask.cpp b/PolyEngine/Core/Src/Collections/BitMask.cpp new file mode 100644 index 00000000..86b525b9 --- /dev/null +++ b/PolyEngine/Core/Src/Collections/BitMask.cpp @@ -0,0 +1,389 @@ +#include "CorePCH.hpp" + +#include + +constexpr u64 ZERO = 0UL; + +using namespace Poly; + +constexpr BitMask::DataType 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; + + for (int 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(RangeCheck(index), "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(RangeCheck(index), "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; +} + +bool BitMask::RangeCheck(size_t index) +{ + if (index >= BitsNumber || index < 0) + return false; + 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; + } + + 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()) + { + 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) +{ + 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 >= 0 && 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) +{ + //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; + + 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; +} \ No newline at end of file diff --git a/PolyEngine/Core/Src/Collections/BitMask.hpp b/PolyEngine/Core/Src/Collections/BitMask.hpp new file mode 100644 index 00000000..6352f39e --- /dev/null +++ b/PolyEngine/Core/Src/Collections/BitMask.hpp @@ -0,0 +1,48 @@ +#pragma once + +#include "Dynarray.hpp" + +namespace Poly { + class CORE_DLLEXPORT BitMask + { + public: + using DataType = unsigned short; + + BitMask(size_t size = sizeof(DataType)); + + //Bitwise operators + BitMask operator|(const BitMask& rhs) const; + BitMask operator^(const BitMask& rhs) const; + BitMask operator&(const BitMask& rhs) const; + BitMask& operator~(); + //Bitwise assignment operators + BitMask& operator|=(const BitMask& rhs); + BitMask& operator^=(const BitMask& rhs); + BitMask& operator&=(const BitMask& rhs); + + + bool operator==(const BitMask rhs) const; + bool operator!=(const BitMask rhs) const + { + return !(*this == rhs); + } + bool operator[](size_t index) const; + + //Set,Reset and toggle bits methods + bool Set(size_t index, bool state); + bool Reset(); + bool Toggle(size_t index); + + bool Resize(const int offset = 0); + + + size_t GetSize() { return BitsNumber; } + size_t GetDynarraySize() { return BitList.GetSize(); } + private: + inline bool RangeCheck(size_t index); + inline size_t BitListIndex(size_t index); + + Dynarray BitList; + size_t BitsNumber = 0; //How many bits are in the class + }; +} \ No newline at end of file diff --git a/PolyEngine/Core/Src/CorePCH.hpp b/PolyEngine/Core/Src/CorePCH.hpp index 4b3c306b..16045e11 100644 --- a/PolyEngine/Core/Src/CorePCH.hpp +++ b/PolyEngine/Core/Src/CorePCH.hpp @@ -31,6 +31,7 @@ #include "Collections/Dynarray.hpp" #include "Collections/Queue.hpp" #include "Collections/PriorityQueue.hpp" +#include "Collections/BitMask.hpp" // Other #include "Math/Color.hpp" diff --git a/PolyEngine/UnitTests/Src/BitMaskTests.cpp b/PolyEngine/UnitTests/Src/BitMaskTests.cpp new file mode 100644 index 00000000..a4cef2de --- /dev/null +++ b/PolyEngine/UnitTests/Src/BitMaskTests.cpp @@ -0,0 +1,477 @@ +#include + +#include + +using namespace Poly; + +constexpr BitMask::DataType TYPE_BIT = CHAR_BIT * sizeof(BitMask::DataType); + +//Function calculating expected Dynarray size ,for debugging purposes +size_t DynarraySize(BitMask mask) +{ + if (mask.GetSize() % TYPE_BIT) + return mask.GetSize() / TYPE_BIT + 1; + else + return mask.GetSize() / TYPE_BIT; +} + +TEST_CASE("BitMask constructors", "[BitMask]") +{ + //Default constructor + BitMask a; + REQUIRE(a.GetSize() == 1 * sizeof(BitMask::DataType)); + REQUIRE(a.GetDynarraySize() == DynarraySize(a)); + BitMask b; + REQUIRE(a.GetSize() == b.GetSize()); + REQUIRE(a.GetDynarraySize() == b.GetDynarraySize()); + //"Not even" constructor + BitMask c(20); + REQUIRE(c.GetSize() == 20); + REQUIRE(c.GetDynarraySize() == DynarraySize(c)); + for (size_t i = 0; i < a.GetSize(); i++) + REQUIRE(a[i] == false); + for (size_t i = 0; i < b.GetSize(); i++) + REQUIRE(b[i] == false); + for (size_t i = 0; i < c.GetSize(); i++) + REQUIRE(c[i] == false); + //Even constructor + BitMask d(16); + REQUIRE(d.GetSize() == 16); + REQUIRE(d.GetDynarraySize() == DynarraySize(d)); +} + +TEST_CASE("BitMask Set,Toggle and Reset", "[BitMask]") +{ + BitMask a(8); + //Set method + a.Set(7, true); + a.Set(0, true); + CHECK(a[7] == true); + CHECK(a[0] == true); + a.Set(7, false); + a.Set(0, false); + CHECK(a[7] == false); + CHECK(a[0] == false); + + //Toggle method + a.Toggle(1); + CHECK(a[1] == true); + a.Toggle(1); + CHECK(a[1] == false); + + //Reset method + a.Reset(); + CHECK(a.GetSize() == 0); + CHECK(a.GetDynarraySize() == DynarraySize(a)); +} +TEST_CASE("Bitwise operators", "[BitMask]") +{ + SECTION("Bitwise OR operator") + { + SECTION("Equal Dynarray sizes") + { + BitMask a(17), b(22), c; + a.Toggle(0); a.Toggle(3); a.Toggle(10); a.Toggle(15); + b.Toggle(0); b.Toggle(5); b.Toggle(11); b.Toggle(20); + c = a | b; + CHECK(c.GetSize() == 22); + CHECK(c.GetDynarraySize() == DynarraySize(c)); + for (size_t i = 0; i < c.GetSize(); i++) + { + if (i == 0 || i == 3 || i == 5 || i == 10 || + i == 11 || i == 15 || i == 20) + CHECK(c[i] == true); + else + CHECK(c[i] == false); + } + } + SECTION("Different Dynarray sizes") + { + BitMask a(16), b(5), c; + b.Toggle(1); b.Toggle(2); b.Toggle(4); + a.Toggle(0); a.Toggle(1); a.Toggle(8); a.Toggle(10); a.Toggle(15); + BitMask *left, *right; + left = &a; right = &b; + SECTION("Lhs size bigger than rhs size") + { + c = *left | *right; + CHECK(c.GetSize() == 16); + CHECK(c.GetDynarraySize() == DynarraySize(c)); + for (size_t i = 0; i < c.GetSize(); i++) + { + if (i == 0 || i == 1 || i == 2 || i == 4 || + i == 8 || i == 15 || i == 10) + CHECK(c[i] == true); + else + CHECK(c[i] == false); + } + } + SECTION("Rhs size bigger than lhs size") + { + left = &b; right = &a; + BitMask d = *left | *right; + CHECK(d.GetSize() == 16); + CHECK(d.GetDynarraySize() == DynarraySize(d)); + for (size_t i = 0; i < d.GetSize(); i++) + { + if (i == 0 || i == 1 || i == 2 || i == 4 || + i == 8 || i == 15 || i == 10) + CHECK(d[i] == true); + else + CHECK(d[i] == false); + } + } + } + } + SECTION("Bitwise XOR operator") + { + SECTION("Equal Dynarray sizes") + { + BitMask a(62), b(57), c; + a.Toggle(4); a.Toggle(21); a.Toggle(29); a.Toggle(59); + b.Toggle(4); b.Toggle(18); b.Toggle(21); b.Toggle(29); b.Toggle(55); + c = a ^ b; + CHECK(c.GetSize() == 62); + CHECK(c.GetDynarraySize() == DynarraySize(c)); + for (size_t i = 0; i < c.GetSize(); i++) + if (i == 18 || i == 59 || i == 55) + CHECK(c[i] == true); + else + CHECK(c[i] == false); + } + SECTION("Different Dynarray sizes") + { + BitMask a(4), b(25); + a.Toggle(0); a.Toggle(2); a.Toggle(3); + b.Toggle(0); b.Toggle(2); b.Toggle(10); b.Toggle(20); + BitMask *left = &a, *right = &b; + SECTION("Rhs size bigger than lhs size") + { + BitMask c = *left ^ *right; + CHECK(c.GetSize() == 25); + CHECK(c.GetDynarraySize() == DynarraySize(c)); + for (size_t i = 0; i < c.GetSize(); i++) + if (i == 3 || i == 10 || i == 20) + CHECK(c[i] == true); + else + CHECK(c[i] == false); + } + SECTION("Lhs size bigger than rhs size") + { + left = &b; right = &a; + BitMask c = *left ^ *right; + CHECK(c.GetSize() == 25); + CHECK(c.GetDynarraySize() == DynarraySize(c)); + for (size_t i = 0; i < c.GetSize(); i++) + if (i == 3 || i == 10 || i == 20) + CHECK(c[i] == true); + else + CHECK(c[i] == false); + } + } + } + SECTION("Bitwise AND operator") + { + SECTION("Equal Dynarray sizes") + { + BitMask a(12), b(14); + a.Toggle(0); a.Toggle(7); a.Toggle(8); a.Toggle(11); + b.Toggle(0); b.Toggle(1); b.Toggle(7); b.Toggle(9); b.Toggle(13); + BitMask c = a&b; + CHECK(c.GetSize() == 14); + CHECK(c.GetDynarraySize() == DynarraySize(c)); + for (size_t i = 0; i < c.GetSize(); i++) + { + if (i == 0 || i == 7) + CHECK(c[i] == true); + else + CHECK(c[i] == false); + } + SECTION("Different Dynarray sizes") + { + BitMask a(21), b(8); + a.Toggle(1); a.Toggle(5); a.Toggle(13); a.Toggle(14); a.Toggle(19); + b.Toggle(1); b.Toggle(5); b.Toggle(7); + BitMask *left, *right; + SECTION("Rhs size bigger than lhs size") + { + left = &b; right = &a; + BitMask c = *left & *right; + CHECK(c.GetSize() == 21); + CHECK(c.GetDynarraySize() == DynarraySize(c)); + for (size_t i = 0; i < c.GetSize(); i++) + if (i == 1 || i == 5) + CHECK(c[i] == true); + else + CHECK(c[i] == false); + } + SECTION("Lhs size bigger than rhs size") + { + left = &a; right = &b; + BitMask c = *left & *right; + CHECK(c.GetSize() == 21); + CHECK(c.GetDynarraySize() == DynarraySize(c)); + for (size_t i = 0; i < c.GetSize(); i++) + if (i == 1 || i == 5) + CHECK(c[i] == true); + else + CHECK(c[i] == false); + } + } + } + } +} + +TEST_CASE("Negate operator", "[BitMask]") +{ + BitMask a(10); + for (size_t i = 0; i < a.GetSize(); i++) + if (i % 2) //Toggle for odd numbers + a.Toggle(i); + + ~a; + for (size_t i = 0; i < a.GetSize(); i++) + if (i % 2) + CHECK(a[i] == false); + else + CHECK(a[i] == true); +} + +TEST_CASE("Bitwise assignment operators", "[BitMask]") +{ + SECTION("Bitwise OR assignment operator") + { + SECTION("Equal Dynarray sizes") + { + BitMask a(13), b(10); + a.Toggle(0); a.Toggle(5); a.Toggle(7); a.Toggle(10); + b.Toggle(0); b.Toggle(4); b.Toggle(5); + a |= b; + CHECK(a.GetSize() == 13); + CHECK(a.GetDynarraySize() == DynarraySize(a)); + for (size_t i = 0; i < a.GetSize(); i++) + { + if (i == 0 || i == 4 || i == 5 || i == 7 || i == 10) + CHECK(a[i] == true); + else + CHECK(a[i] == false); + } + } + SECTION("Different Dynarray sizes") + { + SECTION("Lhs size bigger than rhs size") + { + BitMask a(7), b(26); + a.Toggle(0); a.Toggle(2); a.Toggle(4); a.Toggle(6); + b.Toggle(0); b.Toggle(3); b.Toggle(15); b.Toggle(21); + + b |= a; + CHECK(b.GetSize() == 26); + CHECK(b.GetDynarraySize() == DynarraySize(b)); + for (size_t i = 0; i < b.GetSize(); i++) + if (i == 0 || i == 2 || i == 3 || i == 4 || i == 6 || i == 15 || i == 21) + CHECK(b[i] == true); + else + CHECK(b[i] == false); + } + + SECTION("Rhs size bigger than lhs size") + { + BitMask a(7), b(26); + a.Toggle(0); a.Toggle(2); a.Toggle(4); a.Toggle(6); + b.Toggle(0); b.Toggle(3); b.Toggle(15); b.Toggle(21); + + a |= b; + CHECK(a.GetSize() == 26); + CHECK(a.GetDynarraySize() == DynarraySize(a)); + for (size_t i = 0; i < a.GetSize(); i++) + if (i == 0 || i == 2 || i == 3 || i == 4 || i == 6 || i == 15 || i == 21) + CHECK(a[i] == true); + else + CHECK(a[i] == false); + } + } + } + + SECTION("Bitwise AND assignment operator") + { + SECTION("Equal dynarray sizes") + { + BitMask a(13), b(10); + a.Toggle(0); a.Toggle(3); a.Toggle(6); a.Toggle(12); a.Toggle(9); + b.Toggle(0); b.Toggle(3); b.Toggle(5); b.Toggle(9); + a &= b; + CHECK(a.GetSize() == 13); + CHECK(a.GetDynarraySize() == DynarraySize(a)); + for (size_t i = 0; i < a.GetSize(); i++) + { + if (i == 0 || i == 3 || i == 9) + CHECK(a[i] == true); + else + CHECK(a[i] == false); + } + } + SECTION("Different Dynarray sizes") + { + SECTION("Rhs dynarray size bigger than lhs size") + { + BitMask a(4), b(23); + a.Toggle(1); a.Toggle(2); a.Toggle(3); + b.Toggle(2); b.Toggle(3); b.Toggle(10); b.Toggle(20); b.Toggle(15); + a &= b; + CHECK(a.GetSize() == 23); + CHECK(a.GetDynarraySize() == DynarraySize(a)); + for (size_t i = 0; i < a.GetSize(); i++) + if (i == 2 || i == 3) + CHECK(a[i] == true); + else + CHECK(a[i] == false); + } + SECTION("Lhs dynarray size bigger than rhs size") + { + BitMask a(4), b(23); + a.Toggle(1); a.Toggle(2); a.Toggle(3); + b.Toggle(2); b.Toggle(3); b.Toggle(10); b.Toggle(20); b.Toggle(15); + b &= a; + CHECK(b.GetSize() == 23); + CHECK(b.GetDynarraySize() == DynarraySize(b)); + for (size_t i = 0; i < b.GetSize(); i++) + if (i == 2 || i == 3) + CHECK(b[i] == true); + else + CHECK(b[i] == false); + } + } + } + SECTION("Bitwise XOR assignment operator") + { + SECTION("Same dynarray sizes") + { + BitMask a(29), b(31); + a.Toggle(3); a.Toggle(7); a.Toggle(17); a.Toggle(23); a.Toggle(26); + b.Toggle(7); b.Toggle(15); b.Toggle(23); b.Toggle(26); b.Toggle(29); + a ^= b; + CHECK(a.GetSize() == 31); + CHECK(a.GetDynarraySize() == DynarraySize(a)); + for (size_t i = 0; i < a.GetSize(); i++) + if (i == 3 || i == 15 || i == 17 || i == 3 || i == 29) + CHECK(a[i] == true); + else + CHECK(a[i] == false); + } + SECTION("Different Dynarray sizes") + { + SECTION("Rhs dynnaray size bigger than lhs") + { + BitMask a(8), b(16); + a.Toggle(0); a.Toggle(3); a.Toggle(7); + b.Toggle(1); b.Toggle(3); b.Toggle(7); b.Toggle(12); b.Toggle(15); + a ^= b; + CHECK(a.GetSize() == 16); + CHECK(a.GetDynarraySize() == DynarraySize(a)); + for (size_t i = 0; i < a.GetSize(); i++) + if (i == 0 || i == 1 || i == 12 || i == 15) + CHECK(a[i] == true); + else + CHECK(a[i] == false); + } + SECTION("Lhs dynnaray size bigger than rhs") + { + BitMask a(8), b(16); + a.Toggle(0); a.Toggle(3); a.Toggle(7); + b.Toggle(1); b.Toggle(3); b.Toggle(7); b.Toggle(12); b.Toggle(15); + b ^= a; + CHECK(b.GetSize() == 16); + CHECK(b.GetDynarraySize() == DynarraySize(b)); + + for (size_t i = 0; i < b.GetSize(); i++) + if (i == 0 || i == 1 || i == 12 || i == 15) + CHECK(b[i] == true); + else + CHECK(b[i] == false); + } + } + } +} + +TEST_CASE("Comparision operator", "[BitMask]") +{ + SECTION("Different BitsNumbers") + { + BitMask a(4), b(5); + CHECK_FALSE(a == b); + } + SECTION("Equal BitsNumbers") + { + BitMask a(5), b(5); + a.Toggle(1); a.Toggle(3); + b.Toggle(1); b.Toggle(3); + CHECK(a == b); + BitMask c = b; + CHECK(c == b); + CHECK(c == a); + + a.Toggle(2); + CHECK_FALSE(a == b); + CHECK_FALSE(a == c); + } +} + +TEST_CASE("Negation operator", "[BitMask]") +{ + BitMask a(5), b(6); + CHECK(a != b); + + BitMask c(23), d(23); + c.Toggle(21); + d.Toggle(4); + + CHECK(c != d); +} + +TEST_CASE("Resize function", "[BitMask]") +{ + BitMask a(14); + CHECK(a.GetSize() == 14); + CHECK(a.GetDynarraySize() == DynarraySize(a)); + + a.Resize(6); + CHECK(a.GetSize() == 20); + CHECK(a.GetDynarraySize() == DynarraySize(a)); + + a.Resize(-2); + CHECK(a.GetSize() == 18); + CHECK(a.GetDynarraySize() == DynarraySize(a)); + + a.Resize(-4); + CHECK(a.GetSize() == 14); + CHECK(a.GetDynarraySize() == DynarraySize(a)); + + a.Resize(-8); + CHECK(a.GetSize() == 6); + CHECK(a.GetDynarraySize() == DynarraySize(a)); + + a.Resize(40); + CHECK(a.GetSize() == 46); + CHECK(a.GetDynarraySize() == DynarraySize(a)); + + a.Resize(-6); + CHECK(a.GetSize() == 40); + CHECK(a.GetDynarraySize() == DynarraySize(a)); + + a.Resize(-1); + CHECK(a.GetSize() == 39); + CHECK(a.GetDynarraySize() == DynarraySize(a)); + + a.Resize(-33); + CHECK(a.GetSize() == 6); + CHECK(a.GetDynarraySize() == DynarraySize(a)); + + a.Resize(-5); + CHECK(a.GetSize() == 1); + CHECK(a.GetDynarraySize() == DynarraySize(a)); + + a.Resize(-1); + CHECK(a.GetSize() == 0); + CHECK(a.GetDynarraySize() == DynarraySize(a)); +} \ No newline at end of file From 50cca81197431aa8f591ab38af227a64aab274bb Mon Sep 17 00:00:00 2001 From: Aleksander Jacukowicz Date: Wed, 16 May 2018 16:20:44 +0200 Subject: [PATCH 2/4] Travis CI correction --- PolyEngine/Core/Src/Collections/BitMask.cpp | 15 ++++----------- PolyEngine/Core/Src/Collections/BitMask.hpp | 1 - 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/PolyEngine/Core/Src/Collections/BitMask.cpp b/PolyEngine/Core/Src/Collections/BitMask.cpp index 86b525b9..2d086edf 100644 --- a/PolyEngine/Core/Src/Collections/BitMask.cpp +++ b/PolyEngine/Core/Src/Collections/BitMask.cpp @@ -18,7 +18,7 @@ BitMask::BitMask(size_t size) else arraySize = size / TYPE_BIT; - for (int i = 0; i < arraySize; i++) + for (size_t i = 0; i < arraySize; i++) BitList.PushBack(ZERO); } @@ -31,7 +31,7 @@ bool BitMask::Reset() bool BitMask::Toggle(size_t index) { - HEAVY_ASSERTE(RangeCheck(index), "Out of bounds"); + HEAVY_ASSERTE(index <= BitsNumber, "Out of bounds"); BitList[index / TYPE_BIT] ^= 1UL << index%TYPE_BIT; return true; } @@ -45,7 +45,7 @@ bool BitMask::operator[](size_t index) const bool BitMask::Set(size_t index, bool state) { - HEAVY_ASSERTE(RangeCheck(index), "Out of bounds"); + HEAVY_ASSERTE(index<=BitsNumber, "Out of bounds"); size_t bitListIndex = index / TYPE_BIT; size_t bitPosition = index % TYPE_BIT; @@ -57,13 +57,6 @@ bool BitMask::Set(size_t index, bool state) return true; } -bool BitMask::RangeCheck(size_t index) -{ - if (index >= BitsNumber || index < 0) - return false; - return true; -} - BitMask BitMask::operator|(const BitMask& rhs) const { //Equal Dynarray sizes @@ -216,7 +209,7 @@ bool BitMask::Resize(const int offset) if (offset < 0) { - HEAVY_ASSERTE(BitsNumber + offset >= 0 && BitsNumber + offset(GetDynarraySize() - 1)*TYPE_BIT) { BitsNumber += offset; diff --git a/PolyEngine/Core/Src/Collections/BitMask.hpp b/PolyEngine/Core/Src/Collections/BitMask.hpp index 6352f39e..9268185d 100644 --- a/PolyEngine/Core/Src/Collections/BitMask.hpp +++ b/PolyEngine/Core/Src/Collections/BitMask.hpp @@ -39,7 +39,6 @@ namespace Poly { size_t GetSize() { return BitsNumber; } size_t GetDynarraySize() { return BitList.GetSize(); } private: - inline bool RangeCheck(size_t index); inline size_t BitListIndex(size_t index); Dynarray BitList; From 7a41b9d584fff715f20f045af41114741808abf9 Mon Sep 17 00:00:00 2001 From: Aleksander Jacukowicz Date: Wed, 16 May 2018 16:39:24 +0200 Subject: [PATCH 3/4] Include added --- PolyEngine/UnitTests/Src/BitMaskTests.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/PolyEngine/UnitTests/Src/BitMaskTests.cpp b/PolyEngine/UnitTests/Src/BitMaskTests.cpp index a4cef2de..056ca788 100644 --- a/PolyEngine/UnitTests/Src/BitMaskTests.cpp +++ b/PolyEngine/UnitTests/Src/BitMaskTests.cpp @@ -1,4 +1,5 @@ #include +#include #include From 0f2d75181a437eeabf586fe0454b33800f23592b Mon Sep 17 00:00:00 2001 From: Aleksander Jacukowicz Date: Sun, 24 Jun 2018 14:08:16 +0200 Subject: [PATCH 4/4] Few modifications from code review and writing Proxy in progress --- PolyEngine/Core/Src/Collections/BitMask.cpp | 56 +++++++++++++++------ PolyEngine/Core/Src/Collections/BitMask.hpp | 25 +++++++-- PolyEngine/UnitTests/Src/BitMaskTests.cpp | 29 +++++++++-- 3 files changed, 90 insertions(+), 20 deletions(-) diff --git a/PolyEngine/Core/Src/Collections/BitMask.cpp b/PolyEngine/Core/Src/Collections/BitMask.cpp index 2d086edf..bf94b858 100644 --- a/PolyEngine/Core/Src/Collections/BitMask.cpp +++ b/PolyEngine/Core/Src/Collections/BitMask.cpp @@ -6,18 +6,12 @@ constexpr u64 ZERO = 0UL; using namespace Poly; -constexpr BitMask::DataType TYPE_BIT = CHAR_BIT * sizeof(BitMask::DataType); +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; - + size_t arraySize = (size + TYPE_BIT - 1) / TYPE_BIT; for (size_t i = 0; i < arraySize; i++) BitList.PushBack(ZERO); } @@ -73,7 +67,6 @@ BitMask BitMask::operator|(const BitMask& rhs) const temp.BitList[i] = BitList[i] | rhs.BitList[i]; return temp; } - else if (BitList.GetSize() > rhs.BitList.GetSize()) { BitMask temp(BitsNumber); @@ -83,7 +76,6 @@ BitMask BitMask::operator|(const BitMask& rhs) const temp.BitList[i] = BitList[i]; return temp; } - else if (BitList.GetSize() < rhs.BitList.GetSize()) { BitMask temp(rhs.BitsNumber); @@ -170,17 +162,23 @@ BitMask BitMask::operator&(const BitMask& rhs) const return BitMask(0); } -BitMask& BitMask::operator~() +BitMask BitMask::operator~() const { - for (auto& x : BitList) + BitMask temp = *this; + + for (auto& x : temp.BitList) x = ~x; - return *this; + return temp; } -bool BitMask::Resize(const int offset) +bool BitMask::Resize(size_t size) { + BitsNumber = size; + BitList.Resize((size + TYPE_BIT - 1) / TYPE_BIT); + return true; + /* if (offset > 0) { if (BitsNumber + offset <= GetDynarraySize()*TYPE_BIT) @@ -239,6 +237,7 @@ bool BitMask::Resize(const int offset) return false; } return false; + */ } size_t BitMask::BitListIndex(size_t index) @@ -248,6 +247,10 @@ size_t BitMask::BitListIndex(size_t index) BitMask& BitMask::operator|=(const BitMask& rhs) { + *this = *this | rhs; + + return *this; + /* //Equal Dynarray sizes if (BitList.GetSize() == rhs.BitList.GetSize()) { @@ -285,10 +288,15 @@ BitMask& BitMask::operator|=(const BitMask& rhs) return *this; } return *this; + */ } BitMask& BitMask::operator^=(const BitMask& rhs) { + *this = *this ^ rhs; + + return *this; + /* if (BitList.GetSize() == rhs.BitList.GetSize()) { for (size_t i = 0; i < BitList.GetSize(); i++) @@ -323,11 +331,15 @@ BitMask& BitMask::operator^=(const BitMask& rhs) return *this; } return *this; + */ } BitMask& BitMask::operator&=(const BitMask& rhs) { + *this = *this & rhs; + return *this; + /* if (BitList.GetSize() == rhs.BitList.GetSize()) { for (size_t i = 0; i < BitList.GetSize(); i++) @@ -364,6 +376,7 @@ BitMask& BitMask::operator&=(const BitMask& rhs) return *this; } return *this; + */ } bool BitMask::operator==(const BitMask rhs) const @@ -379,4 +392,19 @@ bool BitMask::operator==(const BitMask rhs) const return true; } return false; +} + +/* +BitMaskProxy BitMaskProxy::operator=(bool index) +{ + BitMaskProxy proxy; + proxy.bitValue = this[index]; + return proxy; +}*/ + +BitMaskProxy BitMaskProxy::operator[](size_t index) +{ + BitMaskProxy temp; + temp.bitValue = BitMask::operator[](index); + return temp; } \ No newline at end of file diff --git a/PolyEngine/Core/Src/Collections/BitMask.hpp b/PolyEngine/Core/Src/Collections/BitMask.hpp index 9268185d..79bff942 100644 --- a/PolyEngine/Core/Src/Collections/BitMask.hpp +++ b/PolyEngine/Core/Src/Collections/BitMask.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include "Dynarray.hpp" namespace Poly { @@ -14,7 +15,7 @@ namespace Poly { BitMask operator|(const BitMask& rhs) const; BitMask operator^(const BitMask& rhs) const; BitMask operator&(const BitMask& rhs) const; - BitMask& operator~(); + BitMask operator~() const; //Bitwise assignment operators BitMask& operator|=(const BitMask& rhs); BitMask& operator^=(const BitMask& rhs); @@ -22,10 +23,13 @@ namespace Poly { bool operator==(const BitMask rhs) const; - bool operator!=(const BitMask rhs) const + bool operator!=(const BitMask& rhs) const { return !(*this == rhs); } + + + //@todo Convert this method to return bit proxy bool operator[](size_t index) const; //Set,Reset and toggle bits methods @@ -33,15 +37,30 @@ namespace Poly { bool Reset(); bool Toggle(size_t index); - bool Resize(const int offset = 0); + bool Resize(size_t size = 0); size_t GetSize() { return BitsNumber; } size_t GetDynarraySize() { return BitList.GetSize(); } + protected: + private: inline size_t BitListIndex(size_t index); Dynarray BitList; size_t BitsNumber = 0; //How many bits are in the class }; + + + class CORE_DLLEXPORT BitMaskProxy : public BitMask { + private: + bool bitValue; + size_t bitIndex; + public: + BitMaskProxy(size_t size = sizeof(DataType)) : BitMask(size) {} + operator bool() { return bitValue; } + BitMaskProxy operator[](size_t index); + BitMaskProxy operator=(bool); + + }; } \ No newline at end of file diff --git a/PolyEngine/UnitTests/Src/BitMaskTests.cpp b/PolyEngine/UnitTests/Src/BitMaskTests.cpp index 056ca788..e06ca4ae 100644 --- a/PolyEngine/UnitTests/Src/BitMaskTests.cpp +++ b/PolyEngine/UnitTests/Src/BitMaskTests.cpp @@ -5,7 +5,7 @@ using namespace Poly; -constexpr BitMask::DataType TYPE_BIT = CHAR_BIT * sizeof(BitMask::DataType); +constexpr size_t TYPE_BIT = CHAR_BIT * sizeof(BitMask::DataType); //Function calculating expected Dynarray size ,for debugging purposes size_t DynarraySize(BitMask mask) @@ -230,7 +230,7 @@ TEST_CASE("Negate operator", "[BitMask]") if (i % 2) //Toggle for odd numbers a.Toggle(i); - ~a; + a=~a; for (size_t i = 0; i < a.GetSize(); i++) if (i % 2) CHECK(a[i] == false); @@ -430,6 +430,29 @@ TEST_CASE("Negation operator", "[BitMask]") CHECK(c != d); } +TEST_CASE("Resize function", "[BitMask]") +{ + BitMask a(10); + CHECK(a.GetSize() == 10); + CHECK(a.GetDynarraySize() == DynarraySize(a)); + + a.Toggle(1); a.Toggle(4); a.Toggle(6); a.Toggle(0); + a.Resize(5); + CHECK(a.GetSize() == 5); + CHECK(a.GetDynarraySize() == DynarraySize(a)); +} + +TEST_CASE("Proxy functions", "[BitMaskProxy]") +{ + bool value = false; + BitMaskProxy a(5); + a.Toggle(2); + value = a[2]; + CHECK(value == true); + value = a[1]; + CHECK(value == false); +} +/* TEST_CASE("Resize function", "[BitMask]") { BitMask a(14); @@ -475,4 +498,4 @@ TEST_CASE("Resize function", "[BitMask]") a.Resize(-1); CHECK(a.GetSize() == 0); CHECK(a.GetDynarraySize() == DynarraySize(a)); -} \ No newline at end of file +}*/ \ No newline at end of file