290#include <__macro_map.h>
295#include <type_traits>
302#if defined(CHERIOT_EXPERIMENTAL) && \
303 !defined(CHERIOT_EXPERIMENTAL_NOWARN_BITPACKS)
304# define BITPACK_DECL_ANNOTATION \
305 CHERIOT_EXPERIMENTAL( \
306 "Bitpacks are an experimental CHERIoT RTOS feature")
308# define BITPACK_DECL_ANNOTATION
317template<
typename StorageParam>
318 requires std::is_unsigned_v<StorageParam>
354 template<
typename Self>
357 const std::remove_cvref_t<Self> &b)
359 self.value = b.value;
368 template<
typename Self>
369 requires(!std::is_volatile_v<Self>)
370 constexpr bool operator==(
this Self &&self,
371 const std::remove_cvref_t<Self> &b)
373 return self.value == b.value;
381 template<
typename Self>
382 requires(!std::is_volatile_v<Self>)
384 const std::remove_cvref_t<Self> &b)
386 return self.value <=> b.value;
406 return static_cast<Storage>(*this);
415 template<
typename Self>
416 const auto read(
this Self &&self)
418 return std::remove_cvref_t<Self>{self.value};
423 requires std::is_unsigned_v<T>
433 static_assert(
sizeof(T) <=
sizeof(
Storage));
437 constexpr Numeric(T v) : value(v) {}
439 constexpr operator T()
const
444 [[nodiscard]]
constexpr T raw()
const
446 return static_cast<T
>(this->value);
474 bool operator==(
const FieldInfo &)
const =
default;
483 template<
typename TypeParam, FieldInfo InfoParam>
492 static_assert(
Info.maxIndex >=
Info.minIndex,
493 "Field span ends before it begins");
495 static_assert(!std::is_base_of_v<Numeric<bool>,
Type> ||
497 "Numeric<bool> fields should be exactly one bit wide");
500 !std::is_enum_v<Type> ||
502 { std::underlying_type_t<Type>() } -> std::same_as<bool>;
504 "Enum fields with underlying type bool should be exactly "
508 CHAR_BIT *
sizeof(Type),
509 "Field type is narrower than specified field bit width");
513 "Field width is not smaller than Bitpack's Storage type");
517 (1U << (
Info.maxIndex -
Info.minIndex + 1)) - 1;
536 requires requires {
static_cast<Storage>(std::declval<Type>()); }
538 return raw_with(lhs,
static_cast<Storage>(rhs));
542 template<
typename OtherStorage>
543 requires requires {
sizeof(OtherStorage) <
sizeof(Storage); }
547 return raw_with(lhs,
static_cast<OtherStorage
>(rhs));
565 template<
typename DerivedBitpack,
typename RefTypeParam>
566 requires std::is_base_of_v<Bitpack, DerivedBitpack> &&
567 std::is_lvalue_reference_v<RefTypeParam> &&
568 std::is_same_v<Storage, std::remove_cvref_t<RefTypeParam>>
588 constexpr Proxy(R &r) : ref(r.value)
598 template<
typename Self>
600 !std::is_const_v<std::remove_reference_t<RefTypeParam>>)
615 template<
typename Self,
typename RHS>
617 !std::is_const_v<std::remove_reference_t<RefTypeParam>> &&
618 std::is_same_v<Field::Type, Numeric<RHS>>)
620 constexpr Self &&
operator=(
this Self &&self, RHS rhs)
633 template<
typename Self,
typename RHS>
635 !std::is_const_v<std::remove_reference_t<RefTypeParam>> &&
636 std::is_scoped_enum_v<Field::Type> &&
637 std::is_same_v<std::underlying_type_t<Field::Type>, RHS>)
639 constexpr Self &&
operator=(
this Self &&self, RHS rhs)
651 template<
typename Self>
653 !std::is_volatile_v<std::remove_reference_t<RefTypeParam>>)
666 [[nodiscard]]
constexpr auto rawer() const
667 requires(std::is_enum_v<typename
Field::
Type>)
669 return std::to_underlying(this->
raw());
675 [[nodiscard]]
constexpr auto rawer() const
676 requires(std::is_base_of_v<
677 Numeric<typename std::remove_cvref_t<
679 typename std::remove_cvref_t<typename
Field::
Type>>)
681 return this->
raw().raw();
694 return DerivedBitpack{
raw_with(this->ref, rhs)};
705 constexpr DerivedBitpack
with(
auto &&f)
const
723 template<
typename Self>
724 constexpr void alter(
this Self &&self,
auto &&f)
728 !std::is_const_v<std::remove_reference_t<RefTypeParam>>)
756 return raw() <=> rhs.raw();
760 requires(
requires(Field::Type v) {
764 return raw() <=> rhs;
767 constexpr bool operator==(Proxy rhs)
const
768 requires(
requires(Field::Type v) {
769 { v == v } -> std::same_as<bool>;
772 return raw() == rhs.raw();
775 constexpr bool operator==(Field::Type rhs)
const
776 requires(
requires(Field::Type v) {
777 { v == v } -> std::same_as<bool>;
784 template<
bool C,
typename T>
785 requires std::is_lvalue_reference_v<T>
786 using ConditionalConstRef = std::
787 conditional_t<C, std::add_const_t<std::remove_reference_t<T>> &, T>;
798 template<
typename BitpackType>
799 Proxy(BitpackType &r)
800 -> Proxy<std::remove_cvref_t<BitpackType>,
801 ConditionalConstRef<Info.
isConst,
decltype((r.value))>>;
811 template<
typename FieldType, FieldInfo Info,
typename Self>
823 template<
typename FieldType,
typename Self>
824 requires std::is_convertible_v<
825 decltype(std::remove_cvref_t<Self>::template field_info_for_type<
835 std::remove_cvref_t<Self>::template field_info_for_type<FieldType>();
845 template<
typename FieldType,
typename Self>
846 constexpr FieldType
get(
this Self &&self)
856 template<
typename FieldType,
typename Self>
857 constexpr std::remove_cvref_t<Self>
with(
this Self &&self, FieldType v)
867 template<
typename FieldType,
typename Self>
868 constexpr void set(
this Self &&self, FieldType v)
879 template<
typename Self>
880 constexpr void alter(
this Self &&self,
auto &&f)
881 requires std::is_invocable_r_v<std::remove_cvref_t<Self>,
883 std::remove_cvref_t<Self>>
885 std::remove_cvref_t<Self> value{self.value};
894 template<
typename Self>
896 requires std::is_invocable_r_v<std::remove_cvref_t<Self>,
898 std::remove_cvref_t<Self>>
900 self = f(std::remove_cvref_t<Self>(0));
912 requires std::derived_from<B, Bitpack<typename B::Storage>>
919 using ParentBitpack = B;
936#define BITPACK_USUAL_PREFIX \
937 using Bitpack::Bitpack; \
938 using Bitpack::operator=; \
939 template<typename FieldType> \
940 static constexpr FieldInfo field_info_for_type() = delete;
950#define BITPACK_MEMBER_ADD(name, Type, ...) \
951 template<typename Self> \
952 constexpr auto name(this Self &&self) \
954 return self.template member<Type __VA_OPT__(, {__VA_ARGS__})>(); \
964#define BITPACK_MEMBER_ADD_ENUM(Type, Base, ...) \
965 enum class Type : Base; \
967 constexpr FieldInfo field_info_for_type<Type>() \
969 constexpr auto info = FieldInfo{__VA_ARGS__}; \
970 static_assert(requires { Field<Type, info>(); }); \
973 enum class Type : Base
987#define BITPACK_MEMBER_ADD_ENUM_BOOL(Type, FalseVal, TrueVal, BitIndex, ...) \
988 BITPACK_MEMBER_ADD_ENUM(Type, bool, BitIndex, BitIndex, __VA_ARGS__) \
990 FalseVal = false, TrueVal = true, \
997#define BITPACK_MEMBER_ADD_ENUM_BOOL_CLEARED_ASSERTED(Type, BitIndex, ...) \
998 BITPACK_MEMBER_ADD_ENUM_BOOL(Type, Cleared, Asserted, BitIndex, __VA_ARGS__)
1004#define BITPACK_MEMBER_ADD_ENUM_BOOL_DISABLED_ENABLED(Type, BitIndex, ...) \
1005 BITPACK_MEMBER_ADD_ENUM_BOOL(Type, Disabled, Enabled, BitIndex, __VA_ARGS__)
1013#define BITPACK_MEMBER_ADD_NUMERIC(Type, Base, ...) \
1014 struct Type : Numeric<Base> \
1016 using Numeric::Numeric; \
1019 constexpr FieldInfo field_info_for_type<Type>() \
1021 constexpr auto info = FieldInfo{__VA_ARGS__}; \
1022 static_assert(requires { Field<Type, info>(); }); \
1037#define BITPACK_MEMBER_ADD_BOOL(Type, BitIndex, ...) \
1038 BITPACK_MEMBER_ADD_NUMERIC(Type, bool, BitIndex, BitIndex, __VA_ARGS__)
1054#define BITPACK_MEMBER_DECLTYPE(b, T) \
1055 (b).template member<std::remove_reference_t<decltype(b)>::T>()
1062#define BITPACK_MEMBER_DEPENDENT(b, T) \
1063 (b).template member<typename std::remove_reference_t<decltype(b)>::T>()
1076#define BITPACK_DERIVED_PREFIX \
1077 using BitpackDerived<ParentBitpack>::BitpackDerived; \
1078 using BitpackDerived<ParentBitpack>::operator=; \
1080 template<typename FieldType> \
1081 static constexpr FieldInfo field_info_for_type() \
1083 return ParentBitpack::field_info_for_type<FieldType>(); \
1087#define BITPACK_DERIVED_FIELD_INFO_FOR_TYPE(Type, lambda) \
1089 constexpr FieldInfo field_info_for_type<Type>() \
1092 std::is_invocable_r_v<void, decltype(lambda), FieldInfo &>); \
1093 auto fi = ParentBitpack::field_info_for_type<Type>(); \
1102#define BITPACK_DERIVED_FIELD_CONST_FOR_TYPE(Type, c) \
1103 BITPACK_DERIVED_FIELD_INFO_FOR_TYPE(Type, [](auto &fi) { fi.isConst = c; })
1119#define BITPACK_OPERATE_QUALIFY(proxy, operator, value) \
1121 using F = decltype(proxy)::Field::Type; \
1122 (proxy) operator(F::value); \
1126#define BITPACK_OPERATE_QUALIFY_DECLTYPE(b, T, operator, v) \
1127 BITPACK_OPERATE_QUALIFY(BITPACK_MEMBER_DECLTYPE(b, T), operator, v)
1130#define BITPACK_OPERATE_QUALIFY_DEPENDENT(b, T, operator, v) \
1131 BITPACK_OPERATE_QUALIFY(BITPACK_MEMBER_DEPENDENT(b, T), operator, v)
1134#define BITPACK_OPERATE_QUALIFY_TYPE(b, T, operator, v) \
1135 BITPACK_OPERATE_QUALIFY((b).template member<T>(), operator, v)
1138#define BITPACK_WITH_QUALIFY(proxy, value) \
1139 BITPACK_OPERATE_QUALIFY(proxy, .with, value)
1145#define BITPACK_WITH_QUALIFY_DECLTYPE(b, T, v) \
1146 BITPACK_OPERATE_QUALIFY_DECLTYPE(b, T, .with, v)
1152#define BITPACK_WITH_QUALIFY_DEPENDENT(b, T, v) \
1153 BITPACK_OPERATE_QUALIFY_DEPENDENT(b, T, .with, v)
1159#define BITPACK_WITH_QUALIFY_TYPE(b, T, v) \
1160 BITPACK_OPERATE_QUALIFY_TYPE(b, T, .with, v)
1177#define BITPACK_OPERATE_WRAP(proxy, operator, value) \
1179 using F = decltype(proxy)::Field::Type; \
1180 (proxy) operator(F{value}); \
1184#define BITPACK_OPERATE_WRAP_DECLTYPE(b, T, operator, v) \
1185 BITPACK_OPERATE_WRAP(BITPACK_MEMBER_DECLTYPE(b, T), operator, v)
1188#define BITPACK_OPERATE_WRAP_DEPENDENT(b, T, operator, v) \
1189 BITPACK_OPERATE_WRAP(BITPACK_MEMBER_DEPENDENT(b, T), operator, v)
1192#define BITPACK_OPERATE_WRAP_TYPE(b, T, operator, v) \
1193 BITPACK_OPERATE_WRAP((b).template member<T>(), operator, v)
1196#define BITPACK_WRAP_WITH(proxy, value) \
1197 BITPACK_OPERATE_WRAP(proxy, .with, value)
1203#define BITPACK_WITH_WRAP_DECLTYPE(b, T, v) \
1204 BITPACK_OPERATE_WRAP_DECLTYPE(b, T, .with, v)
1210#define BITPACK_WITH_WRAP_DEPENDENT(b, T, v) \
1211 BITPACK_OPERATE_WRAP_DEPENDENT(b, T, .with, v)
1214#define BITPACK_WITH_WRAP_TYPE(b, T, v) \
1215 BITPACK_OPERATE_WRAP_TYPE(b, T, .with, v)
1230#define BITPACK_OPERATE_VALUE(b, operator, value) \
1231 ({ (b).template member<decltype(value)>() operator(value); })
1238#define BITPACK_OPERATE_VALUE_DECLTYPE(b, operator, value) \
1239 BITPACK_OPERATE_VALUE( \
1240 b, operator, std::remove_reference_t<decltype(b)>::value)
1246#define BITPACK_OPERATE_VALUE_DEPENDENT(b, operator, value) \
1247 BITPACK_OPERATE_VALUE( \
1248 b, operator, typename std::remove_reference_t<decltype(b)>::value)
1251#define BITPACK_WITH_VALUE(b, value) BITPACK_OPERATE_VALUE(b, .with, value)
1257#define BITPACK_WITH_VALUE_DECLTYPE(b, value) \
1258 BITPACK_OPERATE_VALUE_DECLTYPE(b, .with, value)
1264#define BITPACK_WITH_VALUE_DEPENDENT(b, value) \
1265 BITPACK_OPERATE_VALUE_DEPENDENT(b, .with, value)
1286#define BITPACK_OPERATE_ENUM(proxy, operator, value) \
1288 using E = decltype(proxy)::Field::Type; \
1289 static_assert(std::is_enum_v<E>); \
1291 (proxy) operator(value); \
1295#define BITPACK_OPERATE_ENUM_DECLTYPE(b, T, operator, v) \
1296 BITPACK_OPERATE_ENUM(BITPACK_MEMBER_DECLTYPE(b, T), operator, v)
1299#define BITPACK_OPERATE_ENUM_TYPE(b, T, operator, v) \
1300 BITPACK_OPERATE_ENUM((b).template member<T>(), operator, v)
1303#define BITPACK_WITH_ENUM(proxy, value) \
1304 BITPACK_OPERATE_ENUM(proxy, .with, value)
1310#define BITPACK_WITH_ENUM_DECLTYPE(b, T, v) \
1311 BITPACK_OPERATE_ENUM_DECLTYPE(b, T, .with, v)
1314#define BITPACK_WITH_ENUM_TYPE(b, T, v) \
1315 BITPACK_OPERATE_ENUM_TYPE(b, T, .with, v)
1332#define BITPACK_MAP_DECLTYPE_HELPER(x, b) \
1333 std::remove_reference_t<decltype(b)>::x
1340#define BITPACK_MAP_DECLTYPE(b, ...) \
1341 CHERIOT_MAP_LIST_UD(BITPACK_MAP_DECLTYPE_HELPER, b, __VA_ARGS__)
1344#define BITPACK_MAP_DEPENDENT_HELPER(x, b) \
1345 typename std::remove_reference_t<decltype(b)>::x
1352#define BITPACK_MAP_DEPENDENT(b, ...) \
1353 CHERIOT_MAP_LIST_UD(BITPACK_MAP_DEPENDENT_HELPER, b, __VA_ARGS__)
1356#define BITPACK_MAP_WITHS_HELPER(x) .with(x)
1364#define BITPACK_WITHS(b, ...) \
1365 (b) CHERIOT_MAP(BITPACK_MAP_WITHS_HELPER, __VA_ARGS__)
1371#define BITPACK_WITHS_DECLTYPE(b, ...) \
1372 BITPACK_WITHS(b, BITPACK_MAP_DECLTYPE(b, __VA_ARGS__))
1378#define BITPACK_WITHS_DEPENDENT(b, ...) \
1379 BITPACK_WITHS(b, BITPACK_MAP_DEPENDENT(b, __VA_ARGS__))
1387#define BITPACK_RELATE_MASKED_HELPER(x, b) \
1389 using BT = decltype(b); \
1390 using FT = decltype(x); \
1391 BT::Field<FT, BT::field_info_for_type<FT>()>::FieldMask; \
1403#define BITPACK_RELATE_MASKED(b, operator, ...) \
1405 constexpr decltype(b.raw()) __bitpack_mask = \
1406 (0)CHERIOT_MAP_UD(BITPACK_RELATE_MASKED_HELPER, b, __VA_ARGS__); \
1407 constexpr auto __bitpack_query = \
1408 BITPACK_WITHS((decltype(b))(0), __VA_ARGS__).raw(); \
1409 (b.raw() & __bitpack_mask) operator(__bitpack_query); \
1416#define BITPACK_RELATE_MASKED_DECLTYPE(b, operator, ...) \
1417 BITPACK_RELATE_MASKED(b, operator, BITPACK_MAP_DECLTYPE(b, __VA_ARGS__))
1423#define BITPACK_RELATE_MASKED_DEPENDENT(b, operator, ...) \
1424 BITPACK_RELATE_MASKED(b, operator, BITPACK_MAP_DEPENDENT(b, __VA_ARGS__))
A proxy for this Field within the Bitpack's Storage.
constexpr auto rawer() const
Get the value of this Numeric-typed field as its underlying type.
constexpr DerivedBitpack with(Field::Type rhs) const
Construct a new Bitpack value with an updated value of this field.
constexpr Field::Type raw() const
A shorter way of spelling static_cast<Field::Type>()...
constexpr Proxy(R &r)
Construct a proxy given a reference to the storage word.
constexpr DerivedBitpack with(auto &&f) const
Construct a new Bitpack value with an updated value of this field as a function of its current value.
constexpr void alter(this Self &&self, auto &&f)
Compute and store an updated Bitpack value with a new value for this field as a function of its curre...
constexpr Self && operator=(this Self &&self, Field::Type rhs)
Compute and store an updated Bitpack value with a new value for this field (of the field type itself)...
constexpr auto rawer() const
Get the value of this enum-typed field as its underlying type.
constexpr operator Field::Type(this Self &&self)
Explicit conversion of a Field::Proxy to the field value.
RefTypeParam RefType
Expose the qualified reference type we hold to the Storage.
constexpr void assign_from(auto &&f)
Convenience function for unconditionally assigning a field when it helps to have a zero value of that...
Field Field
Name the Field of which we are a proxy.
constexpr void set(this Self &&self, FieldType v)
Compute a new Bitpack value with an updated field of a given type.
constexpr void assign_from(this Self &&self, auto &&f)
Convenience function for unconditionally assigning an entire Bitpack from a computed value.
constexpr auto operator<=>(this Self &&self, const std::remove_cvref_t< Self > &b)
Spaceship operator on Bitpack-s (reflecing that of Storage).
constexpr std::remove_cvref_t< Self > with(this Self &&self, FieldType v)
Compute a new Bitpack value with an updated field of a given type.
constexpr Self && operator=(this Self &&self, const std::remove_cvref_t< Self > &b)
Assign a whole Bitpack at once given a non-volatile Bitpack of the same (or convertible,...
constexpr Storage raw() const
A shorter way of spelling static_cast<Storage>(...).
constexpr void alter(this Self &&self, auto &&f)
Convenience function for unconditionally changing several sub-fields at once.
constexpr Bitpack()
Construct a Bitpack value with an underlying Storage of all zero bits.
constexpr Bitpack(Storage v)
Construct a Bitpack value from a value of its underlying Storage type.
constexpr auto member(this Self &&self)
Build a Field::Proxy proxy by asking the derived Self class for a FieldInfo structure computed from t...
const auto read(this Self &&self)
Return a snapshot of the underlying Storage.
constexpr FieldType get(this Self &&self)
Fetch the value of a field in this Bitpack based on the field type.
constexpr auto member(this Self &&self)
Build a Field::Proxy of an explicitly given type and info.
StorageParam Storage
Expose the underlying storage type.
consteval std::strong_ordering operator<=>(const DebugLevel Level, const DebugLevel Threshold)
Comparison operator to determine whether a provided debug level is above the threshold at which it sh...
It is occasionally useful to derive one bitpack from another.
Information about a field within a Bitpack.
size_t maxIndex
Maximum 0-indexed bit position occupied by this field.
bool isConst
Should this field be proxied as constant (and so mutation be slightly less ergonomic)?
size_t minIndex
Minimum 0-indexed bit position occupied by this field.
A particular Field within a Bitpack.
static constexpr Storage raw_with(Storage lhs, Storage rhs)
Compute the underlying Storage transform for a Field update.
static constexpr Storage FieldMask
The mask of bits occupied by this value (occupied bits are set).
static constexpr Storage raw_with(Storage lhs, Bitpack< OtherStorage > rhs)
Update for fields that are themselves Bitpacks at smaller types.
TypeParam Type
Expose the type parameter.
static constexpr Storage ValueMask
A span of set bits, starting at index 0, and of the field's width.
static constexpr Storage raw_with(Storage lhs, Type rhs)
Update for fields whose type can be static_cast to Storage.
static constexpr Type raw_view(Storage storage)
Extract a Field from a raw Storage value.
static constexpr FieldInfo Info
Expose the FieldInfo parameter.
Convenience wrapper for the types of numeric fields.
T NumericType
Export the underlying numeric type.