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;
482 template<
typename TypeParam, FieldInfo InfoParam>
491 static_assert(
Info.maxIndex >=
Info.minIndex,
492 "Field span ends before it begins");
494 static_assert(!std::is_base_of_v<Numeric<bool>,
Type> ||
496 "Numeric<bool> fields should be exactly one bit wide");
499 !std::is_enum_v<Type> ||
501 { std::underlying_type_t<Type>() } -> std::same_as<bool>;
503 "Enum fields with underlying type bool should be exactly "
507 CHAR_BIT *
sizeof(Type),
508 "Field type is narrower than specified field bit width");
512 "Field width is not smaller than Bitpack's Storage type");
516 (1U << (
Info.maxIndex -
Info.minIndex + 1)) - 1;
535 requires requires {
static_cast<Storage>(std::declval<Type>()); }
537 return raw_with(lhs,
static_cast<Storage>(rhs));
541 template<
typename OtherStorage>
542 requires requires {
sizeof(OtherStorage) <
sizeof(Storage); }
546 return raw_with(lhs,
static_cast<OtherStorage
>(rhs));
564 template<
typename DerivedBitpack,
typename RefTypeParam>
565 requires std::is_base_of_v<Bitpack, DerivedBitpack> &&
566 std::is_lvalue_reference_v<RefTypeParam> &&
567 std::is_same_v<Storage, std::remove_cvref_t<RefTypeParam>>
587 constexpr Proxy(R &r) : ref(r.value)
597 template<
typename Self>
599 !std::is_const_v<std::remove_reference_t<RefTypeParam>>)
614 template<
typename Self,
typename RHS>
616 !std::is_const_v<std::remove_reference_t<RefTypeParam>> &&
617 std::is_same_v<Field::Type, Numeric<RHS>>)
619 constexpr Self &&
operator=(
this Self &&self, RHS rhs)
632 template<
typename Self,
typename RHS>
634 !std::is_const_v<std::remove_reference_t<RefTypeParam>> &&
635 std::is_scoped_enum_v<Field::Type> &&
636 std::is_same_v<std::underlying_type_t<Field::Type>, RHS>)
638 constexpr Self &&
operator=(
this Self &&self, RHS rhs)
650 template<
typename Self>
652 !std::is_volatile_v<std::remove_reference_t<RefTypeParam>>)
665 [[nodiscard]]
constexpr auto rawer() const
666 requires(std::is_enum_v<typename
Field::
Type>)
668 return std::to_underlying(this->
raw());
674 [[nodiscard]]
constexpr auto rawer() const
675 requires(std::is_base_of_v<
676 Numeric<typename std::remove_cvref_t<
678 typename std::remove_cvref_t<typename
Field::
Type>>)
680 return this->
raw().raw();
693 return DerivedBitpack{
raw_with(this->ref, rhs)};
704 constexpr DerivedBitpack
with(
auto &&f)
const
722 template<
typename Self>
723 constexpr void alter(
this Self &&self,
auto &&f)
727 !std::is_const_v<std::remove_reference_t<RefTypeParam>>)
755 return raw() <=> rhs.raw();
759 requires(
requires(Field::Type v) {
763 return raw() <=> rhs;
766 constexpr bool operator==(Proxy rhs)
const
767 requires(
requires(Field::Type v) {
768 { v == v } -> std::same_as<bool>;
771 return raw() == rhs.raw();
774 constexpr bool operator==(Field::Type rhs)
const
775 requires(
requires(Field::Type v) {
776 { v == v } -> std::same_as<bool>;
783 template<
bool C,
typename T>
784 requires std::is_lvalue_reference_v<T>
785 using ConditionalConstRef = std::
786 conditional_t<C, std::add_const_t<std::remove_reference_t<T>> &, T>;
797 template<
typename BitpackType>
798 Proxy(BitpackType &r)
799 -> Proxy<std::remove_cvref_t<BitpackType>,
800 ConditionalConstRef<Info.
isConst,
decltype((r.value))>>;
810 template<
typename FieldType, FieldInfo Info,
typename Self>
822 template<
typename FieldType,
typename Self>
823 requires std::is_convertible_v<
824 decltype(std::remove_cvref_t<Self>::template field_info_for_type<
834 std::remove_cvref_t<Self>::template field_info_for_type<FieldType>();
844 template<
typename FieldType,
typename Self>
845 constexpr FieldType
get(
this Self &&self)
855 template<
typename FieldType,
typename Self>
856 constexpr std::remove_cvref_t<Self>
with(
this Self &&self, FieldType v)
866 template<
typename FieldType,
typename Self>
867 constexpr void set(
this Self &&self, FieldType v)
878 template<
typename Self>
879 constexpr void alter(
this Self &&self,
auto &&f)
880 requires std::is_invocable_r_v<std::remove_cvref_t<Self>,
882 std::remove_cvref_t<Self>>
884 std::remove_cvref_t<Self> value{self.value};
893 template<
typename Self>
895 requires std::is_invocable_r_v<std::remove_cvref_t<Self>,
897 std::remove_cvref_t<Self>>
899 self = f(std::remove_cvref_t<Self>(0));
911 requires std::derived_from<B, Bitpack<typename B::Storage>>
918 using ParentBitpack = B;
935#define BITPACK_USUAL_PREFIX \
936 using Bitpack::Bitpack; \
937 using Bitpack::operator=; \
938 template<typename FieldType> \
939 static constexpr FieldInfo field_info_for_type() = delete;
949#define BITPACK_MEMBER_ADD(name, Type, ...) \
950 template<typename Self> \
951 constexpr auto name(this Self &&self) \
953 return self.template member<Type __VA_OPT__(, {__VA_ARGS__})>(); \
963#define BITPACK_MEMBER_ADD_ENUM(Type, Base, ...) \
964 enum class Type : Base; \
966 constexpr FieldInfo field_info_for_type<Type>() \
968 constexpr auto info = FieldInfo{__VA_ARGS__}; \
969 static_assert(requires { Field<Type, info>(); }); \
972 enum class Type : Base
986#define BITPACK_MEMBER_ADD_ENUM_BOOL(Type, FalseVal, TrueVal, BitIndex, ...) \
987 BITPACK_MEMBER_ADD_ENUM(Type, bool, BitIndex, BitIndex, __VA_ARGS__) \
989 FalseVal = false, TrueVal = true, \
996#define BITPACK_MEMBER_ADD_ENUM_BOOL_CLEARED_ASSERTED(Type, BitIndex, ...) \
997 BITPACK_MEMBER_ADD_ENUM_BOOL(Type, Cleared, Asserted, BitIndex, __VA_ARGS__)
1003#define BITPACK_MEMBER_ADD_ENUM_BOOL_DISABLED_ENABLED(Type, BitIndex, ...) \
1004 BITPACK_MEMBER_ADD_ENUM_BOOL(Type, Disabled, Enabled, BitIndex, __VA_ARGS__)
1012#define BITPACK_MEMBER_ADD_NUMERIC(Type, Base, ...) \
1013 struct Type : Numeric<Base> \
1015 using Numeric::Numeric; \
1018 constexpr FieldInfo field_info_for_type<Type>() \
1020 constexpr auto info = FieldInfo{__VA_ARGS__}; \
1021 static_assert(requires { Field<Type, info>(); }); \
1036#define BITPACK_MEMBER_ADD_BOOL(Type, BitIndex, ...) \
1037 BITPACK_MEMBER_ADD_NUMERIC(Type, bool, BitIndex, BitIndex, __VA_ARGS__)
1053#define BITPACK_MEMBER_DECLTYPE(b, T) \
1054 (b).template member<std::remove_reference_t<decltype(b)>::T>()
1061#define BITPACK_MEMBER_DEPENDENT(b, T) \
1062 (b).template member<typename std::remove_reference_t<decltype(b)>::T>()
1075#define BITPACK_DERIVED_PREFIX \
1076 using BitpackDerived<ParentBitpack>::BitpackDerived; \
1077 using BitpackDerived<ParentBitpack>::operator=; \
1079 template<typename FieldType> \
1080 static constexpr FieldInfo field_info_for_type() \
1082 return ParentBitpack::field_info_for_type<FieldType>(); \
1086#define BITPACK_DERIVED_FIELD_INFO_FOR_TYPE(Type, lambda) \
1088 constexpr FieldInfo field_info_for_type<Type>() \
1091 std::is_invocable_r_v<void, decltype(lambda), FieldInfo &>); \
1092 auto fi = ParentBitpack::field_info_for_type<Type>(); \
1101#define BITPACK_DERIVED_FIELD_CONST_FOR_TYPE(Type, c) \
1102 BITPACK_DERIVED_FIELD_INFO_FOR_TYPE(Type, [](auto &fi) { fi.isConst = c; })
1118#define BITPACK_OPERATE_QUALIFY(proxy, operator, value) \
1120 using F = decltype(proxy)::Field::Type; \
1121 (proxy) operator(F::value); \
1125#define BITPACK_OPERATE_QUALIFY_DECLTYPE(b, T, operator, v) \
1126 BITPACK_OPERATE_QUALIFY(BITPACK_MEMBER_DECLTYPE(b, T), operator, v)
1129#define BITPACK_OPERATE_QUALIFY_DEPENDENT(b, T, operator, v) \
1130 BITPACK_OPERATE_QUALIFY(BITPACK_MEMBER_DEPENDENT(b, T), operator, v)
1133#define BITPACK_OPERATE_QUALIFY_TYPE(b, T, operator, v) \
1134 BITPACK_OPERATE_QUALIFY((b).template member<T>(), operator, v)
1137#define BITPACK_WITH_QUALIFY(proxy, value) \
1138 BITPACK_OPERATE_QUALIFY(proxy, .with, value)
1144#define BITPACK_WITH_QUALIFY_DECLTYPE(b, T, v) \
1145 BITPACK_OPERATE_QUALIFY_DECLTYPE(b, T, .with, v)
1151#define BITPACK_WITH_QUALIFY_DEPENDENT(b, T, v) \
1152 BITPACK_OPERATE_QUALIFY_DEPENDENT(b, T, .with, v)
1158#define BITPACK_WITH_QUALIFY_TYPE(b, T, v) \
1159 BITPACK_OPERATE_QUALIFY_TYPE(b, T, .with, v)
1176#define BITPACK_OPERATE_WRAP(proxy, operator, value) \
1178 using F = decltype(proxy)::Field::Type; \
1179 (proxy) operator(F{value}); \
1183#define BITPACK_OPERATE_WRAP_DECLTYPE(b, T, operator, v) \
1184 BITPACK_OPERATE_WRAP(BITPACK_MEMBER_DECLTYPE(b, T), operator, v)
1187#define BITPACK_OPERATE_WRAP_DEPENDENT(b, T, operator, v) \
1188 BITPACK_OPERATE_WRAP(BITPACK_MEMBER_DEPENDENT(b, T), operator, v)
1191#define BITPACK_OPERATE_WRAP_TYPE(b, T, operator, v) \
1192 BITPACK_OPERATE_WRAP((b).template member<T>(), operator, v)
1195#define BITPACK_WRAP_WITH(proxy, value) \
1196 BITPACK_OPERATE_WRAP(proxy, .with, value)
1202#define BITPACK_WITH_WRAP_DECLTYPE(b, T, v) \
1203 BITPACK_OPERATE_WRAP_DECLTYPE(b, T, .with, v)
1209#define BITPACK_WITH_WRAP_DEPENDENT(b, T, v) \
1210 BITPACK_OPERATE_WRAP_DEPENDENT(b, T, .with, v)
1213#define BITPACK_WITH_WRAP_TYPE(b, T, v) \
1214 BITPACK_OPERATE_WRAP_TYPE(b, T, .with, v)
1229#define BITPACK_OPERATE_VALUE(b, operator, value) \
1230 ({ (b).template member<decltype(value)>() operator(value); })
1237#define BITPACK_OPERATE_VALUE_DECLTYPE(b, operator, value) \
1238 BITPACK_OPERATE_VALUE( \
1239 b, operator, std::remove_reference_t<decltype(b)>::value)
1245#define BITPACK_OPERATE_VALUE_DEPENDENT(b, operator, value) \
1246 BITPACK_OPERATE_VALUE( \
1247 b, operator, typename std::remove_reference_t<decltype(b)>::value)
1250#define BITPACK_WITH_VALUE(b, value) BITPACK_OPERATE_VALUE(b, .with, value)
1256#define BITPACK_WITH_VALUE_DECLTYPE(b, value) \
1257 BITPACK_OPERATE_VALUE_DECLTYPE(b, .with, value)
1263#define BITPACK_WITH_VALUE_DEPENDENT(b, value) \
1264 BITPACK_OPERATE_VALUE_DEPENDENT(b, .with, value)
1285#define BITPACK_OPERATE_ENUM(proxy, operator, value) \
1287 using E = decltype(proxy)::Field::Type; \
1288 static_assert(std::is_enum_v<E>); \
1290 (proxy) operator(value); \
1294#define BITPACK_OPERATE_ENUM_DECLTYPE(b, T, operator, v) \
1295 BITPACK_OPERATE_ENUM(BITPACK_MEMBER_DECLTYPE(b, T), operator, v)
1298#define BITPACK_OPERATE_ENUM_TYPE(b, T, operator, v) \
1299 BITPACK_OPERATE_ENUM((b).template member<T>(), operator, v)
1302#define BITPACK_WITH_ENUM(proxy, value) \
1303 BITPACK_OPERATE_ENUM(proxy, .with, value)
1309#define BITPACK_WITH_ENUM_DECLTYPE(b, T, v) \
1310 BITPACK_OPERATE_ENUM_DECLTYPE(b, T, .with, v)
1313#define BITPACK_WITH_ENUM_TYPE(b, T, v) \
1314 BITPACK_OPERATE_ENUM_TYPE(b, T, .with, v)
1352#define BITPACK_HAS_MACRO_MAP \
1354 struct BITPACK_HAS_MACRO_MAP_T \
1358 struct BITPACK_HAS_MACRO_MAP_U \
1362 BITPACK_HAS_MACRO_MAP_U CHERIOT_EVAL0(BITPACK_HAS_MACRO_MAP_T); \
1363 return sizeof(BITPACK_HAS_MACRO_MAP_T); \
1367#define BITPACK_MAP_DECLTYPE_HELPER(x, b) \
1368 std::remove_reference_t<decltype(b)>::x
1380#define BITPACK_MAP_DECLTYPE(b, ...) \
1381 CHERIOT_MAP_LIST_UD(BITPACK_MAP_DECLTYPE_HELPER, b, __VA_ARGS__)
1384#define BITPACK_MAP_DEPENDENT_HELPER(x, b) \
1385 typename std::remove_reference_t<decltype(b)>::x
1394#define BITPACK_MAP_DEPENDENT(b, ...) \
1395 CHERIOT_MAP_LIST_UD(BITPACK_MAP_DEPENDENT_HELPER, b, __VA_ARGS__)
1398#define BITPACK_MAP_WITHS_HELPER(x) .with(x)
1406#define BITPACK_WITHS(b, ...) \
1408 static_assert(BITPACK_HAS_MACRO_MAP, \
1409 "BITPACK_WITHS requires __macro_map.h"); \
1410 (b) CHERIOT_MAP(BITPACK_MAP_WITHS_HELPER, __VA_ARGS__); \
1417#define BITPACK_WITHS_DECLTYPE(b, ...) \
1418 BITPACK_WITHS(b, BITPACK_MAP_DECLTYPE(b, __VA_ARGS__))
1424#define BITPACK_WITHS_DEPENDENT(b, ...) \
1425 BITPACK_WITHS(b, BITPACK_MAP_DEPENDENT(b, __VA_ARGS__))
1433#define BITPACK_RELATE_MASKED_HELPER(x, b) \
1435 using BT = decltype(b); \
1436 using FT = decltype(x); \
1437 BT::Field<FT, BT::field_info_for_type<FT>()>::FieldMask; \
1449#define BITPACK_RELATE_MASKED(b, operator, ...) \
1451 static_assert(BITPACK_HAS_MACRO_MAP, \
1452 "BITPACK_MASKED_REL requires __macro_map.h"); \
1453 constexpr decltype(b.raw()) __bitpack_mask = \
1454 (0)CHERIOT_MAP_UD(BITPACK_RELATE_MASKED_HELPER, b, __VA_ARGS__); \
1455 constexpr auto __bitpack_query = \
1456 BITPACK_WITHS((decltype(b))(0), __VA_ARGS__).raw(); \
1457 (b.raw() & __bitpack_mask) operator(__bitpack_query); \
1464#define BITPACK_RELATE_MASKED_DECLTYPE(b, operator, ...) \
1465 BITPACK_RELATE_MASKED(b, operator, BITPACK_MAP_DECLTYPE(b, __VA_ARGS__))
1471#define BITPACK_RELATE_MASKED_DEPENDENT(b, operator, ...) \
1472 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.