5#ifndef GLOBALSIM_BITSPEC_H
6#define GLOBALSIM_BITSPEC_H
20#include <nlohmann/json.hpp>
47 static constexpr std::size_t
parseNumber(std::string_view
str,std::size_t& pos,std::size_t end) {
49 const auto [ptr, ec] = std::from_chars(
55 if (ec != std::errc{})
56 throw std::invalid_argument(
"Expected number");
58 pos = ptr -
str.data();
63 const auto open = spec.find(
'[');
66 if (open == std::string_view::npos) {
69 std::numeric_limits<std::uint64_t>::max(),
76 const auto colon = spec.find(
':', open + 1);
77 const auto close = spec.find(
']', open + 1);
79 if (close == std::string_view::npos ||close != spec.size() - 1) {
80 throw std::invalid_argument(
"Invalid AuxSpec");
83 std::size_t pos = open + 1;
84 const std::size_t lo =
parseNumber(spec, pos, colon == std::string_view::npos ? close : colon);
88 if (colon != std::string_view::npos) {
90 if (colon == open + 1 || colon + 1 == close) {
91 throw std::invalid_argument(
"Invalid AuxSpec range");
97 if (pos != close || lo > hi || hi >= 64)
98 throw std::invalid_argument(
"Invalid bit range");
100 const std::size_t
width = hi - lo + 1;
102 const std::uint64_t
mask =
104 ? std::numeric_limits<std::uint64_t>::max()
105 : ((std::uint64_t{1} <<
width) - 1) << lo;
108 spec.substr(0, open),
124 template <std::
size_t N,
bool Clamp = false,
bool Signed = false>
129 if constexpr (N >= 64)
return std::numeric_limits<std::uint64_t>::max();
130 else return (std::uint64_t{1} << N) - 1;
134 if constexpr (N >= 64)
return std::numeric_limits<std::int64_t>::min();
135 else return -(std::int64_t{1} << (N - 1));
139 if constexpr (N == 64)
return std::numeric_limits<std::int64_t>::max();
140 else return (std::int64_t{1} << (N - 1)) - 1;
143 template <
typename T>
144 static constexpr std::uint64_t
convert(T value) {
145 static_assert(std::is_integral_v<T>);
147 if constexpr (!Clamp) {
148 return static_cast<std::uint64_t
>(value);
149 }
else if constexpr (Signed) {
150 if constexpr (std::is_signed_v<T>) {
153 return std::clamp(
static_cast<std::uint64_t
>(value),std::uint64_t{0},
static_cast<std::uint64_t
>(
signedMax()));
156 if constexpr (std::is_signed_v<T>) {
160 return std::clamp(
static_cast<std::uint64_t
>(value),std::uint64_t{0},
unsignedMax());
166 static constexpr auto max = [] {
167 if constexpr (Signed)
return signedMax();
170 static constexpr auto min = [] {
171 if constexpr (Signed)
return signedMin();
172 else return std::uint64_t{0};
187 template <std::
size_t M>
188 constexpr Bitset(
const std::bitset<M>& other) {
189 constexpr std::size_t
count = (N < M) ? N : M;
190 for (std::size_t i = 0; i <
count; ++i) {
191 this->
set(i, other[i]);
195 template <
typename T>
196 requires std::is_integral_v<T>
204 template<
unsigned Lo,
unsigned Hi,
typename AuxValue,
typename Value=AuxValue,
bool Signed=
false,
bool Clamped=
true>
207 static_assert(Hi >= Lo,
"BitField: Hi must be >= Lo");
208 static_assert(!Signed || (Hi-Lo)<64,
"Signed BitFields have max width of 64");
210 static_assert(
sizeof(AuxValue) * CHAR_BIT >= Hi - Lo + 1,
"AuxType is too small for BitField");
212 static constexpr unsigned lo = Lo;
213 static constexpr unsigned hi = Hi;
214 static constexpr unsigned width = Hi - Lo + 1;
235 std::string_view name_,
236 std::string_view auxvar,
237 std::string_view description_,
240 Value scale = 0,
Value offset = 0,
double centre = 0.5,
bool lower_inc =
true)
248 if constexpr (Signed) {
254 return bits_type{
static_cast<int64_t
>(std::floor((v - offset) / scale))};
258 return bits_type{
static_cast<int64_t
>((std::ceil((v - offset) / scale) - 1))};
263 return bits_type{
static_cast<uint64_t
>(lower_inc ? std::floor((v - offset) / scale) : (
264 std::ceil((v - offset) / scale) - 1))};
268 const double c =
static_cast<double>(
code(
bits));
269 return {
static_cast<Value>(offset + c*scale),
270 static_cast<Value>(offset + (c+1.0)*scale) };
273 if constexpr (std::is_arithmetic_v<Value> && !std::is_same_v<Value, bool>)
310 if constexpr (std::is_integral_v<AuxValue>)
326 if(!truncate)
return value(obj);
331 if constexpr (std::is_integral_v<AuxValue>)
340 using unsigned_aux_type = std::make_unsigned_t<AuxValue>;
341 const auto mask =
static_cast<unsigned_aux_type
>(
auxspec.mask);
342 const auto current =
static_cast<unsigned_aux_type
>(val);
343 const auto encoded = (
static_cast<unsigned_aux_type
>(
value) <<
auxspec.shift) & mask;
344 val =
static_cast<AuxValue
>((current & ~mask) | encoded);
365 static_cast<unsigned long long>(
value)
371 template<
typename...
Args>
375 using T = std::decay_t<
decltype(v)>;
377 if constexpr (std::is_convertible_v<T, Value>) {
379 static_cast<Value>(v));
382 throw std::invalid_argument(
383 "Variant alternative cannot be converted "
384 "to BitField value type");
392 template<
typename...
Args>
395 [
this](
const auto& v) -> std::pair<std::int64_t,std::pair<bool,bool>> {
396 using T = std::decay_t<
decltype(v)>;
398 if constexpr (std::is_convertible_v<T, Value>) {
403 throw std::invalid_argument(
404 "Variant alternative cannot be converted "
405 "to BitField value type");
415 if constexpr (Signed) {
420 return static_cast<std::int64_t
>(
value);
452 if constexpr (std::is_arithmetic_v<Value> && !std::is_same_v<Value, bool>) {
465 template<std::
size_t N>
467 static_assert(Hi < N,
"BitField extends beyond the specification width");
471 for (
unsigned i = 0; i <
width; ++i)
472 result[i] = packed[Lo + i];
481 template<std::
size_t N>
486 template<std::
size_t N>
495 template<std::
size_t N>
497 std::bitset <N> &result,
501 "BitField extends beyond the specification width");
505 for (
unsigned i = 0; i <
width; ++i)
506 result[Lo + i] = field_bits[i];
525 template<
unsigned Lo,
unsigned Hi,
typename AuxValue,
typename Value = AuxValue>
528 template<
unsigned Lo,
unsigned Hi,
typename AuxValue,
typename Value = AuxValue>
532 template<
typename Field>
547 auto value(
bool truncate=
false)
const {
565 template <
typename T>
566 requires (std::is_integral_v<T> && !std::is_same_v<std::remove_cvref_t<T>,
bool> && !std::is_integral_v<typename Field::value_type>)
595 template<std::
size_t N>
596 auto extract(
const std::bitset <N> &packed)
const {
597 return m_field.extract(packed);
604 template<std::
size_t N>
606 return m_field.decodeFrom(packed);
636 template<
typename Derived, std::
size_t N,
typename Base = NoBase>
639 static constexpr std::size_t
width = N;
646 template<std::
size_t I>
static constexpr decltype(
auto)
field() {
647 return *std::get<I>(Derived::allFields());
651 static constexpr std::size_t
654 return std::tuple_size_v < std::remove_cvref_t <
decltype(Derived::allFields()) >> ;
659 std::apply([&](
const auto *...
field) { (func(*
field), ...); }, Derived::allFields());
663 static constexpr std::string
json() {
665 j[
"data_width"] =
width;
666 j[
"fields"] = nlohmann::json::array();
669 f[
"name"] =
field.name;
670 f[
"description"] =
field.description;
671 f[
"start"] =
field.lo;
672 f[
"width"] =
field.width;
673 j[
"fields"].push_back(f);
681 template<
typename... Fields>
683 return std::tuple{&fields...};
689 return std::tuple_cat(
700 template<
typename Fields>
705 [&](
const auto *...
field) {
706 (
field->pack(result, obj), ...);
728 []<
typename... FieldPtrs>(FieldPtrs...
field) {
729 return validateFieldList<
730 std::remove_cvref_t<decltype(*field)>...
741 template<
typename First,
typename... Rest>
744 if constexpr (
sizeof...(Rest) == 0)
757 template<
typename Field>
759 return Field::lo <= Field::hi && Field::hi < N;
766 template<
typename A,
typename B>
768 if (A::lo <= B::hi && B::lo <= A::hi) {
781#define FE_1(m, a) m(a)
782#define FE_2(m, a, ...) m(a) FE_1(m, __VA_ARGS__)
783#define FE_3(m, a, ...) m(a) FE_2(m, __VA_ARGS__)
784#define FE_4(m, a, ...) m(a) FE_3(m, __VA_ARGS__)
785#define FE_5(m, a, ...) m(a) FE_4(m, __VA_ARGS__)
786#define FE_6(m, a, ...) m(a) FE_5(m, __VA_ARGS__)
787#define FE_7(m, a, ...) m(a) FE_6(m, __VA_ARGS__)
788#define FE_8(m, a, ...) m(a) FE_7(m, __VA_ARGS__)
789#define FE_9(m, a, ...) m(a) FE_8(m, __VA_ARGS__)
790#define FE_10(m, a, ...) m(a) FE_9(m, __VA_ARGS__)
791#define FE_11(m, a, ...) m(a) FE_10(m, __VA_ARGS__)
792#define FE_12(m, a, ...) m(a) FE_11(m, __VA_ARGS__)
793#define FE_13(m, a, ...) m(a) FE_12(m, __VA_ARGS__)
794#define FE_14(m, a, ...) m(a) FE_13(m, __VA_ARGS__)
795#define FE_15(m, a, ...) m(a) FE_14(m, __VA_ARGS__)
796#define FE_16(m, a, ...) m(a) FE_15(m, __VA_ARGS__)
797#define FE_17(m, a, ...) m(a) FE_16(m, __VA_ARGS__)
798#define FE_18(m, a, ...) m(a) FE_17(m, __VA_ARGS__)
799#define FE_19(m, a, ...) m(a) FE_18(m, __VA_ARGS__)
800#define FE_20(m, a, ...) m(a) FE_19(m, __VA_ARGS__)
802#define GET_FE(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10, \
803 _11,_12,_13,_14,_15,_16,_17,_18,_19,_20,NAME,...) NAME
805#define FOR_EACH(m, ...) \
806 GET_FE(__VA_ARGS__, \
807 FE_20, FE_19, FE_18, FE_17, \
808 FE_16, FE_15, FE_14, FE_13, \
809 FE_12, FE_11, FE_10, FE_9, \
810 FE_8, FE_7, FE_6, FE_5, \
811 FE_4, FE_3, FE_2, FE_1)(m, __VA_ARGS__)
813#define FIELD_PTR(name) \
814 static inline constexpr auto name##_ptr = &name;
816#define FIELD_PTR_VALUE(name) name##_ptr,
820#define FIELD_ACCESSOR(name) \
821 BitFieldAccessor<std::remove_cvref_t<decltype(*name##_ptr)>> name{*name##_ptr,m_obj};
823#define DECLARE_FIELDS(...) \
825 FOR_EACH(FIELD_PTR, __VA_ARGS__) \
827 static inline constexpr auto fields = \
828 std::tuple{ FOR_EACH(FIELD_PTR_VALUE, __VA_ARGS__) }; \
830 static_assert(validateFields(),"Invalid spec: overlapping fields or fields beyond spec"); \
835 explicit ObjectAcc(const SG::AuxElement& obj) \
839 const SG::AuxElement& m_obj; \
842 FOR_EACH(FIELD_ACCESSOR, __VA_ARGS__) \
Base class for elements of a container that can have aux data.
static const Attributes_t empty
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
bits_type encode(Value value) const
Value value(const SG::AuxElement &obj, bool truncate) const
static constexpr auto minCode
std::function< std::pair< Value, Value >(bits_type)> decoder_type
static constexpr unsigned width
static std::int64_t code(bits_type bits)
std::string_view description
std::pair< Value, Value > range(bits_type bits) const
std::pair< std::int64_t, std::pair< bool, bool > > encodeAndCheckBoundary(const std::variant< Args... > &value) const
std::function< bits_type(Value)> encoder_type
static constexpr unsigned lo
void decodeAndAssignFrom(const std::bitset< N > &packed, SG::AuxElement &obj) const
bits_type bits(const SG::AuxElement &obj) const
SG::Accessor< AuxValue > m_wacc
Value value(const SG::AuxElement &obj) const
bits_type encode(const std::variant< Args... > &value) const
Value decode(bits_type bits) const
constexpr BitField(const Params &p)
bits_type extract(const std::bitset< N > &packed) const
SG::ConstAccessor< AuxValue > m_acc
Bitset< width, Clamped, Signed > 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, double centre=0.5, bool lower_inc=true)
static constexpr auto maxCode
static constexpr unsigned hi
AuxValue & store(SG::AuxElement &obj, Value value) const
void pack(std::bitset< N > &result, const SG::AuxElement &obj) const
Value decodeFrom(const std::bitset< N > &packed) const
static constexpr std::size_t width
static constexpr void forEachField(auto &&func)
static constexpr std::string json()
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()
Custom Bitset class that can handle clamping of values.
static constexpr auto min
constexpr Bitset(const std::bitset< M > &other)
constexpr Bitset(const Bitset &)=default
constexpr Bitset(Base &&bits)
static constexpr std::int64_t signedMin()
constexpr Bitset(unsigned long long value)
constexpr Bitset(Bitset &&)=default
static constexpr std::int64_t signedMax()
static constexpr auto max
static constexpr std::uint64_t unsignedMax()
constexpr Bitset(T value)
static constexpr std::uint64_t convert(T value)
constexpr Bitset(const Base &bits)
int count(std::string s, const std::string ®x)
count how many occurances of a regx are in a string
AlgTool to read in LArStripNeighborhoods, and run the BDT Algorithm.
BitField< Lo, Hi, AuxValue, Value, true > SignedBitField
BitField< Lo, Hi, AuxValue, Value, false, false > UnclampedBitField
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()