diff --git a/include/Nazara/Core/Bitset.hpp b/include/Nazara/Core/Bitset.hpp index e4e2d8042..5c2746d16 100644 --- a/include/Nazara/Core/Bitset.hpp +++ b/include/Nazara/Core/Bitset.hpp @@ -64,6 +64,9 @@ namespace Nz void Set(std::size_t bit, bool val = true); void SetBlock(std::size_t i, Block block); + void ShiftLeft(std::size_t pos); + void ShiftRight(std::size_t pos); + void Swap(Bitset& bitset); bool Test(std::size_t bit) const; @@ -88,6 +91,12 @@ namespace Nz template Bitset& operator=(T value); Bitset& operator=(Bitset&& bitset) noexcept = default; + Bitset operator<<(std::size_t pos) const; + Bitset& operator<<=(std::size_t pos); + + Bitset operator>>(std::size_t pos) const; + Bitset& operator>>=(std::size_t pos); + Bitset& operator&=(const Bitset& bitset); Bitset& operator|=(const Bitset& bitset); Bitset& operator^=(const Bitset& bitset); diff --git a/include/Nazara/Core/Bitset.inl b/include/Nazara/Core/Bitset.inl index d29315afd..362157d40 100644 --- a/include/Nazara/Core/Bitset.inl +++ b/include/Nazara/Core/Bitset.inl @@ -2,8 +2,10 @@ // This file is part of the "Nazara Engine - Core module" // For conditions of distribution and use, see copyright notice in Config.hpp +#include #include #include +#include #include #include #include @@ -512,12 +514,117 @@ namespace Nz ResetExtraBits(); } + /*! + * \brief Shift all the bits toward the left + * + * \param pos Bit shifting to be applied + * + * \remark This does not changes the size of the bitset. + * + * \see operator<<= + */ + template + void Bitset::ShiftLeft(std::size_t pos) + { + if (pos == 0) + return; + + if (pos >= m_bitCount) + { + Reset(); + return; + } + + auto div = std::lldiv(pos, bitsPerBlock); + if (div.rem != 0) + { + std::size_t lastIndex = m_blocks.size() - 1; + std::size_t remaining = bitsPerBlock - div.rem; + + for (std::size_t i = lastIndex - div.quot; i > 0; --i) + m_blocks[i + div.quot] = (m_blocks[i] << div.rem) | (m_blocks[i - 1] >> remaining); + + m_blocks[div.quot] = m_blocks[0] << div.rem; + + std::fill_n(m_blocks.begin(), div.quot, Block(0)); + } + else + { + for (auto it = m_blocks.rbegin(); it != m_blocks.rend(); ++it) + { + if (static_cast(std::distance(m_blocks.rbegin(), it) + div.quot) < m_blocks.size()) + { + auto shiftedIt = it; + std::advance(shiftedIt, div.quot); + + *it = *shiftedIt; + } + else + *it = 0U; + } + } + + ResetExtraBits(); + } + + /*! + * \brief Shift all the bits toward the right + * + * \param pos Bit shifting to be applied + * + * \remark This does not changes the size of the bitset. + * + * \see operator>>= + */ + template + void Bitset::ShiftRight(std::size_t pos) + { + if (pos == 0) + return; + + if (pos >= m_bitCount) + { + Reset(); + return; + } + + auto div = std::lldiv(pos, bitsPerBlock); + if (div.rem != 0) + { + std::size_t lastIndex = m_blocks.size() - 1; + std::size_t remaining = bitsPerBlock - div.rem; + + for (std::size_t i = div.quot; i < last; ++i) + m_blocks[i - div.quot] = (m_blocks[i] >> div.rem) | (m_blocks[i + 1] << remaining); + + m_blocks[last - div.quot] = m_blocks[last] >> div.rem; + + std::fill_n(m_blocks.begin() + (m_blocks.size() - div.quot), div.quot, Block(0)); + } + else + { + for (auto it = m_blocks.begin(); it != m_blocks.end(); ++it) + { + if (static_cast(std::distance(m_blocks.begin(), it) + div.quot) < m_blocks.size()) + { + auto shiftedIt = it; + std::advance(shiftedIt, div.quot); + + *it = *shiftedIt; + } + else + *it = 0U; + } + } + + ResetExtraBits(); + } + /*! * \brief Swaps the two bitsets * * \param bitset Other bitset to swap */ - template void Bitset::Swap(Bitset& bitset) { @@ -763,6 +870,80 @@ namespace Nz return *this; } + /*! + * \brief Shift all the bits toward the left + * + * \param pos Bit shifting to be applied + * + * \return A copies of the bitset with shifted bits + * + * \remark This does not changes the size of the bitset. + * + * \see ShiftLeft + */ + template + Bitset Bitset::operator<<(std::size_t pos) const + { + Bitset bitset(*this); + return bitset <<= pos; + } + + /*! + * \brief Shift all the bits toward the left + * + * \param pos Bit shifting to be applied + * + * \return A reference to this + * + * \remark This does not changes the size of the bitset. + * + * \see ShiftLeft + */ + template + Bitset& Bitset::operator<<=(std::size_t pos) + { + ShiftLeft(pos); + + return *this; + } + + /*! + * \brief Shift all the bits toward the right + * + * \param pos Bit shifting to be applied + * + * \return A copies of the bitset with shifted bits + * + * \remark This does not changes the size of the bitset. + * + * \see ShiftRight + */ + template + Bitset Bitset::operator>>(std::size_t pos) const + { + Bitset bitset(*this); + return bitset >>= pos; + } + + /*! + * \brief Shift all the bits toward the right + * + * \param pos Bit shifting to be applied + * + * \return A reference to this + * + * \remark This does not changes the size of the bitset. + * + * \see ShiftRight + */ + template + Bitset& Bitset::operator>>=(std::size_t pos) + { + ShiftRight(pos); + + return *this; + } + /*! * \brief Performs an "AND" with another bitset * \return A reference to this