289#include <__macro_map.h>
294#include <type_traits>
301#if defined(CHERIOT_EXPERIMENTAL) && \
302 !defined(CHERIOT_EXPERIMENTAL_NOWARN_BITPACKS)
303# define BITPACK_DECL_ANNOTATION \
304 CHERIOT_EXPERIMENTAL( \
305 "Bitpacks are an experimental CHERIoT RTOS feature")
307# define BITPACK_DECL_ANNOTATION
316template<
typename StorageParam>
317 requires std::is_unsigned_v<StorageParam>
353 template<
typename Self>
356 const std::remove_cvref_t<Self> &b)
358 self.value = b.value;
367 template<
typename Self>
368 requires(!std::is_volatile_v<Self>)
369 constexpr bool operator==(
this Self &&self,
370 const std::remove_cvref_t<Self> &b)
372 return self.value == b.value;
380 template<
typename Self>
381 requires(!std::is_volatile_v<Self>)
383 const std::remove_cvref_t<Self> &b)
385 return self.value <=> b.value;
405 return static_cast<Storage>(*this);
414 template<
typename Self>
415 const auto read(
this Self &&self)
417 return std::remove_cvref_t<Self>{self.value};
422 requires std::is_unsigned_v<T>
432 static_assert(
sizeof(T) <=
sizeof(
Storage));
436 constexpr Numeric(T v) : value(v) {}
438 constexpr operator T()
const
443 [[nodiscard]]
constexpr T raw()
const
445 return static_cast<T
>(this->value);
473 bool operator==(
const FieldInfo &)
const =
default;
476 [[nodiscard]]
constexpr size_t width()
const
497 template<
typename TypeParam, FieldInfo InfoParam>
506 static_assert(
Info.maxIndex >=
Info.minIndex,
507 "Field span ends before it begins");
509 static_assert(!std::is_base_of_v<Numeric<bool>,
Type> ||
511 "Numeric<bool> fields should be exactly one bit wide");
514 !std::is_enum_v<Type> ||
516 { std::underlying_type_t<Type>() } -> std::same_as<bool>;
518 "Enum fields with underlying type bool should be exactly "
522 CHAR_BIT *
sizeof(Type),
523 "Field type is narrower than specified field bit width");
527 "Field width is not smaller than Bitpack's Storage type");
531 (1U << (
Info.maxIndex -
Info.minIndex + 1)) - 1;
550 requires requires {
static_cast<Storage>(std::declval<Type>()); }
552 return raw_with(lhs,
static_cast<Storage>(rhs));
556 template<
typename OtherStorage>
557 requires requires {
sizeof(OtherStorage) <
sizeof(Storage); }
561 return raw_with(lhs,
static_cast<OtherStorage
>(rhs));
579 template<
typename DerivedBitpack,
typename RefTypeParam>
580 requires std::is_base_of_v<Bitpack, DerivedBitpack> &&
581 std::is_lvalue_reference_v<RefTypeParam> &&
582 std::is_same_v<Storage, std::remove_cvref_t<RefTypeParam>>
605 constexpr Proxy(R &r) : ref(r.value)
615 template<
typename Self>
617 !std::is_const_v<std::remove_reference_t<RefTypeParam>>)
632 template<
typename Self,
typename RHS>
634 !std::is_const_v<std::remove_reference_t<RefTypeParam>> &&
635 std::is_same_v<Field::Type, Numeric<RHS>>)
637 constexpr Self &&
operator=(
this Self &&self, RHS rhs)
650 template<
typename Self,
typename RHS>
652 !std::is_const_v<std::remove_reference_t<RefTypeParam>> &&
653 std::is_scoped_enum_v<Field::Type> &&
654 std::is_same_v<std::underlying_type_t<Field::Type>, RHS>)
656 constexpr Self &&
operator=(
this Self &&self, RHS rhs)
668 template<
typename Self>
670 !std::is_volatile_v<std::remove_reference_t<RefTypeParam>>)
683 [[nodiscard]]
constexpr auto rawer() const
684 requires(std::is_enum_v<typename
Field::
Type>)
686 return std::to_underlying(this->
raw());
692 [[nodiscard]]
constexpr auto rawer() const
693 requires(std::is_base_of_v<
694 Numeric<typename std::remove_cvref_t<
696 typename std::remove_cvref_t<typename
Field::
Type>>)
698 return this->
raw().raw();
711 return DerivedBitpack{
raw_with(this->ref, rhs)};
722 constexpr DerivedBitpack
with(
auto &&f)
const
740 template<
typename Self>
741 constexpr void alter(
this Self &&self,
auto &&f)
745 !std::is_const_v<std::remove_reference_t<RefTypeParam>>)
773 return raw() <=> rhs.raw();
777 requires(
requires(Field::Type v) {
781 return raw() <=> rhs;
784 constexpr bool operator==(Proxy rhs)
const
785 requires(
requires(Field::Type v) {
786 { v == v } -> std::same_as<bool>;
789 return raw() == rhs.raw();
792 constexpr bool operator==(Field::Type rhs)
const
793 requires(
requires(Field::Type v) {
794 { v == v } -> std::same_as<bool>;
801 template<
bool C,
typename T>
802 requires std::is_lvalue_reference_v<T>
803 using ConditionalConstRef = std::
804 conditional_t<C, std::add_const_t<std::remove_reference_t<T>> &, T>;
815 template<
typename BitpackType>
816 Proxy(BitpackType &r)
817 -> Proxy<std::remove_cvref_t<BitpackType>,
818 ConditionalConstRef<Info.
isConst,
decltype((r.value))>>;
828 template<
typename FieldType, FieldInfo Info,
typename Self>
840 template<
typename FieldType,
typename Self>
841 requires std::is_convertible_v<
842 decltype(std::remove_cvref_t<Self>::template field_info_for_type<
852 std::remove_cvref_t<Self>::template field_info_for_type<FieldType>();
862 template<
typename FieldType,
typename Self>
863 constexpr FieldType
get(
this Self &&self)
873 template<
typename FieldType,
typename Self>
874 constexpr std::remove_cvref_t<Self>
with(
this Self &&self, FieldType v)
884 template<
typename FieldType,
typename Self>
885 constexpr void set(
this Self &&self, FieldType v)
896 template<
typename Self>
897 constexpr void alter(
this Self &&self,
auto &&f)
898 requires std::is_invocable_r_v<std::remove_cvref_t<Self>,
900 std::remove_cvref_t<Self>>
902 std::remove_cvref_t<Self> value{self.value};
911 template<
typename Self>
913 requires std::is_invocable_r_v<std::remove_cvref_t<Self>,
915 std::remove_cvref_t<Self>>
917 self = f(std::remove_cvref_t<Self>(0));
929 requires std::derived_from<B, Bitpack<typename B::Storage>>
936 using ParentBitpack = B;
953#define BITPACK_USUAL_PREFIX \
954 using Bitpack::Bitpack; \
955 using Bitpack::operator=; \
956 template<typename FieldType> \
957 static constexpr FieldInfo field_info_for_type() = delete;
967#define BITPACK_MEMBER_ADD(name, Type, ...) \
968 template<typename Self> \
969 constexpr auto name(this Self &&self) \
971 return self.template member<Type __VA_OPT__(, {__VA_ARGS__})>(); \
981#define BITPACK_MEMBER_ADD_ENUM(Type, Base, ...) \
982 enum class Type : Base; \
984 constexpr FieldInfo field_info_for_type<Type>() \
986 constexpr auto info = FieldInfo{__VA_ARGS__}; \
987 static_assert(requires { Field<Type, info>(); }); \
990 enum class Type : Base
1004#define BITPACK_MEMBER_ADD_ENUM_BOOL(Type, FalseVal, TrueVal, BitIndex, ...) \
1005 BITPACK_MEMBER_ADD_ENUM( \
1006 Type, bool, BitIndex, BitIndex __VA_OPT__(, __VA_ARGS__)) \
1008 FalseVal = false, TrueVal = true, \
1015#define BITPACK_MEMBER_ADD_ENUM_BOOL_CLEARED_ASSERTED(Type, BitIndex, ...) \
1016 BITPACK_MEMBER_ADD_ENUM_BOOL( \
1017 Type, Cleared, Asserted, BitIndex __VA_OPT__(, __VA_ARGS__))
1023#define BITPACK_MEMBER_ADD_ENUM_BOOL_DISABLED_ENABLED(Type, BitIndex, ...) \
1024 BITPACK_MEMBER_ADD_ENUM_BOOL( \
1025 Type, Disabled, Enabled, BitIndex __VA_OPT__(, __VA_ARGS__))
1033#define BITPACK_MEMBER_ADD_NUMERIC(Type, Base, ...) \
1034 struct Type : Numeric<Base> \
1036 using Numeric::Numeric; \
1039 constexpr FieldInfo field_info_for_type<Type>() \
1041 constexpr auto info = FieldInfo{__VA_ARGS__}; \
1042 static_assert(requires { Field<Type, info>(); }); \
1057#define BITPACK_MEMBER_ADD_BOOL(Type, BitIndex, ...) \
1058 BITPACK_MEMBER_ADD_NUMERIC( \
1059 Type, bool, BitIndex, BitIndex __VA_OPT__(, __VA_ARGS__))
1075#define BITPACK_MEMBER_DECLTYPE(b, T) \
1076 (b).template member<std::remove_reference_t<decltype(b)>::T>()
1083#define BITPACK_MEMBER_DEPENDENT(b, T) \
1084 (b).template member<typename std::remove_reference_t<decltype(b)>::T>()
1097#define BITPACK_DERIVED_PREFIX \
1098 using BitpackDerived<ParentBitpack>::BitpackDerived; \
1099 using BitpackDerived<ParentBitpack>::operator=; \
1101 template<typename FieldType> \
1102 static constexpr FieldInfo field_info_for_type() \
1104 return ParentBitpack::field_info_for_type<FieldType>(); \
1108#define BITPACK_DERIVED_FIELD_INFO_FOR_TYPE(Type, lambda) \
1110 constexpr FieldInfo field_info_for_type<Type>() \
1113 std::is_invocable_r_v<void, decltype(lambda), FieldInfo &>); \
1114 auto fi = ParentBitpack::field_info_for_type<Type>(); \
1123#define BITPACK_DERIVED_FIELD_CONST_FOR_TYPE(Type, c) \
1124 BITPACK_DERIVED_FIELD_INFO_FOR_TYPE(Type, [](auto &fi) { fi.isConst = c; })
1140#define BITPACK_OPERATE_QUALIFY(proxy, operator, value) \
1142 using F = decltype(proxy)::Field::Type; \
1143 (proxy) operator(F::value); \
1147#define BITPACK_OPERATE_QUALIFY_DECLTYPE(b, T, operator, v) \
1148 BITPACK_OPERATE_QUALIFY(BITPACK_MEMBER_DECLTYPE(b, T), operator, v)
1151#define BITPACK_OPERATE_QUALIFY_DEPENDENT(b, T, operator, v) \
1152 BITPACK_OPERATE_QUALIFY(BITPACK_MEMBER_DEPENDENT(b, T), operator, v)
1155#define BITPACK_OPERATE_QUALIFY_TYPE(b, T, operator, v) \
1156 BITPACK_OPERATE_QUALIFY((b).template member<T>(), operator, v)
1159#define BITPACK_WITH_QUALIFY(proxy, value) \
1160 BITPACK_OPERATE_QUALIFY(proxy, .with, value)
1166#define BITPACK_WITH_QUALIFY_DECLTYPE(b, T, v) \
1167 BITPACK_OPERATE_QUALIFY_DECLTYPE(b, T, .with, v)
1173#define BITPACK_WITH_QUALIFY_DEPENDENT(b, T, v) \
1174 BITPACK_OPERATE_QUALIFY_DEPENDENT(b, T, .with, v)
1180#define BITPACK_WITH_QUALIFY_TYPE(b, T, v) \
1181 BITPACK_OPERATE_QUALIFY_TYPE(b, T, .with, v)
1198#define BITPACK_OPERATE_WRAP(proxy, operator, value) \
1200 using F = decltype(proxy)::Field::Type; \
1201 (proxy) operator(F{value}); \
1205#define BITPACK_OPERATE_WRAP_DECLTYPE(b, T, operator, v) \
1206 BITPACK_OPERATE_WRAP(BITPACK_MEMBER_DECLTYPE(b, T), operator, v)
1209#define BITPACK_OPERATE_WRAP_DEPENDENT(b, T, operator, v) \
1210 BITPACK_OPERATE_WRAP(BITPACK_MEMBER_DEPENDENT(b, T), operator, v)
1213#define BITPACK_OPERATE_WRAP_TYPE(b, T, operator, v) \
1214 BITPACK_OPERATE_WRAP((b).template member<T>(), operator, v)
1217#define BITPACK_WRAP_WITH(proxy, value) \
1218 BITPACK_OPERATE_WRAP(proxy, .with, value)
1224#define BITPACK_WITH_WRAP_DECLTYPE(b, T, v) \
1225 BITPACK_OPERATE_WRAP_DECLTYPE(b, T, .with, v)
1231#define BITPACK_WITH_WRAP_DEPENDENT(b, T, v) \
1232 BITPACK_OPERATE_WRAP_DEPENDENT(b, T, .with, v)
1235#define BITPACK_WITH_WRAP_TYPE(b, T, v) \
1236 BITPACK_OPERATE_WRAP_TYPE(b, T, .with, v)
1251#define BITPACK_OPERATE_VALUE(b, operator, value) \
1252 ({ (b).template member<decltype(value)>() operator(value); })
1259#define BITPACK_OPERATE_VALUE_DECLTYPE(b, operator, value) \
1260 BITPACK_OPERATE_VALUE( \
1261 b, operator, std::remove_reference_t<decltype(b)>::value)
1267#define BITPACK_OPERATE_VALUE_DEPENDENT(b, operator, value) \
1268 BITPACK_OPERATE_VALUE( \
1269 b, operator, typename std::remove_reference_t<decltype(b)>::value)
1272#define BITPACK_WITH_VALUE(b, value) BITPACK_OPERATE_VALUE(b, .with, value)
1278#define BITPACK_WITH_VALUE_DECLTYPE(b, value) \
1279 BITPACK_OPERATE_VALUE_DECLTYPE(b, .with, value)
1285#define BITPACK_WITH_VALUE_DEPENDENT(b, value) \
1286 BITPACK_OPERATE_VALUE_DEPENDENT(b, .with, value)
1307#define BITPACK_OPERATE_ENUM(proxy, operator, value) \
1309 using E = decltype(proxy)::Field::Type; \
1310 static_assert(std::is_enum_v<E>); \
1312 (proxy) operator(value); \
1316#define BITPACK_OPERATE_ENUM_DECLTYPE(b, T, operator, v) \
1317 BITPACK_OPERATE_ENUM(BITPACK_MEMBER_DECLTYPE(b, T), operator, v)
1320#define BITPACK_OPERATE_ENUM_TYPE(b, T, operator, v) \
1321 BITPACK_OPERATE_ENUM((b).template member<T>(), operator, v)
1324#define BITPACK_WITH_ENUM(proxy, value) \
1325 BITPACK_OPERATE_ENUM(proxy, .with, value)
1331#define BITPACK_WITH_ENUM_DECLTYPE(b, T, v) \
1332 BITPACK_OPERATE_ENUM_DECLTYPE(b, T, .with, v)
1335#define BITPACK_WITH_ENUM_TYPE(b, T, v) \
1336 BITPACK_OPERATE_ENUM_TYPE(b, T, .with, v)
1351#define BITPACK_FIELD_MASK(proxy) \
1352 (static_cast<decltype(proxy)::ContainingBitpack>( \
1353 decltype(proxy)::Field::FieldMask))
1356#define BITPACK_FIELD_MASK_DECLTYPE(b, T) \
1357 BITPACK_FIELD_MASK(BITPACK_MEMBER_DECLTYPE(b, T))
1360#define BITPACK_FIELD_MASK_DEPENDENT(b, T) \
1361 BITPACK_FIELD_MASK(BITPACK_MEMBER_DEPENDENT(b, T))
1367#define BITPACK_FIELD_SHIFT(proxy) (decltype(proxy)::Field::Info.minIndex)
1370#define BITPACK_FIELD_SHIFT_DECLTYPE(b, T) \
1371 BITPACK_FIELD_SHIFT(BITPACK_MEMBER_DECLTYPE(b, T))
1374#define BITPACK_FIELD_SHIFT_DEPENDENT(b, T) \
1375 BITPACK_FIELD_SHIFT(BITPACK_MEMBER_DEPENDENT(b, T))
1392#define BITPACK_MAP_DECLTYPE_HELPER(x, b) \
1393 std::remove_reference_t<decltype(b)>::x
1400#define BITPACK_MAP_DECLTYPE(b, ...) \
1401 CHERIOT_MAP_LIST_UD(BITPACK_MAP_DECLTYPE_HELPER, b, __VA_ARGS__)
1404#define BITPACK_MAP_DEPENDENT_HELPER(x, b) \
1405 typename std::remove_reference_t<decltype(b)>::x
1412#define BITPACK_MAP_DEPENDENT(b, ...) \
1413 CHERIOT_MAP_LIST_UD(BITPACK_MAP_DEPENDENT_HELPER, b, __VA_ARGS__)
1416#define BITPACK_MAP_WITHS_HELPER(x) .with(x)
1424#define BITPACK_WITHS(b, ...) \
1425 (b) CHERIOT_MAP(BITPACK_MAP_WITHS_HELPER, __VA_ARGS__)
1431#define BITPACK_WITHS_DECLTYPE(b, ...) \
1432 BITPACK_WITHS(b, BITPACK_MAP_DECLTYPE(b, __VA_ARGS__))
1438#define BITPACK_WITHS_DEPENDENT(b, ...) \
1439 BITPACK_WITHS(b, BITPACK_MAP_DEPENDENT(b, __VA_ARGS__))
1447#define BITPACK_RELATE_MASKED_HELPER(x, b) \
1449 using BT = decltype(b); \
1450 using FT = decltype(x); \
1451 BT::Field<FT, BT::field_info_for_type<FT>()>::FieldMask; \
1463#define BITPACK_RELATE_MASKED(b, operator, ...) \
1465 constexpr decltype(b.raw()) __bitpack_mask = \
1466 (0)CHERIOT_MAP_UD(BITPACK_RELATE_MASKED_HELPER, b, __VA_ARGS__); \
1467 constexpr auto __bitpack_query = \
1468 BITPACK_WITHS((decltype(b))(0), __VA_ARGS__).raw(); \
1469 (b.raw() & __bitpack_mask) operator(__bitpack_query); \
1476#define BITPACK_RELATE_MASKED_DECLTYPE(b, operator, ...) \
1477 BITPACK_RELATE_MASKED(b, operator, BITPACK_MAP_DECLTYPE(b, __VA_ARGS__))
1483#define BITPACK_RELATE_MASKED_DEPENDENT(b, operator, ...) \
1484 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.
DerivedBitpack ContainingBitpack
Expose the type of the bitpack into which we are a Field::Proxy.
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.
constexpr Storage maximum_as_unsigned() const
Return the maximum value this field can hold, if it is interpreted as holding an unsigned number.
size_t maxIndex
Maximum 0-indexed bit position occupied by this field.
constexpr size_t width() const
Return the field width, in bits.
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.