Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save Twilight-Dream-Of-Magic/c800dc2b69ee46600cbea6115d46ce6b to your computer and use it in GitHub Desktop.
Save Twilight-Dream-Of-Magic/c800dc2b69ee46600cbea6115d46ce6b to your computer and use it in GitHub Desktop.
C++ 2020 Utility Tools Library - Bitset (Concatenator & Spliter)
#include <bitset>
#include <bit>
#include <pair>
#include <type_traits>
#include <concepts>
#include <limits>
namespace UtilityTools::Bitset
{
template<std::size_t BitsetSize>
inline void Exclusive_OR(std::bitset<BitsetSize>& bits, const std::bitset<BitsetSize>& other_bits)
{
bits ^= other_bits;
}
template<size_t BitsetSize>
inline void BitLeftCircularShift(const std::bitset<BitsetSize>& bits, std::size_t shift_count, std::bitset<BitsetSize>& result_bits)
{
shift_count %= BitsetSize; // Limit count to range [0,N)
auto part_bits = bits << shift_count;
auto part2_bits = bits >> (BitsetSize - shift_count);
result_bits = part_bits | part2_bits;
/*
result_bits = (bits << count | bits >> (BitsetSize - count));
The shifted bits ^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ The wrapped bits
*/
}
template<size_t BitsetSize>
inline void BitRightCircularShift(const std::bitset<BitsetSize>& bits, std::size_t shift_count, std::bitset<BitsetSize>& result_bits )
{
shift_count %= BitsetSize; // Limit count to range [0,N)
auto part_bits = bits >> shift_count;
auto part2_bits = bits << (BitsetSize - shift_count);
result_bits = part_bits | part2_bits;
/*
result_bits = (bits >> count | bits << (BitsetSize - count));
The shifted bits ^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ The wrapped bits
*/
}
template<size_t BitsetSize>
inline void BitToggle( std::bitset<BitsetSize>& bits, std::size_t index )
{
constexpr std::bitset<BitsetSize> Mask{ 1 };
index %= BitsetSize; // Limit count to range [0,N)
bits ^= ( Mask << index );
}
template<std::size_t SIZE>
struct bitset_size
{
bitset_size(const std::bitset<SIZE>&)
{
}
static constexpr std::size_t BITSET_SIZE = SIZE;
};
template<std::size_t BinaryDataCopySize, std::size_t SplitPosition_OnePartSize, std::size_t SplitPosition_TwoPartSize = BinaryDataCopySize - SplitPosition_OnePartSize>
inline std::pair<std::bitset<SplitPosition_OnePartSize>, std::bitset<SplitPosition_TwoPartSize>> SplitBitset(const std::bitset<BinaryDataCopySize>& BinaryData)
{
constexpr std::size_t BinaryDataSize = decltype(bitset_size{ BinaryData })::BITSET_SIZE;
//invalied_split_binary
static_assert(BinaryDataCopySize != 0 && BinaryDataSize != 0, "Unexpected logic error: Binary data size BinaryData.size() must not be 0!\n源二进制数据大小BinaryData.size()不得为0");
//invalied_split_binary
static_assert(BinaryDataSize == BinaryDataCopySize,"Unexpected logic error: The source data size BinaryData.size() does not match the template parameter BitsetCopySize \n源数据大小BinaryData.size()与模板参数BinaryDataCopySize不一致");
if constexpr(SplitPosition_OnePartSize + SplitPosition_TwoPartSize != BinaryDataSize)
{
//invalied_split_binary
static_assert(CommonToolkit::Dependent_Always_Failed<decltype(BinaryDataCopySize)>,"Unexpected logic error: The size of the two target binary data comes from the total size of the source binary data after the split is completed, where one or both of the subsizes are not and range complementary. \n两个目标二进制数据的大小,来自于分割完成之后源二进制数据的总大小,其中有一个或者两个的子大小是不和范围互补的");
}
else if constexpr(SplitPosition_OnePartSize >= BinaryDataSize || SplitPosition_TwoPartSize >= BinaryDataSize)
{
//invalied_split_binary
static_assert(CommonToolkit::Dependent_Always_Failed<decltype(SplitPosition_OnePartSize)>, "Unexpected logic error: Binary data split point position out of range!\n二进制数据分割点位置超出范围");
}
else
{
using WordType = std::conditional_t<BinaryDataSize <= std::numeric_limits<unsigned long>::digits, unsigned long, unsigned long long>;
if constexpr(SplitPosition_OnePartSize <= std::numeric_limits<unsigned long long>::digits && SplitPosition_TwoPartSize <= std::numeric_limits<unsigned long long>::digits)
{
//Example binary data:
//A is: 0001'1010'0110'0111'0011'0010'0100(Digits size is 26 bit)
//B is: 13
//A with B split to C and D:
//C is: 0001'101'0011'0011
//D is: 0010'011'0010'0100
/*
The process of implementation:
High Digit Binary data calculation:
Step 1: 0000'0000'0000'0000'1101'0011'0011 = 0001'1010'0110'0111'0011'0010'0100 >> 13 (Bit Right Shift)
Step 2: 0000'1101'0011'0011 and 0000'0000'0000'0000'1101'0011'0011 It's actually the same!
Low Digit Binary data calculation:
Step 1: SelectedBinaryDigit = ~(1 << index)
If index is 14, Then 0000'0000'0000'0010'0000'0000'0000 = 0000'0000'0000'0000'0000'0000'0001 << 14 (Bit Left Shift)
Step 2: SelectedBinaryDigit = 1111'1111'1111'1101'1111'1111'1111 = ~0000'0000'0000'0010'0000'0000'0000 (Bit Not)
Step 3: 0001'1010'0110'0101'0011'0010'0100 = 0001'1010'0110'0111'0011'0010'0100 & 1111'1111'1111'1101'1111'1111'1111 (Bit And)
Step 4: Repeat the above steps until all binary data high bit 1s are changed to data bit 0
*/
std::bitset<BinaryDataCopySize> BitsetDataCopy { BinaryData };
/*
//Reset binary HighDigitPart bit
//复位二进制高位部分位
for(unsigned long long index = BitsetCopySize; index != 0 && index != SplitPosition_TwoPartSize; --index )
{
unsigned long long BitsetDataPosition = 1 << index;
unsigned long long BitsetDataPositionMask = ~BitsetDataPosition;
LowDigitPartDataWithInteger = LowDigitPartDataWithInteger & BitsetDataPositionMask;
}
//Reset binary LowDigitPart bit
//复位二进制低位部分位
for(unsigned long long index = SplitPosition_OnePartSize; index != 0 && index != BitsetCopySize + 1; ++index )
{
unsigned long long BitsetDataPosition = 1 << index;
unsigned long long BitsetDataPositionMask = ~BitsetDataPosition;
HighDigitPartDataWithInteger = HighDigitPartDataWithInteger & BitsetDataPositionMask;
}
*/
if constexpr(SplitPosition_OnePartSize == SplitPosition_TwoPartSize)
{
WordType BitsetDataWithInteger;
if constexpr(std::same_as<WordType, unsigned long long>)
BitsetDataWithInteger = BitsetDataCopy.to_ullong();
else
BitsetDataWithInteger = BitsetDataCopy.to_ulong();
//Discard binary LowDigitPart bits
//丢弃二进制低位部分位数
WordType HighDigitPartDataWithInteger = BitsetDataWithInteger >> SplitPosition_OnePartSize;
//Discard binary HighDigitPart bits
//丢弃二进制高位部分位数
WordType LowDigitPartDataWithInteger = BitsetDataWithInteger << SplitPosition_TwoPartSize;
LowDigitPartDataWithInteger = LowDigitPartDataWithInteger >> SplitPosition_TwoPartSize;
std::bitset<SplitPosition_OnePartSize> HighDigitPartBitsetData{ HighDigitPartDataWithInteger };
std::bitset<SplitPosition_TwoPartSize> LowDigitPartBitsetData{ LowDigitPartDataWithInteger };
return std::pair<std::bitset<SplitPosition_OnePartSize>, std::bitset<SplitPosition_TwoPartSize>> { HighDigitPartBitsetData, LowDigitPartBitsetData };
}
else
{
/*
10 <-> 1010
11 <-> 1011
Source Binary Data:
0000 0000 0001 0100 1110 0011 1001 1100
1010011100
01110011100
Bit Right Shift (Logic):
0000 0000 0000 0000 0000 0010 1001 1100 = 0000 0000 0001 0100 1110 0011 1001 1100 >> 11
Bits Right Rotate:
0111 0011 1000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0010 1001 1100 = (0000 0000 0001 0100 1110 0011 1001 1100 >> 11) | (0000 0000 0001 0100 1110 0011 1001 1100 << 32 - 11)
Bit Right Shift (Logic):
0001 1100 1110 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 = 0111 0011 1000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0010 1001 1100 >> 10
Bits Left Rotate:
0000 0000 0000 0000 0000 0011 1001 1100 = (0001 1100 1110 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 << (10 + 11)) | (0001 1100 1110 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 >> 32 - (10 + 11))
0000000000000-01010011100
Target Binary Pair:
1010011100
01110011100
*/
if constexpr(SplitPosition_OnePartSize < SplitPosition_TwoPartSize)
{
WordType BitsetDataWithInteger = 0;
WordType HighDigitPartDataWithInteger = 0;
WordType LowDigitPartDataWithInteger = 0;
if constexpr(std::same_as<WordType, unsigned long long>)
BitsetDataWithInteger = BitsetDataCopy.to_ullong();
else
BitsetDataWithInteger = BitsetDataCopy.to_ulong();
//Discard binary LowDigitPart bits
//丢弃二进制低位部分位数
HighDigitPartDataWithInteger = BitsetDataWithInteger >> SplitPosition_TwoPartSize;
//By right (circular shift) rotation, the low bits of binary data are moved to the high bits (and reversed)
//Facilitates discarding the original high bits of data
//通过右(循环移位)旋转,将二进制的低位比特的数据,移动至高位(并且反向)
//便于丢弃原高位比特的数据
LowDigitPartDataWithInteger = std::rotr(BitsetDataWithInteger, SplitPosition_TwoPartSize);
//Discard the original high bits of data
//丢弃原高位比特的数据
LowDigitPartDataWithInteger = LowDigitPartDataWithInteger >> SplitPosition_OnePartSize;
//By left (circular shift) rotation, the high bits of the binary data are moved to the low bits (and reversed)
//Used to recover the original low bits of data
//通过左(循环移位)旋转,将二进制的高位比特的数据,移动至低位(并且反向)
//用于恢复原低位比特的数据
LowDigitPartDataWithInteger = std::rotl(LowDigitPartDataWithInteger, SplitPosition_OnePartSize + SplitPosition_TwoPartSize);
std::bitset<SplitPosition_OnePartSize> HighDigitPartBitsetData{ HighDigitPartDataWithInteger };
std::bitset<SplitPosition_TwoPartSize> LowDigitPartBitsetData{ LowDigitPartDataWithInteger };
return std::pair<std::bitset<SplitPosition_OnePartSize>, std::bitset<SplitPosition_TwoPartSize>> { HighDigitPartBitsetData, LowDigitPartBitsetData };
}
if constexpr(SplitPosition_OnePartSize > SplitPosition_TwoPartSize)
{
WordType BitsetDataWithInteger = 0;
WordType HighDigitPartDataWithInteger = 0;
WordType LowDigitPartDataWithInteger = 0;
if constexpr(std::same_as<WordType, unsigned long long>)
BitsetDataWithInteger = BitsetDataCopy.to_ullong();
else
BitsetDataWithInteger = BitsetDataCopy.to_ulong();
//Discard binary LowDigitPart bits
//丢弃二进制低位部分位数
HighDigitPartDataWithInteger = BitsetDataWithInteger >> SplitPosition_TwoPartSize;
//By right (circular shift) rotation, the low bits of binary data are moved to the high bits (and reversed)
//Facilitates discarding the original high bits of data
//通过右(循环移位)旋转,将二进制的低位比特的数据,移动至高位(并且反向)
//便于丢弃原高位比特的数据
LowDigitPartDataWithInteger = std::rotr(BitsetDataWithInteger, SplitPosition_TwoPartSize);
//Discard the original high bits of data
//丢弃原高位比特的数据
LowDigitPartDataWithInteger = LowDigitPartDataWithInteger >> SplitPosition_OnePartSize;
//By left (circular shift) rotation, the high bits of the binary data are moved to the low bits (and reversed)
//Used to recover the original low bits of data
//通过左(循环移位)旋转,将二进制的高位比特的数据,移动至低位(并且反向)
//用于恢复原低位比特的数据
LowDigitPartDataWithInteger = std::rotl(LowDigitPartDataWithInteger, SplitPosition_OnePartSize + SplitPosition_TwoPartSize);
std::bitset<SplitPosition_OnePartSize> HighDigitPartBitsetData{ HighDigitPartDataWithInteger };
std::bitset<SplitPosition_TwoPartSize> LowDigitPartBitsetData{ LowDigitPartDataWithInteger };
return std::pair<std::bitset<SplitPosition_OnePartSize>, std::bitset<SplitPosition_TwoPartSize>> { HighDigitPartBitsetData, LowDigitPartBitsetData };
}
}
}
else
{
std::bitset<SplitPosition_OnePartSize> HighDigitPartBitsetData;
std::bitset<SplitPosition_TwoPartSize> LowDigitPartBitsetData;
for(std::size_t index = 0; index != BinaryData.size(); ++index)
{
if(index < SplitPosition_OnePartSize)
{
if(BinaryData.operator[](index))
{
LowDigitPartBitsetData.operator[](index) = BinaryData.operator[](index);
}
}
else
{
if(BinaryData.operator[](index))
{
HighDigitPartBitsetData.operator[](index - SplitPosition_OnePartSize) = BinaryData.operator[](index);
}
}
}
}
}
}
template <std::size_t BitsetSize, std::size_t BitsetSize2 >
inline std::bitset <BitsetSize + BitsetSize2> ConcatenateBitset( const std::bitset<BitsetSize>& leftBinaryData, const std::bitset<BitsetSize2>& rightBinaryData, bool isNeedSwapTwoPart )
{
constexpr unsigned long long ConcatenateBinarySize = BitsetSize + BitsetSize2;
//invalied_concat_binary
static_assert(decltype(bitset_size{ leftBinaryData })::BITSET_SIZE != 0 && decltype(bitset_size{ rightBinaryData })::BITSET_SIZE != 0, "Unexpected logic error: The size of the two parts of the binary data that need to be concatenated, the size of their bits, cannot have either one of them be 0 or both of them be 0!\n需要的串接的两个部分的二进制数据,它们的位数的大小,不能有任意一个是0或者两个都是0");
constexpr unsigned long long ConcatenateBinarySize2 = decltype(bitset_size{ leftBinaryData })::BITSET_SIZE + decltype(bitset_size{ rightBinaryData })::BITSET_SIZE;
//invalied_concat_binary
static_assert(ConcatenateBinarySize == ConcatenateBinarySize2, "Unexpected logic error: The source data size leftBinaryData.size() + rightBinaryData.size() does not match the result of the template parameter BitsetSize + BitsetSize2!\n源数据大小 leftBinaryData.size() + rightBinaryData.size() 与模板参数 BitsetSize + BitsetSize2 的结果不一致");
using WordType = std::conditional_t<ConcatenateBinarySize <= std::numeric_limits<unsigned long>::digits, unsigned long, unsigned long long>;
if constexpr(ConcatenateBinarySize <= std::numeric_limits<unsigned long long>::digits)
{
//Example binary data:
//A is: 0000'1101'0011'0011(Digits size is 13 bit)
//B is: 0001'0011'0010'0100(Digits size is 13 bit)
//C from A concate B: 0001'1010'0110'0111'0011'0010'0100
/*
The process of implementation:
Binary data calculation:
Step 1: 0001'1010'0110'0110'0000'0000'0000 = 0000'1101'0011'0011 << 13 (Bit Left Shift)
Step 2: 0001'0011'0010'0100 and 0000'0000'0000'0001'0011'0010'0100, It's actually the same!
Step 3: 0001'1010'0110'0111'0011'0010'0100 = 0001'1010'0110'0110'0000'0000'0000 | 0000'0000'0000'0001'0011'0010'0100 (Bit Or)
*/
//Discard binary HighDigitPart bit and Reset binary LowDigitPart bit, then Set binary LowDigitPart bit.
//丢弃二进制高位部分的位数并重置二进制低位部分的位数,然后设置二进制低位部分的位数。
if(!isNeedSwapTwoPart)
{
WordType ConcatenatedBinaryDataWithInteger = leftBinaryData.to_ullong() << leftBinaryData.size() | rightBinaryData.to_ullong();
std::bitset<ConcatenateBinarySize> ConcatenatedBitset( ConcatenatedBinaryDataWithInteger );
return ConcatenatedBitset;
}
else
{
WordType ConcatenatedBinaryDataWithInteger = rightBinaryData.to_ullong() << rightBinaryData.size() | leftBinaryData.to_ullong();
std::bitset<ConcatenateBinarySize> ConcatenatedBitset( ConcatenatedBinaryDataWithInteger );
return ConcatenatedBitset;
}
}
else
{
if(!isNeedSwapTwoPart)
{
//Binary string concat
return std::bitset<ConcatenateBinarySize>( leftBinaryData.to_string() + rightBinaryData.to_string() );
}
else
{
//Binary string concat
return std::bitset<ConcatenateBinarySize>( rightBinaryData.to_string() + leftBinaryData.to_string() );
}
}
}
inline std::bitset<64> ClassicByteArrayToBitset64Bit(const std::vector<unsigned char>& ByteArray)
{
unsigned long long TemporaryInteger = 0;
if(ByteArray.size() != sizeof(TemporaryInteger))
{
std::length_error conversion_type_data_is_undefined_behaviour("This object CharacterArray size is not equal 8 !");
throw conversion_type_data_is_undefined_behaviour;
}
std::memcpy(&TemporaryInteger, ByteArray.data(), sizeof(TemporaryInteger));
std::bitset<64> Bitset64Object(TemporaryInteger);
return Bitset64Object;
}
inline std::vector<unsigned char> ClassicByteArrayFromBitset64Bit(const std::bitset<64>& Bitset64Object)
{
unsigned long long TemporaryInteger { Bitset64Object.to_ullong() };
std::vector<unsigned char> ByteArray { reinterpret_cast<unsigned char *>( &TemporaryInteger ), reinterpret_cast<unsigned char *>( &TemporaryInteger + 1 ) };
return ByteArray;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment