5#ifndef GLOBALSIM_BITSPEC_H
6#define GLOBALSIM_BITSPEC_H
19#include <nlohmann/json.hpp>
46 static constexpr std::size_t
parseNumber(std::string_view
str,std::size_t& pos,std::size_t end) {
48 const auto [ptr, ec] = std::from_chars(
54 if (ec != std::errc{})
55 throw std::invalid_argument(
"Expected number");
57 pos = ptr -
str.data();
62 const auto open = spec.find(
'[');
65 if (open == std::string_view::npos) {
68 std::numeric_limits<std::uint64_t>::max(),
75 const auto colon = spec.find(
':', open + 1);
76 const auto close = spec.find(
']', open + 1);
78 if (close == std::string_view::npos ||close != spec.size() - 1) {
79 throw std::invalid_argument(
"Invalid AuxSpec");
82 std::size_t pos = open + 1;
83 const std::size_t lo =
parseNumber(spec, pos, colon == std::string_view::npos ? close : colon);
87 if (colon != std::string_view::npos) {
89 if (colon == open + 1 || colon + 1 == close) {
90 throw std::invalid_argument(
"Invalid AuxSpec range");
96 if (pos != close || lo > hi || hi >= 64)
97 throw std::invalid_argument(
"Invalid bit range");
99 const std::size_t
width = hi - lo + 1;
101 const std::uint64_t
mask =
103 ? std::numeric_limits<std::uint64_t>::max()
104 : ((std::uint64_t{1} <<
width) - 1) << lo;
107 spec.substr(0, open),
121 template<
unsigned Lo,
unsigned Hi,
typename AuxValue,
typename Value=AuxValue>
124 static_assert(Hi >= Lo,
"BitField: Hi must be >= Lo");
126 static_assert(
sizeof(AuxValue) * CHAR_BIT >= Hi - Lo + 1,
"AuxType is too small for BitField");
128 static constexpr unsigned lo = Lo;
129 static constexpr unsigned hi = Hi;
130 static constexpr unsigned width = Hi - Lo + 1;
148 std::string_view
name,
149 std::string_view auxvar,
176 if constexpr (std::is_integral_v<AuxValue>)
192 if(!truncate)
return value(obj);
197 if constexpr (std::is_integral_v<AuxValue>)
225 static_cast<unsigned long long>(
value)
245 return static_cast<Value>(
bits.to_ullong());
252 template<std::
size_t N>
254 static_assert(Hi < N,
"BitField extends beyond the specification width");
258 for (
unsigned i = 0; i <
width; ++i)
259 result[i] = packed[Lo + i];
268 template<std::
size_t N>
273 template<std::
size_t N>
282 template<std::
size_t N>
284 std::bitset <N> &result,
288 "BitField extends beyond the specification width");
292 for (
unsigned i = 0; i <
width; ++i)
293 result[Lo + i] = field_bits[i];
310 template<
typename Field>
325 auto value(
bool truncate=
false)
const {
360 template<std::
size_t N>
361 auto extract(
const std::bitset <N> &packed)
const {
362 return m_field.extract(packed);
369 template<std::
size_t N>
371 return m_field.decodeFrom(packed);
389 template<
typename Derived, std::
size_t N>
392 static constexpr std::size_t
width = N;
398 template<std::
size_t I>
static constexpr decltype(
auto)
field() {
399 return *std::get<I>(Derived::fields);
403 static constexpr std::size_t
406 return std::tuple_size_v < std::remove_cvref_t <
decltype(Derived::fields) >> ;
411 std::apply([&](
const auto *...
field) { (func(*
field), ...); }, Derived::fields);
415 static constexpr std::string
json() {
417 j[
"data_width"] =
width;
418 j[
"fields"] = nlohmann::json::array();
421 f[
"name"] =
field.name();
422 f[
"description"] =
field.description();
423 f[
"start"] =
field.lo;
424 f[
"width"] =
field.width;
425 j[
"fields"].push_back(f);
433 template<
typename... Fields>
435 return std::tuple{&fields...};
443 template<
typename Fields>
448 [&](
const auto *...
field) {
449 (
field->pack(result, obj), ...);
471 []<
typename... FieldPtrs>(FieldPtrs...
field) {
472 return validateFieldList<
473 std::remove_cvref_t<decltype(*field)>...
484 template<
typename First,
typename... Rest>
487 if constexpr (
sizeof...(Rest) == 0)
500 template<
typename Field>
502 return Field::lo <= Field::hi && Field::hi < N;
509 template<
typename A,
typename B>
511 if (A::lo <= B::hi && B::lo <= A::hi) {
524#define FE_1(m, a) m(a)
525#define FE_2(m, a, ...) m(a) FE_1(m, __VA_ARGS__)
526#define FE_3(m, a, ...) m(a) FE_2(m, __VA_ARGS__)
527#define FE_4(m, a, ...) m(a) FE_3(m, __VA_ARGS__)
528#define FE_5(m, a, ...) m(a) FE_4(m, __VA_ARGS__)
529#define FE_6(m, a, ...) m(a) FE_5(m, __VA_ARGS__)
530#define FE_7(m, a, ...) m(a) FE_6(m, __VA_ARGS__)
531#define FE_8(m, a, ...) m(a) FE_7(m, __VA_ARGS__)
532#define FE_9(m, a, ...) m(a) FE_8(m, __VA_ARGS__)
533#define FE_10(m, a, ...) m(a) FE_9(m, __VA_ARGS__)
534#define FE_11(m, a, ...) m(a) FE_10(m, __VA_ARGS__)
535#define FE_12(m, a, ...) m(a) FE_11(m, __VA_ARGS__)
536#define FE_13(m, a, ...) m(a) FE_12(m, __VA_ARGS__)
537#define FE_14(m, a, ...) m(a) FE_13(m, __VA_ARGS__)
538#define FE_15(m, a, ...) m(a) FE_14(m, __VA_ARGS__)
539#define FE_16(m, a, ...) m(a) FE_15(m, __VA_ARGS__)
540#define FE_17(m, a, ...) m(a) FE_16(m, __VA_ARGS__)
541#define FE_18(m, a, ...) m(a) FE_18(m, __VA_ARGS__)
542#define FE_19(m, a, ...) m(a) FE_19(m, __VA_ARGS__)
543#define FE_20(m, a, ...) m(a) FE_20(m, __VA_ARGS__)
545#define GET_FE(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10, \
546 _11,_12,_13,_14,_15,_16,_17,_18,_19,_20,NAME,...) NAME
548#define FOR_EACH(m, ...) \
549 GET_FE(__VA_ARGS__, \
550 FE_20, FE_19, FE_18, FE_17, \
551 FE_16, FE_15, FE_14, FE_13, \
552 FE_12, FE_11, FE_10, FE_9, \
553 FE_8, FE_7, FE_6, FE_5, \
554 FE_4, FE_3, FE_2, FE_1)(m, __VA_ARGS__)
556#define FIELD_PTR(name) \
557 static inline constexpr auto name##_ptr = &name;
559#define FIELD_PTR_VALUE(name) name##_ptr,
563#define FIELD_ACCESSOR(name) \
564 BitFieldAccessor<std::remove_cvref_t<decltype(*name##_ptr)>> name{*name##_ptr,m_obj};
566#define DECLARE_FIELDS(...) \
568 FOR_EACH(FIELD_PTR, __VA_ARGS__) \
570 static inline constexpr auto fields = \
571 std::tuple{ FOR_EACH(FIELD_PTR_VALUE, __VA_ARGS__) }; \
573 static_assert(validateFields(),"Invalid spec: overlapping fields or fields beyond spec"); \
578 explicit ObjectAcc(const SG::AuxElement& obj) \
582 const SG::AuxElement& m_obj; \
585 FOR_EACH(FIELD_ACCESSOR, __VA_ARGS__) \
Base class for elements of a container that can have aux data.
BitFieldAccessor(const Field &field, const SG::AuxElement &obj)
auto decodeFrom(const std::bitset< N > &packed) const
BitFieldAccessor & operator=(const Field::value_type &value)
BitFieldAccessor & operator()()
const SG::AuxElement & m_obj
BitFieldAccessor & operator=(const Field::bits_type &bits)
constexpr auto spec() const
auto value(bool truncate=false) const
auto extract(const std::bitset< N > &packed) const
Value(*)(bits_type) decoder_type
SG::Accessor< AuxValue > m_wacc
static constexpr unsigned width
SG::ConstAccessor< AuxValue > m_acc
bits_type(*)(Value) encoder_type
Value value(const SG::AuxElement &obj, bool truncate) const
static constexpr unsigned hi
void decodeAndAssignFrom(const std::bitset< N > &packed, SG::AuxElement &obj) const
bits_type extract(const std::bitset< N > &packed) const
void pack(std::bitset< N > &result, const SG::AuxElement &obj) const
constexpr std::string_view description() const
constexpr BitField(std::string_view name, std::string_view auxvar, std::string_view description, encoder_type encoder=nullptr, decoder_type decoder=nullptr)
constexpr std::string_view name() const
Value value(const SG::AuxElement &obj) const
Value decodeFrom(const std::bitset< N > &packed) const
std::string_view m_description
bits_type bits(const SG::AuxElement &obj) const
bits_type encode(Value value) const
AuxValue & store(SG::AuxElement &obj, Value value) const
std::bitset< width > bits_type
static constexpr unsigned lo
Value decode(bits_type bits) const
static consteval bool validateFields()
static constexpr decltype(auto) field()
static consteval bool validateFieldList()
static constexpr void forEachField(auto &&func)
static bitset_type packFields(const Fields &fields, const SG::AuxElement &obj)
std::bitset< N > bitset_type
static constexpr std::size_t width
static consteval bool validateField()
static constexpr std::string json()
static consteval bool checkOverlap()
static constexpr std::size_t numFields()
static constexpr auto makeFields(Fields &... fields)
AlgTool to read in LArStripNeighborhoods, and run the BDT Algorithm.
AuxElement(SG::AuxVectorData *container, size_t index)
Base class for elements of a container that can have aux data.
static constexpr std::size_t parseNumber(std::string_view str, std::size_t &pos, std::size_t end)
static constexpr AuxSpec parse(std::string_view spec)