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 &