7 #include "../ProxyRefOpMixin.hpp"
11 #include <type_traits>
24 template<
typename Integral>
27 return bits >=
sizeof(Integral) * CHAR_BIT ? ~Integral{0} : (Integral{1} << bits) - 1u;
30 template<
bool KeepSignBit,
typename Integral,
typename StoredIntegral>
32 const StoredIntegral* ptr,
33 StoredIntegral bitOffset,
34 StoredIntegral bitCount) -> Integral
36 constexpr
auto bitsPerIntegral =
static_cast<StoredIntegral
>(
sizeof(Integral) * CHAR_BIT);
37 constexpr
auto bitsPerStoredIntegral =
static_cast<StoredIntegral
>(
sizeof(StoredIntegral) * CHAR_BIT);
38 static_assert(bitsPerIntegral <= bitsPerStoredIntegral);
39 assert(bitCount > 0 && bitCount <= bitsPerStoredIntegral);
42 __builtin_assume(bitCount > 0 && bitCount <= bitsPerStoredIntegral);
45 const auto* p = ptr + bitOffset / bitsPerStoredIntegral;
46 const auto innerBitOffset = bitOffset % bitsPerStoredIntegral;
48 auto v = p[0] >> innerBitOffset;
50 const auto innerBitEndOffset = innerBitOffset + bitCount;
51 if(innerBitEndOffset <= bitsPerStoredIntegral)
53 const auto mask =
makeMask(bitCount);
58 const auto excessBits = innerBitEndOffset - bitsPerStoredIntegral;
59 const auto bitsLoaded = bitsPerStoredIntegral - innerBitOffset;
60 const auto mask =
makeMask(excessBits);
62 v |= (p[1] & mask) << bitsLoaded;
64 if constexpr(std::is_signed_v<Integral> && KeepSignBit)
67 if((v & (StoredIntegral{1} << (bitCount - 1))) && bitCount < bitsPerStoredIntegral)
68 v |= ~StoredIntegral{0} << bitCount;
70 return static_cast<Integral
>(v);
73 template<
bool KeepSignBit,
typename StoredIntegral,
typename Integral>
76 StoredIntegral bitOffset,
77 StoredIntegral bitCount,
80 constexpr
auto bitsPerIntegral =
static_cast<StoredIntegral
>(
sizeof(Integral) * CHAR_BIT);
81 constexpr
auto bitsPerStoredIntegral =
static_cast<StoredIntegral
>(
sizeof(StoredIntegral) * CHAR_BIT);
82 static_assert(bitsPerIntegral <= bitsPerStoredIntegral);
83 assert(bitCount > 0 && bitCount <= bitsPerStoredIntegral);
86 __builtin_assume(bitCount > 0 && bitCount <= bitsPerStoredIntegral);
90 const auto unsignedValue =
static_cast<StoredIntegral
>(value);
91 const auto mask =
makeMask(bitCount);
92 StoredIntegral valueBits;
93 if constexpr(std::is_signed_v<Integral> && KeepSignBit)
95 const auto magnitudeMask =
makeMask(bitCount - 1);
96 const auto isSigned = value < 0;
97 valueBits = (StoredIntegral{isSigned} << (bitCount - 1)) | (unsignedValue & magnitudeMask);
101 valueBits = unsignedValue & mask;
104 auto* p = ptr + bitOffset / bitsPerStoredIntegral;
105 const auto innerBitOffset = bitOffset % bitsPerStoredIntegral;
108 const auto clearMask = ~(mask << innerBitOffset);
110 auto mem = p[0] & clearMask;
111 mem |= valueBits << innerBitOffset;
115 const auto innerBitEndOffset = innerBitOffset + bitCount;
116 if(innerBitEndOffset > bitsPerStoredIntegral)
118 const auto excessBits = innerBitEndOffset - bitsPerStoredIntegral;
119 const auto bitsWritten = bitsPerStoredIntegral - innerBitOffset;
120 const auto clearMask = ~
makeMask(excessBits);
122 auto mem = p[1] & clearMask;
123 mem |= valueBits >> bitsWritten;
128 template<
typename Integral,
typename StoredIntegral>
132 constexpr
auto bitsPerStoredIntegral =
static_cast<StoredIntegral
>(
sizeof(StoredIntegral) * CHAR_BIT);
134 = (ptr[bitOffset / bitsPerStoredIntegral] >> (bitOffset % bitsPerStoredIntegral)) & StoredIntegral{1};
135 return static_cast<Integral
>(bit);
138 template<
typename StoredIntegral,
typename Integral>
141 constexpr
auto bitsPerStoredIntegral =
static_cast<StoredIntegral
>(
sizeof(StoredIntegral) * CHAR_BIT);
142 const auto bitOff = bitOffset % bitsPerStoredIntegral;
143 auto& dst = ptr[bitOffset / bitsPerStoredIntegral];
144 dst &= ~(StoredIntegral{1} << bitOff);
145 const auto bit = (
static_cast<StoredIntegral
>(value) & StoredIntegral{1});
146 dst |= (bit << bitOff);
154 template<
typename Integral,
typename StoredIntegralCV,
typename VHBits,
typename SizeType, SignBit SignBit>
158 ,
ProxyRefOpMixin<BitPackedIntRef<Integral, StoredIntegralCV, VHBits, SizeType, SignBit>, Integral>
161 using StoredIntegral = std::remove_cv_t<StoredIntegralCV>;
162 StoredIntegralCV* ptr;
169 StoredIntegralCV* ptr,
174 , bitOffset{bitOffset}
191 if constexpr(std::is_empty_v<VHBits>)
195 return bitunpack1<Integral>(ptr,
static_cast<StoredIntegral
>(bitOffset));
199 return bitunpack<SignBit == SignBit::Keep, Integral>(
201 static_cast<StoredIntegral
>(bitOffset),
202 static_cast<StoredIntegral
>(VHBits::value()));
208 if constexpr(std::is_empty_v<VHBits>)
212 bitpack1(ptr,
static_cast<StoredIntegral
>(bitOffset), value);
216 bitpack<SignBit == SignBit::Keep>(
218 static_cast<StoredIntegral
>(bitOffset),
219 static_cast<StoredIntegral
>(VHBits::value()),
225 template<
typename A,
typename B>
228 template<
typename RecordDim>
231 template<
typename RecordDim>
236 typename TArrayExtents,
240 typename TLinearizeArrayIndexFunctor,
241 typename TStoredIntegral>
249 static_assert(std::is_integral_v<StoredIntegral>);
250 static_assert(std::is_unsigned_v<StoredIntegral>);
254 std::is_same_v<StoredIntegral, std::uint32_t> || std::is_same_v<StoredIntegral, std::uint64_t>);
266 "All record dimension field types must be integral");
273 "The integral type used for storage must be at least as big as the type of the values to retrieve");
282 template<
typename B = Bits, std::enable_if_t<isConstant<B>,
int> = 0>
291 mp_for_each_inline<mp_transform<mp_identity, FlatRecordDim<TRecordDim>>>(
294 using FieldType =
typename decltype(t)::type;
296 static_cast<std::size_t
>(
VHBits::value()) <=
sizeof(FieldType) * CHAR_BIT,
297 "Storage bits must not be greater than bits of field type");
301 "When keeping the sign bit, Bits must be at least 2 with signed integers in the record "
306 template<
typename B = Bits, std::enable_if_t<!isConstant<B>,
int> = 0>
318 throw std::invalid_argument(
"BitPackedInt* Bits must not be zero");
320 mp_for_each_inline<mp_transform<mp_identity, FlatRecordDim<TRecordDim>>>(
323 using FieldType [[maybe_unused]] =
typename decltype(t)::type;
327 if(
static_cast<std::size_t
>(
VHBits::value()) >
sizeof(FieldType) * CHAR_BIT)
328 throw std::invalid_argument(
329 "BitPackedInt* Bits must not be larger than any field type in the record dimension");
332 throw std::invalid_argument(
"When keeping the sign bit, Bits must be at least 2 with "
333 "signed integers in the record "
339 template<std::size_t... RecordCoords>
360 typename TArrayExtents,
362 typename Bits =
typename TArrayExtents::value_type,
364 typename TLinearizeArrayIndexFunctor = LinearizeArrayIndexRight,
365 typename TStoredIntegral = internal::StoredUnsignedFor<TRecordDim>>
372 TLinearizeArrayIndexFunctor,
376 using Base = internal::
377 BitPackedIntCommon<TArrayExtents, TRecordDim, Bits, SignBit, TLinearizeArrayIndexFunctor, TStoredIntegral>;
389 constexpr
auto bitsPerStoredIntegral =
static_cast<size_type>(
sizeof(TStoredIntegral) * CHAR_BIT);
390 const auto bitsNeeded = TLinearizeArrayIndexFunctor{}.size(
Base::extents()) * VHBits::value();
394 template<std::size_t... RecordCoords,
typename Blobs>
401 const auto bitOffset = TLinearizeArrayIndexFunctor{}(ai,
Base::extents()) * VHBits::value();
407 reinterpret_cast<QualifiedStoredIntegral*
>(&blobs[blob][0]),
409 static_cast<const VHBits&
>(*
this)};
418 typename Bits = void,
421 typename StoredIntegral =
void>
424 template<
typename ArrayExtents,
typename RecordDim>
430 LinearizeArrayIndexFunctor,
432 !std::is_void_v<StoredIntegral>,
438 template<
typename Mapping>
447 typename LinearizeArrayIndexFunctor,
448 typename StoredIntegral>
469 typename TArrayExtents,
471 typename Bits =
typename TArrayExtents::value_type,
482 TLinearizeArrayIndexFunctor,
486 using Base = internal::
487 BitPackedIntCommon<TArrayExtents, TRecordDim, Bits, SignBit, TLinearizeArrayIndexFunctor, TStoredIntegral>;
500 constexpr
auto bitsPerStoredIntegral =
static_cast<size_type>(
sizeof(TStoredIntegral) * CHAR_BIT);
501 const auto bitsNeeded = TLinearizeArrayIndexFunctor{}.size(
Base::extents())
502 *
static_cast<size_type>(VHBits::value()) *
static_cast<size_type>(flatFieldCount<TRecordDim>);
506 template<std::size_t... RecordCoords,
typename Blobs>
512 constexpr
auto flatFieldIndex =
static_cast<size_type>(
514 const auto bitOffset = ((TLinearizeArrayIndexFunctor{}(ai,
Base::extents())
515 *
static_cast<size_type>(flatFieldCount<TRecordDim>))
517 *
static_cast<size_type>(VHBits::value());
523 reinterpret_cast<QualifiedStoredIntegral*
>(&blobs[0][0]),
525 static_cast<const VHBits&
>(*
this)};
534 typename Bits = void,
537 template<
typename>
typename PermuteFields = PermuteFieldsInOrder,
538 typename StoredIntegral =
void>
541 template<
typename ArrayExtents,
typename RecordDim>
547 LinearizeArrayIndexFunctor,
550 !std::is_void_v<StoredIntegral>,
556 template<
typename Mapping>
564 typename LinearizeArrayIndexFunctor,
566 typename PermuteFields,
567 typename StoredIntegral>
573 LinearizeArrayIndexFunctor,
#define LLAMA_BEGIN_SUPPRESS_HOST_DEVICE_WARNING
#define LLAMA_FN_HOST_ACC_INLINE
#define LLAMA_END_SUPPRESS_HOST_DEVICE_WARNING
constexpr auto bitunpack1(const StoredIntegral *ptr, StoredIntegral bitOffset) -> Integral
constexpr auto makeMask(Integral bits) -> Integral
constexpr void bitpack1(StoredIntegral *ptr, StoredIntegral bitOffset, Integral value)
std::conditional_t<(sizeof(LargestIntegral< RecordDim >) > sizeof(std::uint32_t)), std::uint64_t, std::uint32_t > StoredUnsignedFor
constexpr auto bitunpack(const StoredIntegral *ptr, StoredIntegral bitOffset, StoredIntegral bitCount) -> Integral
constexpr void bitpack(StoredIntegral *ptr, StoredIntegral bitOffset, StoredIntegral bitCount, Integral value)
mp_bool< sizeof(A)< sizeof(B)> HasLargerSize
mp_max_element< FlatRecordDim< RecordDim >, HasLargerSize > LargestIntegral
constexpr bool isBitPackedIntAoS
constexpr bool isBitPackedIntSoA
typename internal::FlattenRecordDimImpl< RecordDim >::type FlatRecordDim
Returns a flat type list containing all leaf field types of the given record dimension.
ArrayExtents(Args...) -> ArrayExtents< typename internal::IndexTypeFromArgs< std::size_t, Args... >::type,(Args{}, dyn)... >
constexpr std::size_t flatRecordCoord
std::conditional_t< std::is_const_v< FromT >, const ToT, ToT > CopyConst
Alias for ToT, adding const if FromT is const qualified.
constexpr auto roundUpToMultiple(Integral n, Integral mult) -> Integral
Returns the integral n rounded up to be a multiple of mult.
typename internal::GetTypeImpl< RecordDim, RecordCoordOrTags... >::type GetType
CRTP mixin for proxy reference types to support all compound assignment and increment/decrement opera...
constexpr auto value() const
static constexpr std::size_t blobCount
constexpr auto compute(typename Base::ArrayIndex ai, RecordCoord< RecordCoords... >, Blobs &blobs) const
PermuteFields< TRecordDim > Permuter
typename Base::VHBits VHBits
constexpr auto blobSize(size_type) const -> size_type
typename Base::VHBits VHBits
constexpr auto compute(typename Base::ArrayIndex ai, RecordCoord< RecordCoords... >, Blobs &blobs) const
static constexpr std::size_t blobCount
constexpr auto blobSize(size_type) const -> size_type
typename ArrayExtents::value_type size_type
typename ArrayExtents::Index ArrayIndex
constexpr auto extents() const -> ArrayExtents
Retains the order of the record dimension's fields.
constexpr BitPackedIntCommon(TArrayExtents extents, Bits bits, TRecordDim={})
MappingBase< TArrayExtents, TRecordDim > Base
typename TArrayExtents::value_type size_type
constexpr BitPackedIntCommon(TArrayExtents extents={}, Bits bits={}, TRecordDim={})
mp_or< std::is_integral< T >, std::is_enum< T > > IsAllowedFieldType
TLinearizeArrayIndexFunctor LinearizeArrayIndexFunctor
mp_bool< sizeof(T)<=sizeof(StoredIntegral)> IsFieldTypeSmallerOrEqualStorageIntegral
static constexpr auto isComputed(RecordCoord< RecordCoords... >)
llama::internal::BoxedValue< Bits > VHBits
TStoredIntegral StoredIntegral
constexpr auto bits() const -> size_type
BitPackedIntRef(const BitPackedIntRef &)=default
constexpr auto operator=(Integral value) -> BitPackedIntRef &
constexpr BitPackedIntRef(StoredIntegralCV *ptr, SizeType bitOffset, VHBits vhBits)
constexpr auto operator=(const BitPackedIntRef &other) -> BitPackedIntRef &