feat(containers): enable TBitset to support custom block type
This commit is contained in:
parent
432b6e0a6b
commit
dd8b698bb3
@ -284,11 +284,11 @@ void TestBitset()
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
FBitset BitsetA(64, 0x0339'0339'0339'0339ull);
|
FBitset BitsetA(64, 0x0139'0239'0339'0439ull);
|
||||||
uint64 IntA = 0x0339'0339'0339'0339ull;
|
uint64 IntA = 0x0139'0239'0339'0439ull;
|
||||||
|
|
||||||
FBitset BitsetB(32, 0x017F'017Full);
|
FBitset BitsetB(32, 0x017F'027Full);
|
||||||
uint32 IntB = 0x017F'017Full;
|
uint32 IntB = 0x017F'027Full;
|
||||||
|
|
||||||
FBitset BitsetANDA = BitsetA; BitsetANDA &= BitsetB;
|
FBitset BitsetANDA = BitsetA; BitsetANDA &= BitsetB;
|
||||||
FBitset BitsetANDB = BitsetB; BitsetANDB &= BitsetA;
|
FBitset BitsetANDB = BitsetB; BitsetANDB &= BitsetA;
|
||||||
@ -317,11 +317,11 @@ void TestBitset()
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
FBitset BitsetA(64, 0x0339'0339'0339'0339ull);
|
FBitset BitsetA(64, 0x0139'0239'0339'0439ull);
|
||||||
uint64 IntA = 0x0339'0339'0339'0339ull;
|
uint64 IntA = 0x0139'0239'0339'0439ull;
|
||||||
|
|
||||||
FBitset BitsetB(32, 0x017F'017Full);
|
FBitset BitsetB(32, 0x017F'027Full);
|
||||||
uint32 IntB = 0x017F'017Full;
|
uint32 IntB = 0x017F'027Full;
|
||||||
|
|
||||||
always_check(((BitsetA & BitsetB).ToIntegral() == (IntA & IntB)));
|
always_check(((BitsetA & BitsetB).ToIntegral() == (IntA & IntB)));
|
||||||
always_check(((BitsetA | BitsetB).ToIntegral() == (IntA | IntB)));
|
always_check(((BitsetA | BitsetB).ToIntegral() == (IntA | IntB)));
|
||||||
@ -329,8 +329,8 @@ void TestBitset()
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
FBitset Bitset(64, 0x0339'0339'0339'0339ull);
|
FBitset Bitset(64, 0x0139'0239'0339'0439ull);
|
||||||
uint64 Int = 0x0339'0339'0339'0339ull;
|
uint64 Int = 0x0139'0239'0339'0439ull;
|
||||||
|
|
||||||
always_check(((Bitset << 40).ToIntegral() == (Int << 40)));
|
always_check(((Bitset << 40).ToIntegral() == (Int << 40)));
|
||||||
always_check(((Bitset >> 40).ToIntegral() == (Int >> 40)));
|
always_check(((Bitset >> 40).ToIntegral() == (Int >> 40)));
|
||||||
|
@ -17,7 +17,14 @@ NAMESPACE_REDCRAFT_BEGIN
|
|||||||
NAMESPACE_MODULE_BEGIN(Redcraft)
|
NAMESPACE_MODULE_BEGIN(Redcraft)
|
||||||
NAMESPACE_MODULE_BEGIN(Utility)
|
NAMESPACE_MODULE_BEGIN(Utility)
|
||||||
|
|
||||||
template <CInstantiableAllocator Allocator>
|
NAMESPACE_PRIVATE_BEGIN
|
||||||
|
|
||||||
|
template <CUnsignedIntegral InBlockType> requires (!CSameAs<InBlockType, bool>)
|
||||||
|
using TDefaultBitsetAllocator = TInlineAllocator<(40 - 3 * sizeof(size_t)) / sizeof(InBlockType)>;
|
||||||
|
|
||||||
|
NAMESPACE_PRIVATE_END
|
||||||
|
|
||||||
|
template <CUnsignedIntegral InBlockType, CInstantiableAllocator Allocator = NAMESPACE_PRIVATE::TDefaultBitsetAllocator<InBlockType>> requires (!CSameAs<InBlockType, bool>)
|
||||||
class TBitset final
|
class TBitset final
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
@ -27,7 +34,7 @@ private:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
using BlockType = uint64;
|
using BlockType = InBlockType;
|
||||||
using ElementType = bool;
|
using ElementType = bool;
|
||||||
using AllocatorType = Allocator;
|
using AllocatorType = Allocator;
|
||||||
|
|
||||||
@ -59,9 +66,38 @@ public:
|
|||||||
/** Constructs a bitset from an integer. */
|
/** Constructs a bitset from an integer. */
|
||||||
TBitset(size_t InCount, uint64 InValue) : TBitset(InCount > 64 ? InCount : 64)
|
TBitset(size_t InCount, uint64 InValue) : TBitset(InCount > 64 ? InCount : 64)
|
||||||
{
|
{
|
||||||
size_t BlockInteger = sizeof(uint64) / sizeof(BlockType);
|
static_assert(sizeof(BlockType) <= sizeof(uint64), "The block width of TBitset is unexpected");
|
||||||
|
|
||||||
*reinterpret_cast<uint64*>(Impl.Pointer) = InValue;
|
if constexpr (sizeof(BlockType) == sizeof(uint8))
|
||||||
|
{
|
||||||
|
Impl.Pointer[0] = static_cast<BlockType>(InValue >> 0);
|
||||||
|
Impl.Pointer[1] = static_cast<BlockType>(InValue >> 8);
|
||||||
|
Impl.Pointer[2] = static_cast<BlockType>(InValue >> 16);
|
||||||
|
Impl.Pointer[3] = static_cast<BlockType>(InValue >> 24);
|
||||||
|
Impl.Pointer[4] = static_cast<BlockType>(InValue >> 32);
|
||||||
|
Impl.Pointer[5] = static_cast<BlockType>(InValue >> 40);
|
||||||
|
Impl.Pointer[6] = static_cast<BlockType>(InValue >> 48);
|
||||||
|
Impl.Pointer[7] = static_cast<BlockType>(InValue >> 56);
|
||||||
|
}
|
||||||
|
else if constexpr (sizeof(BlockType) == sizeof(uint16))
|
||||||
|
{
|
||||||
|
Impl.Pointer[0] = static_cast<BlockType>(InValue >> 0);
|
||||||
|
Impl.Pointer[1] = static_cast<BlockType>(InValue >> 16);
|
||||||
|
Impl.Pointer[2] = static_cast<BlockType>(InValue >> 32);
|
||||||
|
Impl.Pointer[3] = static_cast<BlockType>(InValue >> 48);
|
||||||
|
}
|
||||||
|
else if constexpr (sizeof(BlockType) == sizeof(uint32))
|
||||||
|
{
|
||||||
|
Impl.Pointer[0] = static_cast<BlockType>(InValue >> 0);
|
||||||
|
Impl.Pointer[1] = static_cast<BlockType>(InValue >> 32);
|
||||||
|
}
|
||||||
|
else if constexpr (sizeof(BlockType) == sizeof(uint64))
|
||||||
|
{
|
||||||
|
Impl.Pointer[0] = static_cast<BlockType>(InValue >> 0);
|
||||||
|
}
|
||||||
|
else check_no_entry();
|
||||||
|
|
||||||
|
size_t BlockInteger = sizeof(uint64) / sizeof(BlockType);
|
||||||
|
|
||||||
Memory::Memset(Impl.Pointer + BlockInteger, 0, (NumBlocks() - BlockInteger) * sizeof(BlockType));
|
Memory::Memset(Impl.Pointer + BlockInteger, 0, (NumBlocks() - BlockInteger) * sizeof(BlockType));
|
||||||
|
|
||||||
@ -151,7 +187,7 @@ public:
|
|||||||
if (NumToAllocate != MaxBlocks())
|
if (NumToAllocate != MaxBlocks())
|
||||||
{
|
{
|
||||||
Impl->Deallocate(Impl.Pointer);
|
Impl->Deallocate(Impl.Pointer);
|
||||||
|
|
||||||
Impl.BitsetNum = InValue.Num();
|
Impl.BitsetNum = InValue.Num();
|
||||||
Impl.BlocksMax = NumToAllocate;
|
Impl.BlocksMax = NumToAllocate;
|
||||||
Impl.Pointer = Impl->Allocate(MaxBlocks());
|
Impl.Pointer = Impl->Allocate(MaxBlocks());
|
||||||
@ -199,7 +235,7 @@ public:
|
|||||||
TBitset& operator=(initializer_list<bool> IL)
|
TBitset& operator=(initializer_list<bool> IL)
|
||||||
{
|
{
|
||||||
auto First = Iteration::Begin(IL);
|
auto First = Iteration::Begin(IL);
|
||||||
|
|
||||||
const size_t BlocksCount = (GetNum(IL) + BlockWidth - 1) / BlockWidth;
|
const size_t BlocksCount = (GetNum(IL) + BlockWidth - 1) / BlockWidth;
|
||||||
|
|
||||||
size_t NumToAllocate = BlocksCount;
|
size_t NumToAllocate = BlocksCount;
|
||||||
@ -210,7 +246,7 @@ public:
|
|||||||
if (NumToAllocate != MaxBlocks())
|
if (NumToAllocate != MaxBlocks())
|
||||||
{
|
{
|
||||||
Impl->Deallocate(Impl.Pointer);
|
Impl->Deallocate(Impl.Pointer);
|
||||||
|
|
||||||
Impl.BitsetNum = GetNum(IL);
|
Impl.BitsetNum = GetNum(IL);
|
||||||
Impl.BlocksMax = NumToAllocate;
|
Impl.BlocksMax = NumToAllocate;
|
||||||
Impl.Pointer = Impl->Allocate(MaxBlocks());
|
Impl.Pointer = Impl->Allocate(MaxBlocks());
|
||||||
@ -497,6 +533,8 @@ public:
|
|||||||
|
|
||||||
static constexpr auto BlockCount = [](BlockType Block)
|
static constexpr auto BlockCount = [](BlockType Block)
|
||||||
{
|
{
|
||||||
|
static_assert(sizeof(BlockType) <= sizeof(uint64), "The block width of TBitset is unexpected");
|
||||||
|
|
||||||
if constexpr (sizeof(BlockType) == sizeof(uint8))
|
if constexpr (sizeof(BlockType) == sizeof(uint8))
|
||||||
{
|
{
|
||||||
Block = (Block & 0x55ull) + ((Block >> 1) & 0x55ull);
|
Block = (Block & 0x55ull) + ((Block >> 1) & 0x55ull);
|
||||||
@ -576,9 +614,42 @@ public:
|
|||||||
{
|
{
|
||||||
checkf(Num() <= 64, TEXT("The bitset can not be represented in uint64. Please check Num()."));
|
checkf(Num() <= 64, TEXT("The bitset can not be represented in uint64. Please check Num()."));
|
||||||
|
|
||||||
|
uint64 Result = 0;
|
||||||
|
|
||||||
|
static_assert(sizeof(BlockType) <= sizeof(uint64), "The block width of TBitset is unexpected");
|
||||||
|
|
||||||
|
if constexpr (sizeof(BlockType) == sizeof(uint8))
|
||||||
|
{
|
||||||
|
Result |= static_cast<uint64>(Impl.Pointer[0]) << 0;
|
||||||
|
Result |= static_cast<uint64>(Impl.Pointer[1]) << 8;
|
||||||
|
Result |= static_cast<uint64>(Impl.Pointer[2]) << 16;
|
||||||
|
Result |= static_cast<uint64>(Impl.Pointer[3]) << 24;
|
||||||
|
Result |= static_cast<uint64>(Impl.Pointer[4]) << 32;
|
||||||
|
Result |= static_cast<uint64>(Impl.Pointer[5]) << 40;
|
||||||
|
Result |= static_cast<uint64>(Impl.Pointer[6]) << 48;
|
||||||
|
Result |= static_cast<uint64>(Impl.Pointer[7]) << 56;
|
||||||
|
}
|
||||||
|
else if constexpr (sizeof(BlockType) == sizeof(uint16))
|
||||||
|
{
|
||||||
|
Result |= static_cast<uint64>(Impl.Pointer[0]) << 0;
|
||||||
|
Result |= static_cast<uint64>(Impl.Pointer[1]) << 16;
|
||||||
|
Result |= static_cast<uint64>(Impl.Pointer[2]) << 32;
|
||||||
|
Result |= static_cast<uint64>(Impl.Pointer[3]) << 48;
|
||||||
|
}
|
||||||
|
else if constexpr (sizeof(BlockType) == sizeof(uint32))
|
||||||
|
{
|
||||||
|
Result |= static_cast<uint64>(Impl.Pointer[0]) << 0;
|
||||||
|
Result |= static_cast<uint64>(Impl.Pointer[1]) << 32;
|
||||||
|
}
|
||||||
|
else if constexpr (sizeof(BlockType) == sizeof(uint64))
|
||||||
|
{
|
||||||
|
Result |= static_cast<uint64>(Impl.Pointer[0]) << 0;
|
||||||
|
}
|
||||||
|
else check_no_entry();
|
||||||
|
|
||||||
const uint64 Mask = Num() < 64 ? (1ull << Num()) - 1 : -1;
|
const uint64 Mask = Num() < 64 ? (1ull << Num()) - 1 : -1;
|
||||||
|
|
||||||
return *reinterpret_cast<uint64*>(Impl.Pointer) & Mask;
|
return Result & Mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Appends the given bit value to the end of the bitset. */
|
/** Appends the given bit value to the end of the bitset. */
|
||||||
@ -960,7 +1031,7 @@ private:
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
using FBitset = TBitset<TInlineAllocator<((40 - 3 * sizeof(size_t)) / sizeof(TBitset<FHeapAllocator>::BlockType))>>;
|
using FBitset = TBitset<uint64>;
|
||||||
|
|
||||||
static_assert(sizeof(FBitset) == 40, "The byte size of FBitset is unexpected");
|
static_assert(sizeof(FBitset) == 40, "The byte size of FBitset is unexpected");
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user