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,
bool Signed=
false>
124 static_assert(Hi >= Lo,
"BitField: Hi must be >= Lo");
125 static_assert(!Signed || (Hi-Lo)<64,
"Signed BitFields have max width of 64");
127 static_assert(
sizeof(AuxValue) * CHAR_BIT >= Hi - Lo + 1,
"AuxType is too small for BitField");
129 static constexpr unsigned lo = Lo;
130 static constexpr unsigned hi = Hi;
131 static constexpr unsigned width = Hi - Lo + 1;
149 std::string_view
name,
150 std::string_view auxvar,
163 return bits_type{
static_cast<uint64_t
>(std::round((v-offset)/scale)) };
166 const double c =
static_cast<double>(
code(
bits));
167 return {
static_cast<Value>(offset + (c-0.5)*scale),
168 static_cast<Value>(offset + (c+0.5)*scale) };
202 if constexpr (std::is_integral_v<AuxValue>)
218 if(!truncate)
return value(obj);
223 if constexpr (std::is_integral_v<AuxValue>)
232 using unsigned_aux_type = std::make_unsigned_t<AuxValue>;
233 const auto mask =
static_cast<unsigned_aux_type
>(
auxspec.mask);
234 const auto current =
static_cast<unsigned_aux_type
>(val);
235 const auto encoded = (
static_cast<unsigned_aux_type
>(
value) <<
auxspec.shift) & mask;
236 val =
static_cast<AuxValue
>((current & ~mask) | encoded);
257 static_cast<unsigned long long>(
value)
263 template<
typename...
Args>
267 using T = std::decay_t<
decltype(v)>;
269 if constexpr (std::is_convertible_v<T, Value>) {
271 static_cast<Value>(v));
274 throw std::invalid_argument(
275 "Variant alternative cannot be converted "
276 "to BitField value type");
286 if constexpr (Signed) {
291 return static_cast<std::int64_t
>(
value);
323 if constexpr (std::is_arithmetic_v<Value> && !std::is_same_v<Value, bool>) {
324 return static_cast<Value>(
325 (
static_cast<double>(
lo) +
static_cast<double>(
hi)) / 2.0);
337 template<std::
size_t N>
339 static_assert(Hi < N,
"BitField extends beyond the specification width");
343 for (
unsigned i = 0; i <
width; ++i)
344 result[i] = packed[Lo + i];
353 template<std::
size_t N>
358 template<std::
size_t N>
367 template<std::
size_t N>
369 std::bitset <N> &result,
373 "BitField extends beyond the specification width");
377 for (
unsigned i = 0; i <
width; ++i)
378 result[Lo + i] = field_bits[i];
395 template<
unsigned Lo,
unsigned Hi,
typename AuxValue,
typename Value = AuxValue>
399 template<
typename Field>
414 auto value(
bool truncate=
false)
const {
432 template <
typename T>
433 requires (std::is_integral_v<T> && !std::is_same_v<std::remove_cvref_t<T>,
bool> && !std::is_integral_v<typename Field::value_type>)
457 template<std::
size_t N>
458 auto extract(
const std::bitset <N> &packed)
const {
459 return m_field.extract(packed);
466 template<std::
size_t N>
468 return m_field.decodeFrom(packed);
498 template<
typename Derived, std::
size_t N,
typename Base = NoBase>
501 static constexpr std::size_t
width = N;
508 template<std::
size_t I>
static constexpr decltype(
auto)
field() {
509 return *std::get<I>(Derived::allFields());
513 static constexpr std::size_t
516 return std::tuple_size_v < std::remove_cvref_t <
decltype(Derived::allFields()) >> ;
521 std::apply([&](
const auto *...
field) { (func(*
field), ...); }, Derived::allFields());
525 static constexpr std::string
json() {
527 j[
"data_width"] =
width;
528 j[
"fields"] = nlohmann::json::array();
531 f[
"name"] =
field.name();
532 f[
"description"] =
field.description();
533 f[
"start"] =
field.lo;
534 f[
"width"] =
field.width;
535 j[
"fields"].push_back(f);
543 template<
typename... Fields>
545 return std::tuple{&fields...};
551 return std::tuple_cat(
562 template<
typename Fields>
567 [&](
const auto *...
field) {
568 (
field->pack(result, obj), ...);
590 []<
typename... FieldPtrs>(FieldPtrs...
field) {
591 return validateFieldList<
592 std::remove_cvref_t<decltype(*field)>...
603 template<
typename First,
typename... Rest>
606 if constexpr (
sizeof...(Rest) == 0)
619 template<
typename Field>
621 return Field::lo <= Field::hi && Field::hi < N;
628 template<
typename A,
typename B>
630 if (A::lo <= B::hi && B::lo <= A::hi) {
643#define FE_1(m, a) m(a)
644#define FE_2(m, a, ...) m(a) FE_1(m, __VA_ARGS__)
645#define FE_3(m, a, ...) m(a) FE_2(m, __VA_ARGS__)
646#define FE_4(m, a, ...) m(a) FE_3(m, __VA_ARGS__)
647#define FE_5(m, a, ...) m(a) FE_4(m, __VA_ARGS__)
648#define FE_6(m, a, ...) m(a) FE_5(m, __VA_ARGS__)
649#define FE_7(m, a, ...) m(a) FE_6(m, __VA_ARGS__)
650#define FE_8(m, a, ...) m(a) FE_7(m, __VA_ARGS__)
651#define FE_9(m, a, ...) m(a) FE_8(m, __VA_ARGS__)
652#define FE_10(m, a, ...) m(a) FE_9(m, __VA_ARGS__)
653#define FE_11(m, a, ...) m(a) FE_10(m, __VA_ARGS__)
654#define FE_12(m, a, ...) m(a) FE_11(m, __VA_ARGS__)
655#define FE_13(m, a, ...) m(a) FE_12(m, __VA_ARGS__)
656#define FE_14(m, a, ...) m(a) FE_13(m, __VA_ARGS__)
657#define FE_15(m, a, ...) m(a) FE_14(m, __VA_ARGS__)
658#define FE_16(m, a, ...) m(a) FE_15(m, __VA_ARGS__)
659#define FE_17(m, a, ...) m(a) FE_16(m, __VA_ARGS__)
660#define FE_18(m, a, ...) m(a) FE_18(m, __VA_ARGS__)
661#define FE_19(m, a, ...) m(a) FE_19(m, __VA_ARGS__)
662#define FE_20(m, a, ...) m(a) FE_20(m, __VA_ARGS__)
664#define GET_FE(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10, \
665 _11,_12,_13,_14,_15,_16,_17,_18,_19,_20,NAME,...) NAME
667#define FOR_EACH(m, ...) \
668 GET_FE(__VA_ARGS__, \
669 FE_20, FE_19, FE_18, FE_17, \
670 FE_16, FE_15, FE_14, FE_13, \
671 FE_12, FE_11, FE_10, FE_9, \
672 FE_8, FE_7, FE_6, FE_5, \
673 FE_4, FE_3, FE_2, FE_1)(m, __VA_ARGS__)
675#define FIELD_PTR(name) \
676 static inline constexpr auto name##_ptr = &name;
678#define FIELD_PTR_VALUE(name) name##_ptr,
682#define FIELD_ACCESSOR(name) \
683 BitFieldAccessor<std::remove_cvref_t<decltype(*name##_ptr)>> name{*name##_ptr,m_obj};
685#define DECLARE_FIELDS(...) \
687 FOR_EACH(FIELD_PTR, __VA_ARGS__) \
689 static inline constexpr auto fields = \
690 std::tuple{ FOR_EACH(FIELD_PTR_VALUE, __VA_ARGS__) }; \
692 static_assert(validateFields(),"Invalid spec: overlapping fields or fields beyond spec"); \
697 explicit ObjectAcc(const SG::AuxElement& obj) \
701 const SG::AuxElement& m_obj; \
704 FOR_EACH(FIELD_ACCESSOR, __VA_ARGS__) \
Base class for elements of a container that can have aux data.
doing TRTHTH Hypo selection
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 value(const SG::AuxElement &obj, bool truncate) const
bits_type extract(const std::bitset< N > &packed) const
static constexpr unsigned lo
AuxValue & store(SG::AuxElement &obj, Value value) const
constexpr std::string_view name() const
void decodeAndAssignFrom(const std::bitset< N > &packed, SG::AuxElement &obj) const
std::string_view m_description
constexpr BitField(const Params &p)
static std::int64_t code(bits_type bits)
bits_type encode(const std::variant< Args... > &value) const
SG::ConstAccessor< AuxValue > m_acc
Value value(const SG::AuxElement &obj) const
bits_type bits(const SG::AuxElement &obj) const
static constexpr unsigned hi
static constexpr unsigned width
bits_type encode(Value value) const
constexpr std::string_view description() const
std::bitset< width > bits_type
constexpr BitField(std::string_view name, std::string_view auxvar, std::string_view description, encoder_type encoder=nullptr, decoder_type decoder=nullptr, Value scale=0, Value offset=0)
std::function< std::pair< Value, Value >(bits_type)> decoder_type
void pack(std::bitset< N > &result, const SG::AuxElement &obj) const
Value decodeFrom(const std::bitset< N > &packed) const
SG::Accessor< AuxValue > m_wacc
Value decode(bits_type bits) const
std::function< bits_type(Value)> encoder_type
std::pair< Value, Value > range(bits_type bits) const
static constexpr std::size_t width
static constexpr void forEachField(auto &&func)
static constexpr std::string json()
std::bitset< N > bitset_type
static constexpr decltype(auto) field()
static consteval bool validateField()
static consteval bool checkOverlap()
static consteval bool validateFieldList()
static constexpr auto makeFields(Fields &... fields)
static constexpr auto allFields()
static consteval bool validateFields()
static bitset_type packFields(const Fields &fields, const SG::AuxElement &obj)
static constexpr std::size_t numFields()
AlgTool to read in LArStripNeighborhoods, and run the BDT Algorithm.
BitField< Lo, Hi, AuxValue, Value, true > SignedBitField
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)
std::string_view description
static constexpr auto allFields()