Core/Bitset: Add bit shifting functions

Former-commit-id: a5d9aa0da769a1f5b70e5db8eed5c370e1e9b076 [formerly c8338571cedad83c557ffa9210f8e11a928157f2] [formerly 47e36d22755f77c878f5277a99f61388f096a449 [formerly 12f27f9470c490160deb869f83736c000bb18d93]]
Former-commit-id: bc971c681a184ac7d340fa1d5b053f2e4a8cd156 [formerly 2a84c48ec1ab8970fb768dc5d925e7712cb193ea]
Former-commit-id: 728cccf49da4bb48416aa91e3687fa7fad8035ef
This commit is contained in:
Lynix 2016-10-07 19:16:25 +02:00
parent d99cfa5181
commit 2b28b217d1
2 changed files with 191 additions and 1 deletions

View File

@ -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<typename T> 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);

View File

@ -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 <Nazara/Core/Bitset.hpp>
#include <Nazara/Core/Error.hpp>
#include <Nazara/Math/Algorithm.hpp>
#include <cstdlib>
#include <limits>
#include <utility>
#include <Nazara/Core/Debug.hpp>
@ -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<typename Block, class Allocator>
void Bitset<Block, Allocator>::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::size_t>(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<typename Block, class Allocator>
void Bitset<Block, Allocator>::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::size_t>(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<typename Block, class Allocator>
void Bitset<Block, Allocator>::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<typename Block, class Allocator>
Bitset<Block, Allocator> Bitset<Block, Allocator>::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<typename Block, class Allocator>
Bitset<Block, Allocator>& Bitset<Block, Allocator>::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<typename Block, class Allocator>
Bitset<Block, Allocator> Bitset<Block, Allocator>::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<typename Block, class Allocator>
Bitset<Block, Allocator>& Bitset<Block, Allocator>::operator>>=(std::size_t pos)
{
ShiftRight(pos);
return *this;
}
/*!
* \brief Performs an "AND" with another bitset
* \return A reference to this