diff --git a/include/Nazara/Core/Bitset.inl b/include/Nazara/Core/Bitset.inl index 68104b093..1b4cab200 100644 --- a/include/Nazara/Core/Bitset.inl +++ b/include/Nazara/Core/Bitset.inl @@ -16,12 +16,30 @@ namespace Nz { + /*! + * \class Nz::Bitset + * \brief Core class that represents a set of bits + * + * This class meets the requirements of Container, AllocatorAwareContainer, SequenceContainer + */ + + /*! + * \brief Constructs a Bitset object by default + */ + template Bitset::Bitset() : m_bitCount(0) { } + /*! + * \brief Constructs a Bitset object of bitCount bits to value val + * + * \param bitCount Number of bits + * \param val Value of those bits, by default false + */ + template Bitset::Bitset(unsigned int bitCount, bool val) : Bitset() @@ -29,12 +47,29 @@ namespace Nz Resize(bitCount, val); } + /*! + * \brief Constructs a Bitset object from the contents initialized with a copy of the null-terminated character string pointed to by bits + * + * \param bits Null-terminated character string containing only '0' and '1' + * + * \remark The length of the string is determined by the first null character, if there is no null character, the behaviour is undefined + */ + template Bitset::Bitset(const char* bits) : Bitset(bits, std::strlen(bits)) { } + /*! + * \brief Constructs a Bitset object from the contents initialized with a copy of the character string pointed to by bits takings the bitCount first characters + * + * \param bits Character string containing only '0' and '1' + * \param bitCount Number of characters to take into consideration + * + * \remark If the length of the string is inferior to the bitCount, the behaviour is undefined + */ + template Bitset::Bitset(const char* bits, unsigned int bitCount) : m_blocks(ComputeBlockCount(bitCount), 0U), @@ -45,12 +80,12 @@ namespace Nz switch (*bits++) { case '1': - // On adapte l'indice (inversion par rapport à la chaîne) + // We adapt the index (inversion in comparison to the string) Set(m_bitCount - i - 1, true); break; case '0': - // Tous les blocs ont été initialisés à zéro, rien à faire ici + // Each block is zero-initialised, nothing to do break; default: @@ -60,12 +95,24 @@ namespace Nz } } + /*! + * \brief Constructs a Bitset object from a Nz::String + * + * \param bits String containing only '0' and '1' + */ + template Bitset::Bitset(const String& bits) : Bitset(bits.GetConstBuffer(), bits.GetSize()) { } + /*! + * \brief Clears the content of the bitset, GetSize() is now equals to 0 + * + * \remark The memory allocated is not released + */ + template void Bitset::Clear() { @@ -73,6 +120,11 @@ namespace Nz m_blocks.clear(); } + /*! + * \brief Counts the number of bits set to 1 + * \return Number of bits set to 1 + */ + template unsigned int Bitset::Count() const { @@ -86,6 +138,10 @@ namespace Nz return count; } + /*! + * \brief Flips each bit of the bitset + */ + template void Bitset::Flip() { @@ -95,12 +151,26 @@ namespace Nz ResetExtraBits(); } + /*! + * \brief Finds the first bit set to one in the bitset + * \return Index of the first bit + */ + template unsigned int Bitset::FindFirst() const { return FindFirstFrom(0); } + /*! + * \brief Finds the next bit set to one in the bitset + * \return Index of the next bit if exists or npos + * + * \param bit Index of the bit, the search begin with bit + 1 + * + * \remark Produce a NazaraAssert if bit is greather than number of bits in bitset + */ + template unsigned int Bitset::FindNext(unsigned int bit) const { @@ -109,23 +179,32 @@ namespace Nz if (++bit >= m_bitCount) return npos; - // Le bloc du bit, l'indice du bit + // The block of the bit and its index unsigned int blockIndex = GetBlockIndex(bit); unsigned int bitIndex = GetBitIndex(bit); - // Récupération du bloc + // We get the block Block block = m_blocks[blockIndex]; - // On ignore les X premiers bits + // We ignore the X first bits block >>= bitIndex; - // Si le bloc n'est pas nul, c'est bon, sinon on doit chercher à partir du prochain bloc + // If the block is not empty, it's good, else we must keep trying with the next block if (block) return IntegralLog2Pot(block & -block) + bit; else return FindFirstFrom(blockIndex + 1); } + /*! + * \brief Gets the ith block + * \return Block in the bitset + * + * \param i Index of the block + * + * \remark Produce a NazaraAssert if i is greather than number of blocks in bitset + */ + template Block Bitset::GetBlock(unsigned int i) const { @@ -134,41 +213,71 @@ namespace Nz return m_blocks[i]; } + /*! + * \brief Gets the number of blocks + * \return Number of blocks + */ + template unsigned int Bitset::GetBlockCount() const { return m_blocks.size(); } + /*! + * \brief Gets the capacity of the bitset + * \return Capacity of the bitset + */ + template unsigned int Bitset::GetCapacity() const { return m_blocks.capacity()*bitsPerBlock; } + /*! + * \brief Gets the number of bits + * \return Number of bits + */ + template unsigned int Bitset::GetSize() const { return m_bitCount; } + /*! + * \brief Performs the "AND" operator between two bitsets + * + * \param a First bitset + * \param b Second bitset + * + * \remark The "AND" is performed with all the bits of the smallest bitset and the capacity of this is set to the largest of the two bitsets + */ + template void Bitset::PerformsAND(const Bitset& a, const Bitset& b) { std::pair minmax = std::minmax(a.GetBlockCount(), b.GetBlockCount()); - // On réinitialise nos blocs à zéro + // We reinitialise our blocks with zero m_blocks.clear(); m_blocks.resize(minmax.second, 0U); m_bitCount = std::max(a.GetSize(), b.GetSize()); - // Dans le cas du AND, nous pouvons nous arrêter à la plus petite taille (car x & 0 = 0) + // In case of the "AND", we can stop with the smallest size (because x & 0 = 0) for (unsigned int i = 0; i < minmax.first; ++i) m_blocks[i] = a.GetBlock(i) & b.GetBlock(i); ResetExtraBits(); } + /*! + * \brief Performs the "NOT" operator of the bitset + * + * \param a Bitset to negate + */ + template void Bitset::PerformsNOT(const Bitset& a) { @@ -181,6 +290,15 @@ namespace Nz ResetExtraBits(); } + /*! + * \brief Performs the "OR" operator between two bitsets + * + * \param a First bitset + * \param b Second bitset + * + * \remark The "OR" is performed with all the bits of the smallest bitset and the others are copied from the largest and the capacity of this is set to the largest of the two bitsets + */ + template void Bitset::PerformsOR(const Bitset& a, const Bitset& b) { @@ -201,6 +319,15 @@ namespace Nz ResetExtraBits(); } + /*! + * \brief Performs the "XOR" operator between two bitsets + * + * \param a First bitset + * \param b Second bitset + * + * \remark The "XOR" is performed with all the bits of the smallest bitset and the others are copied from the largest and the capacity of this is set to the largest of the two bitsets + */ + template void Bitset::PerformsXOR(const Bitset& a, const Bitset& b) { @@ -221,10 +348,16 @@ namespace Nz ResetExtraBits(); } + /*! + * \brief Checks if bitsets have one block in common + * + * \param bitset Bitset to test + */ + template bool Bitset::Intersects(const Bitset& bitset) const { - // On ne testera que les blocs en commun + // We only test the blocks in common unsigned int sharedBlocks = std::min(GetBlockCount(), bitset.GetBlockCount()); for (unsigned int i = 0; i < sharedBlocks; ++i) { @@ -237,40 +370,71 @@ namespace Nz return false; } + /*! + * \brief Reserves enough blocks to contain bitCount bits + * + * \param bitCount Number of bits to reserve + */ + template void Bitset::Reserve(unsigned int bitCount) { m_blocks.reserve(ComputeBlockCount(bitCount)); } + /*! + * \brief Resizes the bitset to the size of bitCount + * + * \param bitCount Number of bits to resize + * \param defaultVal Value of the bits if new size is greather than the old one + */ + template void Bitset::Resize(unsigned int bitCount, bool defaultVal) { - // On commence par changer la taille du conteneur, avec la valeur correcte d'initialisation + // We begin with changing the size of container, with the correct value of initialisation unsigned int lastBlockIndex = m_blocks.size() - 1; m_blocks.resize(ComputeBlockCount(bitCount), (defaultVal) ? fullBitMask : 0U); unsigned int remainingBits = GetBitIndex(m_bitCount); if (bitCount > m_bitCount && remainingBits > 0 && defaultVal) - // Initialisation des bits non-utilisés du dernier bloc avant le changement de taille + // Initialisation of unused bits in the last block before the size change m_blocks[lastBlockIndex] |= fullBitMask << remainingBits; m_bitCount = bitCount; ResetExtraBits(); } + /*! + * \brief Resets the bitset to zero bits + */ + template void Bitset::Reset() { Set(false); } + /*! + * \brief Resets the bit at the index + * + * \param bit Index of the bit + * + * \see UnboundReset + */ + template void Bitset::Reset(unsigned int bit) { Set(bit, false); } + /*! + * \brief Sets the bitset to val + * + * \param val Value of the bits + */ + template void Bitset::Set(bool val) { @@ -279,6 +443,17 @@ namespace Nz ResetExtraBits(); } + /*! + * \brief Sets the bit at the index + * + * \param bit Index of the bit + * \param val Value of the bit + * + * \remark Produce a NazaraAssert if bit is greather than number of bits in bitset + * + * \see UnboundSet + */ + template void Bitset::Set(unsigned int bit, bool val) { @@ -287,11 +462,19 @@ namespace Nz Block& block = m_blocks[GetBlockIndex(bit)]; Block mask = Block(1U) << GetBitIndex(bit); - // Activation du bit sans branching + // Activation of the bit without branching // https://graphics.stanford.edu/~seander/bithacks.html#ConditionalSetOrClearBitsWithoutBranching block = (block & ~mask) | (-val & mask); } + /*! + * \brief Set the ith block + * + * \param i Index of the block + * \param block Block to set + * + * \remark Produce a NazaraAssert if i is greather than number of blocks in bitset + */ template void Bitset::SetBlock(unsigned int i, Block block) { @@ -302,6 +485,12 @@ namespace Nz ResetExtraBits(); } + /*! + * \brief Swaps the two bitsets + * + * \param bitset Other bitset to swap + */ + template void Bitset::Swap(Bitset& bitset) { @@ -309,6 +498,17 @@ namespace Nz std::swap(m_blocks, bitset.m_blocks); } + /*! + * \brief Tests the ith bit + * \return true if bit is set + * + * \param bit Index of the bit + * + * \remark Produce a NazaraAssert if bit is greather than number of bits in bitset + * + * \see UnboundTest + */ + template bool Bitset::Test(unsigned int bit) const { @@ -317,22 +517,32 @@ namespace Nz return (m_blocks[GetBlockIndex(bit)] & (Block(1U) << GetBitIndex(bit))) != 0; } + /*! + * \brief Tests each block + * \return true if each block is set + */ + template bool Bitset::TestAll() const { - // Cas particulier du dernier bloc + // Special case for the last block Block lastBlockMask = GetLastBlockMask(); for (unsigned int i = 0; i < m_blocks.size(); ++i) { Block mask = (i == m_blocks.size() - 1) ? lastBlockMask : fullBitMask; - if (m_blocks[i] == mask) // Les extra bits sont à zéro, on peut donc tester sans procéder à un masquage + if (m_blocks[i] == mask) // The extra bits are set to zero, thus we can't test without proceeding with a mask return false; } return true; } + /*! + * \brief Tests if one bit is set + * \return true if one bit is set + */ + template bool Bitset::TestAny() const { @@ -348,12 +558,24 @@ namespace Nz return false; } + /*! + * \brief Tests if one bit is not set + * \return true if one bit is not set + */ + template bool Bitset::TestNone() const { return !TestAny(); } + /*! + * \brief Converts the bitset to template type + * \return The conversion of the bitset + * + * \remark Produce a NazaraAssert if the template type can not hold the number of bits + */ + template template T Bitset::To() const @@ -369,6 +591,11 @@ namespace Nz return value; } + /*! + * \brief Gives a string representation + * \return A string representation of the object with only '0' and '1' + */ + template String Bitset::ToString() const { @@ -383,12 +610,33 @@ namespace Nz return str; } + /*! + * \brief Resets the bit at the index + * + * \param bit Index of the bit + * + * \remark if bit is greather than the number of bits, the bitset is enlarged and the added bits are set to false + * + * \see Reset + */ + template void Bitset::UnboundedReset(unsigned int bit) { UnboundedSet(bit, false); } + /*! + * \brief Sets the bit at the index + * + * \param bit Index of the bit + * \param val Value of the bit + * + * \remark if bit is greather than the number of bits, the bitset is enlarged and the added bits are set to false and the one at bit is set to val + * + * \see Set + */ + template void Bitset::UnboundedSet(unsigned int bit, bool val) { @@ -402,6 +650,15 @@ namespace Nz } } + /*! + * \brief Tests the ith bit + * \return true if bit is set + * + * \param bit Index of the bit + * + * \see Test + */ + template bool Bitset::UnboundedTest(unsigned int bit) const { @@ -411,18 +668,33 @@ namespace Nz return false; } + /*! + * \brief Gets the ith bit + * \return bit in ith position + */ + template typename Bitset::Bit Bitset::operator[](int index) { return Bit(m_blocks[GetBlockIndex(index)], Block(1U) << GetBitIndex(index)); } + /*! + * \brief Gets the ith bit + * \return bit in ith position + */ + template bool Bitset::operator[](int index) const { return Test(index); } + /*! + * \brief Negates the bitset + * \return A new bitset which is the "NOT" of this bitset + */ + template Bitset Bitset::operator~() const { @@ -432,6 +704,13 @@ namespace Nz return bitset; } + /*! + * \brief Sets this bitset from a Nz::String + * \return A reference to this + * + * \param bits String containing only '0' and '1' + */ + template Bitset& Bitset::operator=(const String& bits) { @@ -441,6 +720,13 @@ namespace Nz return *this; } + /*! + * \brief Performs an "AND" with another bitset + * \return A reference to this + * + * \param bitset Other bitset + */ + template Bitset& Bitset::operator&=(const Bitset& bitset) { @@ -449,6 +735,13 @@ namespace Nz return *this; } + /*! + * \brief Performs an "OR" with another bitset + * \return A reference to this + * + * \param bitset Other bitset + */ + template Bitset& Bitset::operator|=(const Bitset& bitset) { @@ -457,6 +750,13 @@ namespace Nz return *this; } + /*! + * \brief Performs an "XOR" with another bitset + * \return A reference to this + * + * \param bitset Other bitset + */ + template Bitset& Bitset::operator^=(const Bitset& bitset) { @@ -465,13 +765,20 @@ namespace Nz return *this; } + /*! + * \brief Finds the position of the first bit set to true after the blockIndex + * \return The position of the bit + * + * \param blockIndex Index of the block + */ + template unsigned int Bitset::FindFirstFrom(unsigned int blockIndex) const { if (blockIndex >= m_blocks.size()) return npos; - // On cherche le premier bloc non-nul + // We are looking for the first non-null block unsigned int i = blockIndex; for (; i < m_blocks.size(); ++i) { @@ -479,22 +786,31 @@ namespace Nz break; } - // Est-ce qu'on a un bloc non-nul ? + // Do we have a non-null block ? if (i == m_blocks.size()) return npos; Block block = m_blocks[i]; - // Calcul de la position du LSB dans le bloc (et ajustement de la position) + // Compute the position of LSB in the block (and adjustement of the position) return IntegralLog2Pot(block & -block) + i*bitsPerBlock; } + /*! + * \brief Gets the mask associated to the last block + * \return Block which represents the mask + */ + template Block Bitset::GetLastBlockMask() const { return (Block(1U) << GetBitIndex(m_bitCount)) - 1U; } + /*! + * \brief Sets to '0' the last bits unassigned in the last block + */ + template void Bitset::ResetExtraBits() { @@ -503,24 +819,43 @@ namespace Nz m_blocks.back() &= mask; } + /*! + * \brief Computes the block count with the index of the bit + * \return Number of the blocks to contain the bit + */ + template unsigned int Bitset::ComputeBlockCount(unsigned int bitCount) { return GetBlockIndex(bitCount) + ((GetBitIndex(bitCount) != 0U) ? 1U : 0U); } + /*! + * \brief Computes the bit position in the block + * \return Index of the bit in the block + */ + template unsigned int Bitset::GetBitIndex(unsigned int bit) { return bit & (bitsPerBlock - 1U); // bit % bitsPerBlock } + /*! + * \brief Computes the block index with the index of the bit + * \return Index of the block containing the bit + */ + template unsigned int Bitset::GetBlockIndex(unsigned int bit) { return bit / bitsPerBlock; } + /*! + * \brief Flips the bit + * \return A reference to this + */ template typename Bitset::Bit& Bitset::Bit::Flip() @@ -530,12 +865,24 @@ namespace Nz return *this; } + /*! + * \brief Resets the bit + * \return A reference to this + */ + template typename Bitset::Bit& Bitset::Bit::Reset() { return Set(false); } + /*! + * \brief Sets the bit to a value + * \return A reference to this + * + * \param val Value of the bit + */ + template typename Bitset::Bit& Bitset::Bit::Set(bool val) { @@ -545,47 +892,85 @@ namespace Nz return *this; } + /*! + * \brief Tests the bit + * \return A reference to this + */ + template bool Bitset::Bit::Test() const { return m_block & m_mask; } + /*! + * \brief Gets the adress of the bit + * \return Nullptr + * + * \see std::addressof + */ + template template void* Bitset::Bit::operator&() const { - // Le template est nécessaire pour ne planter la compilation qu'à l'utilisation + // The template is necessary to make it fail only when used static_assert(!BadCall, "It is impossible to take the address of a bit in a bitset"); return nullptr; } + /*! + * \brief Converts this to bool + * \return true if bit set to '1' + */ + template Bitset::Bit::operator bool() const { return Test(); } + /*! + * \brief Sets the bit to a value + * \return A reference to this + * + * \param val Value of the bit + */ + template typename Bitset::Bit& Bitset::Bit::operator=(bool val) { return Set(val); } + /*! + * \brief Sets the bit to the value of another one + * \return A reference to this + * + * \param bit Other bit + */ + template typename Bitset::Bit& Bitset::Bit::operator=(const Bit& bit) { return Set(bit); } + /*! + * \brief Performs the operator "OR" on this bit with a boolean + * \return A reference to this + * + * \param val Value + */ + template typename Bitset::Bit& Bitset::Bit::operator|=(bool val) { - // Version sans branching: + // Version without branching: Set((val) ? true : Test()); - // Avec branching: + // With branching: /* if (val) Set(); @@ -594,13 +979,20 @@ namespace Nz return *this; } + /*! + * \brief Performs the operator "AND" on this bit with a boolean + * \return A reference to this + * + * \param val Value + */ + template typename Bitset::Bit& Bitset::Bit::operator&=(bool val) { - // Version sans branching: + // Version without branching: Set((val) ? Test() : false); - // Avec branching: + // With branching: /* if (!val) Reset(); @@ -609,13 +1001,20 @@ namespace Nz return *this; } + /*! + * \brief Performs the operator "XOR" on this bit with a boolean + * \return A reference to this + * + * \param val Value + */ + template typename Bitset::Bit& Bitset::Bit::operator^=(bool val) { - // Version sans branching: + // Version without branching: Set((val) ? !Test() : Test()); - // Avec branching: + // With branching: /* if (val) Flip(); @@ -624,13 +1023,20 @@ namespace Nz return *this; } + /*! + * \brief Performs the operator "RESET" on this bit with a boolean + * \return A reference to this + * + * \param val Value + */ + template typename Bitset::Bit& Bitset::Bit::operator-=(bool val) { - // Version sans branching: + // Version without branching: Set((val) ? false : Test()); - // Avec branching: + // With branching: /* if (val) Reset(); @@ -639,26 +1045,35 @@ namespace Nz return *this; } + /*! + * \brief Compares two bitsets + * \return true if the two bitsets are the same + * + * \param lhs First bitset to compare with + * \param rhs Other bitset to compare with + * + * \remark If one is bigger, they are equal only if the largest has the last bit set to '0' + */ + template bool operator==(const Bitset& lhs, const Bitset& rhs) { - // La comparaison part du principe que (uint8) 00001100 == (uint16) 00000000 00001100 - // et conserve donc cette propriété + // The comparison uses that (uint8) 00001100 == (uint16) 00000000 00001100 + // and thus conserve this property const Bitset& greater = (lhs.GetBlockCount() > rhs.GetBlockCount()) ? lhs : rhs; const Bitset& lesser = (lhs.GetBlockCount() > rhs.GetBlockCount()) ? rhs : lhs; unsigned int maxBlockCount = greater.GetBlockCount(); unsigned int minBlockCount = lesser.GetBlockCount(); - // Nous testons les blocs en commun pour vérifier l'égalité des bits + // We test the blocks in common to check the equality of bits for (unsigned int i = 0; i < minBlockCount; ++i) { if (lhs.GetBlock(i) != rhs.GetBlock(i)) return false; } - // Nous vérifions maintenant les blocs que seul le plus grand bitset possède, pour prétendre à l'égalité - // ils doivent tous être nuls + // Now we check for the blocks that only the biggest bitset owns, and to be equal, they must be set to '0' for (unsigned int i = minBlockCount; i < maxBlockCount; ++i) if (greater.GetBlock(i)) return false; @@ -666,12 +1081,28 @@ namespace Nz return true; } + /*! + * \brief Compares two bitsets + * \return false if the two bitsets are the same + * + * \param lhs First bitset to compare with + * \param rhs Other bitset to compare with + */ + template bool operator!=(const Bitset& lhs, const Bitset& rhs) { return !(lhs == rhs); } + /*! + * \brief Compares two bitsets + * \return true if the binary number represented by the lhs bitset is smaller + * + * \param lhs First bitset to compare with + * \param rhs Other bitset to compare with + */ + template bool operator<(const Bitset& lhs, const Bitset& rhs) { @@ -699,24 +1130,56 @@ namespace Nz return false; // They are equal } + /*! + * \brief Compares two bitsets + * \return true if the binary number represented by the lhs bitset is smaller or equal + * + * \param lhs First bitset to compare with + * \param rhs Other bitset to compare with + */ + template bool operator<=(const Bitset& lhs, const Bitset& rhs) { return lhs < rhs || lhs == rhs; } + /*! + * \brief Compares two bitsets + * \return true if the binary number represented by the lhs bitset is greather + * + * \param lhs First bitset to compare with + * \param rhs Other bitset to compare with + */ + template bool operator>(const Bitset& lhs, const Bitset& rhs) { return rhs < lhs; } + /*! + * \brief Compares two bitsets + * \return true if the binary number represented by the lhs bitset is greather or equal + * + * \param lhs First bitset to compare with + * \param rhs Other bitset to compare with + */ + template bool operator>=(const Bitset& lhs, const Bitset& rhs) { return rhs <= lhs; } + /*! + * \brief Performs the operator "AND" between two bitsets + * \return The result of operator "AND" + * + * \param lhs First bitset + * \param rhs Second bitset + */ + template Bitset operator&(const Bitset& lhs, const Bitset& rhs) { @@ -726,6 +1189,14 @@ namespace Nz return bitset; } + /*! + * \brief Performs the operator "OR" between two bitsets + * \return The result of operator "OR" + * + * \param lhs First bitset + * \param rhs Second bitset + */ + template Bitset operator|(const Bitset& lhs, const Bitset& rhs) { @@ -735,6 +1206,14 @@ namespace Nz return bitset; } + /*! + * \brief Performs the operator "XOR" between two bitsets + * \return The result of operator "XOR" + * + * \param lhs First bitset + * \param rhs Second bitset + */ + template Bitset operator^(const Bitset& lhs, const Bitset& rhs) { @@ -748,6 +1227,13 @@ namespace Nz namespace std { + /*! + * \brief Swaps two bitsets, specialisation of std + * + * \param lhs First bitset + * \param rhs Second bitset + */ + template void swap(Nz::Bitset& lhs, Nz::Bitset& rhs) { diff --git a/tests/Engine/Core/Bitset.cpp b/tests/Engine/Core/Bitset.cpp new file mode 100644 index 000000000..76c35c886 --- /dev/null +++ b/tests/Engine/Core/Bitset.cpp @@ -0,0 +1,117 @@ +#include +#include + +#include + +SCENARIO("Bitset", "[CORE][BITSET]") +{ + GIVEN("Allocate and constructor") + { + Nz::Bitset<> bitset(3); + + THEN("Capacity is 3 and size is 3") + { + REQUIRE(bitset.GetSize() == 3); + REQUIRE(bitset.GetCapacity() >= 3); + } + } + + GIVEN("Iterator and default constructor") + { + Nz::String anotherDataString("0101"); + Nz::Bitset<> defaultByte; + Nz::Bitset<> anotherData(anotherDataString.GetConstBuffer()); + + WHEN("We assign 'anotherData'") + { + defaultByte = anotherDataString; + REQUIRE(anotherData == defaultByte); + REQUIRE(defaultByte.GetSize() == 4); + REQUIRE(defaultByte.GetCapacity() >= 4); + REQUIRE(anotherData.GetSize() == 4); + REQUIRE(anotherData.GetCapacity() >= 4); + } + } + + GIVEN("Copy and Move constructor") + { + Nz::Bitset<> originalArray(3, true); + + WHEN("We copy") + { + Nz::Bitset<> copyBitset(originalArray); + + THEN("We get a copy") + { + REQUIRE(copyBitset == originalArray); + + AND_WHEN("We modify one") + { + for (auto i = 0; i < copyBitset.GetSize(); ++i) + copyBitset[i] = false; + + THEN("They are no more equal") + { + REQUIRE(copyBitset != originalArray); + REQUIRE(copyBitset == Nz::Bitset<>(3, false)); + } + } + } + } + + WHEN("We move") + { + Nz::Bitset<> moveBitset(std::move(originalArray)); + + THEN("These results are expected") + { + REQUIRE(moveBitset == Nz::Bitset<>(3, true)); + REQUIRE(originalArray.GetCapacity() == 0); + } + } + } + + GIVEN("Three bitsets") + { + Nz::Bitset<> first("01001"); + Nz::Bitset<> second("10110"); + Nz::Bitset<> third; + + WHEN("We swap first and third, then second and third and finally third and first") + { + Nz::Bitset<> oldFirst(first); + Nz::Bitset<> oldSecond(second); + + first.Swap(third); + std::swap(second, third); + third.Swap(first); + + THEN("First and second have been swapped and third is still empty.") + { + REQUIRE(oldFirst == second); + REQUIRE(oldSecond == first); + REQUIRE(third.GetSize() == 0); + } + } + } + + GIVEN("Two bitsets") + { + Nz::Bitset<> first("01001"); + Nz::Bitset<> second("10111"); + + WHEN("We perform operators") + { + Nz::Bitset<> andBitset = first & second; + Nz::Bitset<> orBitset = first | second; + Nz::Bitset<> xorBitset = first ^ second; + + THEN("They should operate as logical operators") + { + REQUIRE(andBitset == Nz::Bitset<>("00001")); + REQUIRE(orBitset == Nz::Bitset<>("11111")); + REQUIRE(xorBitset == Nz::Bitset<>("11110")); + } + } + } +}