6#include <Common/assertion.h>
7#include <Common/primitive_type.h>
8#include <Common/utility.h>
28 static_assert(
sizeof(std::byte)* CHAR_BIT == 8,
29 "The buffer explicitly depends on the fact that std::byte contains 8 bits.");
39 template<std::
integral IntegerType>
46 template<std::
integral IntegerType>
47 void setUInt(std::size_t index, IntegerType value);
54 template<
typename ValueType>
55 void setUInts(
const ValueType* values, std::size_t numValues, std::size_t dstBeginValueIndex = 0);
57 void setUInts(
const std::byte* srcBytes, std::size_t numBytes, std::size_t dstOffset = 0);
60 uint64
getUInt(std::size_t index)
const;
75 const std::byte*
getData()
const;
79 static uint64 maxAllowedValue(uint8 numBitsPerUInt);
81 std::unique_ptr<std::byte[]> m_byteBuffer;
82 std::size_t m_byteBufferSize;
83 uint8 m_numBitsPerUInt;
88template<std::
integral IntegerType>
96 return sizeof(*this) + m_byteBufferSize;
101 return m_byteBuffer !=
nullptr;
106 return maxAllowedValue(m_numBitsPerUInt);
111 return m_numBitsPerUInt > 0 ? m_byteBufferSize * CHAR_BIT / m_numBitsPerUInt : 0;
114inline uint64 IndexedUIntBuffer::maxAllowedValue(
const uint8 numBitsPerUInt)
116 return numBitsPerUInt < 64
117 ? (
static_cast<uint64
>(1) << numBitsPerUInt) - 1
118 : std::numeric_limits<uint64>::max();
121template<std::
integral IntegerType>
126 const auto uint64Value = lossless_integer_cast<uint64>(value);
129 throw std::invalid_argument(std::format(
130 "Integer value {} cannot be stored using {} bits.", value, m_numBitsPerUInt));
133 const std::size_t firstByteIndex = index * m_numBitsPerUInt / CHAR_BIT;
134 const std::size_t firstByteBitOffset = index * m_numBitsPerUInt - firstByteIndex * CHAR_BIT;
135 const std::size_t numStraddledBytes = (firstByteBitOffset + m_numBitsPerUInt + (CHAR_BIT - 1)) / CHAR_BIT;
137 PH_ASSERT_LT(firstByteBitOffset, CHAR_BIT);
138 PH_ASSERT_LE(numStraddledBytes, 8 + 1);
139 PH_ASSERT_LE(firstByteIndex + numStraddledBytes, m_byteBufferSize);
143 std::memcpy(&rawBits, &m_byteBuffer[firstByteIndex], std::min<std::size_t>(numStraddledBytes, 8));
147 rawBits |= (uint64Value << firstByteBitOffset);
148 std::memcpy(&m_byteBuffer[firstByteIndex], &rawBits, std::min<std::size_t>(numStraddledBytes, 8));
152 if(numStraddledBytes > 8)
154 uint8 remainingRawBits;
155 std::memcpy(&remainingRawBits, &m_byteBuffer[firstByteIndex + 8], 1);
158 remainingRawBits =
math::clear_bits_in_range(remainingRawBits,
static_cast<std::size_t
>(0), firstByteBitOffset + m_numBitsPerUInt - 64);
159 remainingRawBits |=
static_cast<uint8
>(uint64Value >> (64 - firstByteBitOffset));
160 std::memcpy(&m_byteBuffer[firstByteIndex + 8], &remainingRawBits, 1);
164template<
typename ValueType>
166 const ValueType*
const values,
167 const std::size_t numValues,
168 const std::size_t dstBeginValueIndex)
173 if(std::is_unsigned_v<ValueType> && sizeof_in_bits<ValueType>() == m_numBitsPerUInt)
176 reinterpret_cast<const std::byte*
>(values),
177 numValues *
sizeof(ValueType),
178 dstBeginValueIndex *
sizeof(ValueType));
183 for(std::size_t uintIdx = dstBeginValueIndex, valueIdx = 0; valueIdx < numValues; ++uintIdx, ++valueIdx)
185 if constexpr(std::is_integral_v<ValueType>)
187 setUInt(uintIdx, values[valueIdx]);
191 setUInt(uintIdx,
static_cast<uint64
>(values[valueIdx]));
201 const std::size_t firstByteIndex = index * m_numBitsPerUInt / CHAR_BIT;
202 const std::size_t firstByteBitOffset = index * m_numBitsPerUInt - firstByteIndex * CHAR_BIT;
203 const std::size_t numStraddledBytes = (firstByteBitOffset + m_numBitsPerUInt + (CHAR_BIT - 1)) / CHAR_BIT;
205 PH_ASSERT_LT(firstByteBitOffset, CHAR_BIT);
206 PH_ASSERT_LE(numStraddledBytes, 8 + 1);
207 PH_ASSERT_LE(firstByteIndex + numStraddledBytes, m_byteBufferSize);
211 std::memcpy(&rawBits, &m_byteBuffer[firstByteIndex], std::min<std::size_t>(numStraddledBytes, 8));
215 uint64 value = (rawBits & bitMask) >> firstByteBitOffset;
219 if(numStraddledBytes > 8)
221 uint8 remainingRawBits;
222 std::memcpy(&remainingRawBits, &m_byteBuffer[firstByteIndex + 8], 1);
226 remainingRawBits &= remainingBitsBitMask;
229 value |= (
static_cast<uint64
>(remainingRawBits) << (64 - firstByteBitOffset));
238 return m_byteBuffer.get();
244 return m_byteBuffer.get();
A general unsigned integer buffer for integers with any number of bits.
Definition IndexedUIntBuffer.h:27
uint64 getUInt(std::size_t index) const
Definition IndexedUIntBuffer.h:197
std::size_t numUInts() const
Definition IndexedUIntBuffer.h:109
void declareUIntFormat()
Definition IndexedUIntBuffer.h:89
IndexedUIntBuffer()
Definition IndexedUIntBuffer.cpp:10
void allocate(std::size_t numUInts)
Definition IndexedUIntBuffer.cpp:37
std::size_t memoryUsage() const
Definition IndexedUIntBuffer.h:94
void declareUIntFormatByMaxValue(uint64 maxValue)
Definition IndexedUIntBuffer.cpp:21
void setUInts(const ValueType *values, std::size_t numValues, std::size_t dstBeginValueIndex=0)
Set integers to a range of indices. This method handles all types, including both integer and floatin...
Definition IndexedUIntBuffer.h:165
bool isAllocated() const
Definition IndexedUIntBuffer.h:99
uint64 getMaxAllowedValue() const
Definition IndexedUIntBuffer.h:104
std::byte * getData()
Access to the underlying raw byte buffer.
Definition IndexedUIntBuffer.h:235
void setUInt(std::size_t index, IntegerType value)
Set a single integer.
Definition IndexedUIntBuffer.h:122
Miscellaneous math utilities.
UIntType set_bits_in_range(const UIntType bits, const RangeType beginBitIdx, const RangeType endBitIdx)
Set bits in the range to 1. The bits in [beginBitIdx, endBitIdx) will be set to 1,...
Definition math.h:497
UIntType clear_bits_in_range(const UIntType bits, const RangeType beginBitIdx, const RangeType endBitIdx)
Set bits in the range to 0. The bits in [beginBitIdx, endBitIdx) will be set to 0,...
Definition math.h:518
The root for all renderer implementations.
Definition EEngineProject.h:6