ATLAS Offline Software
Loading...
Searching...
No Matches
BitSpec.h
Go to the documentation of this file.
1/*
2 * Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3 */
4
5#ifndef GLOBALSIM_BITSPEC_H
6#define GLOBALSIM_BITSPEC_H
7
8#include <bit>
9#include <bitset>
10#include <cstddef>
11#include <cstdint>
12#include <stdexcept>
13#include <string>
14#include <string_view>
15#include <tuple>
16#include <type_traits>
17#include <utility>
18#include <algorithm>
19
20#include <nlohmann/json.hpp>
21
23
24namespace GlobalSim {
25
26// ============================================================================
27// BitField
28//
29// Lo and Hi are inclusive bit positions.
30//
31// BitField<0, 10, int>
32//
33// represents an 11-bit field occupying bits [10:0].
34//
35// The bit representation is:
36//
37// std::bitset<11>
38//
39// ============================================================================
40
41 struct AuxSpec {
42 std::string_view name{};
43 std::uint64_t mask{};
44 std::size_t shift{};
45 bool has_mask{};
46
47 static constexpr std::size_t parseNumber(std::string_view str,std::size_t& pos,std::size_t end) {
48 std::size_t value{};
49 const auto [ptr, ec] = std::from_chars(
50 str.data() + pos,
51 str.data() + end,
52 value
53 );
54
55 if (ec != std::errc{})
56 throw std::invalid_argument("Expected number");
57
58 pos = ptr - str.data();
59 return value;
60 }
61
62 static constexpr AuxSpec parse(std::string_view spec) {
63 const auto open = spec.find('[');
64
65 // No mask specification.
66 if (open == std::string_view::npos) {
67 return {
68 spec,
69 std::numeric_limits<std::uint64_t>::max(),
70 0,
71 false
72 };
73 }
74
75 // Expected: name[lo:hi] or name[bit]
76 const auto colon = spec.find(':', open + 1);
77 const auto close = spec.find(']', open + 1);
78
79 if (close == std::string_view::npos ||close != spec.size() - 1) {
80 throw std::invalid_argument("Invalid AuxSpec");
81 }
82
83 std::size_t pos = open + 1;
84 const std::size_t lo = parseNumber(spec, pos, colon == std::string_view::npos ? close : colon);
85
86 std::size_t hi = lo;
87
88 if (colon != std::string_view::npos) {
89 // Range: [lo:hi]
90 if (colon == open + 1 || colon + 1 == close) {
91 throw std::invalid_argument("Invalid AuxSpec range");
92 }
93 pos = colon + 1;
94 hi = parseNumber(spec, pos, close);
95 }
96
97 if (pos != close || lo > hi || hi >= 64)
98 throw std::invalid_argument("Invalid bit range");
99
100 const std::size_t width = hi - lo + 1;
101
102 const std::uint64_t mask =
103 width == 64
104 ? std::numeric_limits<std::uint64_t>::max()
105 : ((std::uint64_t{1} << width) - 1) << lo;
106
107 return {
108 spec.substr(0, open),
109 mask,
110 lo,
111 true
112 };
113 }
114
115 };
116
117
124 template <std::size_t N, bool Clamp = false, bool Signed = false>
125 class Bitset : public std::bitset<N> {
126 using Base = std::bitset<N>;
127
128 static constexpr std::uint64_t unsignedMax() {
129 if constexpr (N >= 64) return std::numeric_limits<std::uint64_t>::max();
130 else return (std::uint64_t{1} << N) - 1;
131 }
132
133 static constexpr std::int64_t signedMin() {
134 if constexpr (N >= 64) return std::numeric_limits<std::int64_t>::min();
135 else return -(std::int64_t{1} << (N - 1));
136 }
137
138 static constexpr std::int64_t signedMax() {
139 if constexpr (N == 64) return std::numeric_limits<std::int64_t>::max();
140 else return (std::int64_t{1} << (N - 1)) - 1;
141 }
142
143 template <typename T>
144 static constexpr std::uint64_t convert(T value) {
145 static_assert(std::is_integral_v<T>);
146
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>) {
151 return std::clamp(static_cast<std::int64_t>(value),signedMin(),signedMax());
152 } else {
153 return std::clamp(static_cast<std::uint64_t>(value),std::uint64_t{0},static_cast<std::uint64_t>(signedMax()));
154 }
155 } else {
156 if constexpr (std::is_signed_v<T>) {
157 if (value < 0)
158 return 0;
159 }
160 return std::clamp(static_cast<std::uint64_t>(value),std::uint64_t{0},unsignedMax());
161 }
162 }
163
164 public:
165 // convenience max and min definition aliases
166 static constexpr auto max = [] {
167 if constexpr (Signed) return signedMax();
168 else return unsignedMax();
169 }();
170 static constexpr auto min = [] {
171 if constexpr (Signed) return signedMin();
172 else return std::uint64_t{0};
173 }();
174
175 using Base::Base;
176 constexpr Bitset(unsigned long long value) : Base(convert(value)) {} // Hides the inherited bitset(unsigned long long)
177
178 // Copy and move constructors from another Bitset
179 constexpr Bitset(const Bitset&) = default;
180 constexpr Bitset(Bitset&&) = default;
181
182 // Construct from the underlying std::bitset
183 constexpr Bitset(const Base& bits) : Base(bits) {}
184 constexpr Bitset(Base&& bits) : Base(std::move(bits)) {}
185
186 // allow construction from other size bitsets
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]);
192 }
193 }
194
195 template <typename T>
196 requires std::is_integral_v<T>
197 constexpr Bitset(T value)
198 : Base(convert(value)) {}
199 };
200
201
202 //struct NoMask {};
203
204 template<unsigned Lo, unsigned Hi, typename AuxValue, typename Value=AuxValue, bool Signed=false, bool Clamped=true/*, auto Mask = NoMask{}*/>
205 class BitField {
206 public:
207 static_assert(Hi >= Lo,"BitField: Hi must be >= Lo");
208 static_assert(!Signed || (Hi-Lo)<64,"Signed BitFields have max width of 64");
209 // next line makes it required that AuxValue type is big enough for this bitfield
210 static_assert(sizeof(AuxValue) * CHAR_BIT >= Hi - Lo + 1,"AuxType is too small for BitField");
211 public:
212 static constexpr unsigned lo = Lo;
213 static constexpr unsigned hi = Hi;
214 static constexpr unsigned width = Hi - Lo + 1;
215 // leaving this commented as the alternative way to do constexpr masking
216 /*static constexpr auto mask = Mask;
217 static constexpr bool has_mask = !std::is_same_v<decltype(Mask), NoMask>;
218 static constexpr std::size_t shift = [] {
219 if constexpr (has_mask)
220 return std::countr_zero(static_cast<uint64_t>(Mask));
221 else
222 return std::size_t{0};
223 }();*/
224
227
228 static constexpr auto maxCode = bits_type::max;
229 static constexpr auto minCode = bits_type::min;
230
231 using encoder_type = std::function<bits_type(Value)>;
232 using decoder_type = std::function<std::pair<Value,Value>(bits_type)>; // pair is {lower,upper} boundaries
233
234 constexpr BitField(
235 std::string_view name_,
236 std::string_view auxvar,
237 std::string_view description_,
238 encoder_type encoder = nullptr,
239 decoder_type decoder = nullptr,
240 Value scale = 0, Value offset = 0, double centre = 0.5, bool lower_inc = true)
241 : auxspec(AuxSpec::parse(auxvar)),
242 name(name_),
243 description(description_),
244 m_encoder(encoder),
245 m_decoder(decoder),
247 if(!m_encoder && !m_decoder && scale) {
248 if constexpr (Signed) {
249 // need to cast to signed int, as casting a negative float to unsigned int is undefined behaviour
250 // was previously then explicitly casting to uint64_t when bits_type was a std::bitset
251 // which worked. But now using clampable bitsets, the behaviour isn't quite the same
252 if(lower_inc) {
253 m_encoder = [scale, offset](Value v) {
254 return bits_type{static_cast<int64_t>(std::floor((v - offset) / scale))};
255 };
256 } else {
257 m_encoder = [scale, offset](Value v) {
258 return bits_type{static_cast<int64_t>((std::ceil((v - offset) / scale) - 1))};
259 };
260 }
261 } else {
262 m_encoder = [scale, offset, lower_inc](Value v) {
263 return bits_type{static_cast<uint64_t>(lower_inc ? std::floor((v - offset) / scale) : (
264 std::ceil((v - offset) / scale) - 1))};
265 };
266 }
267 m_decoder = [scale,offset](bits_type bits) -> std::pair<Value,Value> {
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) };
271 };
272 }
273 if constexpr (std::is_arithmetic_v<Value> && !std::is_same_v<Value, bool>)
274 {
275 m_valueoffset = centre;
276 }
277 }
278
279 // Named-parameter aggregate for constructing a BitField.
280 // Designated initializers must follow declaration order, but any
281 // subset may be skipped -- skipped members just take their default.
282 struct Params {
283 std::string_view name;
284 std::string_view auxvar{}; // empty => defaults to `name`
285 std::string_view description{};
290 double centre{0.5};
291 bool lower_incl{true};
292 };
293
294 constexpr BitField(const Params& p) : BitField(p.name,p.auxvar.empty()?p.name:p.auxvar,p.description,p.encoder,p.decoder,p.scale,p.offset,p.centre,p.lower_incl) { }
295
296 // ------------------------------------------------------------------------
297 // Metadata
298 // ------------------------------------------------------------------------
299
300 /*constexpr std::string_view name() const { return m_name; }
301
302 constexpr std::string_view description() const { return m_description; }*/
303
304 // ------------------------------------------------------------------------
305 // Get the value directly from an AOD object.
306 // ------------------------------------------------------------------------
307
308 Value value(const SG::AuxElement &obj) const {
309
310 if constexpr (std::is_integral_v<AuxValue>)
311 { // ensures have bitwise operators
312
313 /*if constexpr(has_mask) {
314 return (m_acc(obj) & Mask) >> shift;*/
315 if (auxspec.has_mask) {
316 return decode((m_acc(obj) & auxspec.mask) >> auxspec.shift);
317 }
318 }
319
320 return m_acc(obj);
321
322 }
323
324 // if truncate = true, then will do an encode-decode to truncate the stored value
325 Value value(const SG::AuxElement& obj, bool truncate) const {
326 if(!truncate) return value(obj);
327 return decode(encode(value(obj)));
328 }
329
330 AuxValue& store(SG::AuxElement &obj, Value value) const {
331 if constexpr (std::is_integral_v<AuxValue>)
332 { // ensures have bitwise operators, has_mask is not constexpr so must hide this from invalid AuxValue types
333 // leaving this commented as may revert to constexpr again at some point
334 // if constexpr (has_mask) {
335 // auto& val = m_wacc(obj);
336 // val = (val & ~Mask) | ((value << shift) & Mask);
337 if (auxspec.has_mask) {
338 auto &val = m_wacc(obj);
339 //avoid unintended sign extension, make everything unsigned
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);
345 return val;
346 }
347 }
348 return (m_wacc(obj) = value);
349
350 }
351
352 // ------------------------------------------------------------------------
353 // Encode a Value into this field's bit representation.
354 // ------------------------------------------------------------------------
355
357 if (m_encoder)
358 return m_encoder(value);
359
360 // Default behaviour: integral conversion.
361
362 // should we check for out-of-range given size of bitset?
363
364 return bits_type{
365 static_cast<unsigned long long>(value)
366 };
367 }
368
369
370 // version of encode that accepts a variant
371 template<typename... Args>
372 bits_type encode(const std::variant<Args...>& value) const {
373 return std::visit(
374 [this](const auto& v) -> bits_type {
375 using T = std::decay_t<decltype(v)>;
376
377 if constexpr (std::is_convertible_v<T, Value>) {
378 return encode(
379 static_cast<Value>(v));
380 }
381 else {
382 throw std::invalid_argument(
383 "Variant alternative cannot be converted "
384 "to BitField value type");
385 }
386 },
387 value);
388 }
389
390 // version of encode that returns actual code and
391 // also check if value being encoded lies on either of lower or upper boundary
392 template<typename... Args>
393 std::pair<std::int64_t,std::pair<bool,bool>> encodeAndCheckBoundary(const std::variant<Args...>& value) const {
394 return std::visit(
395 [this](const auto& v) -> std::pair<std::int64_t,std::pair<bool,bool>> {
396 using T = std::decay_t<decltype(v)>;
397
398 if constexpr (std::is_convertible_v<T, Value>) {
399 auto bits = encode(static_cast<Value>(v));
400 auto r = range(bits);
401 return {code(bits),{v==r.first,v==r.second}};
402 } else {
403 throw std::invalid_argument(
404 "Variant alternative cannot be converted "
405 "to BitField value type");
406 }
407 },
408 value);
409 }
410
411 // get the "code" of the encoding, i.e. converts the bitset to int64_t
412 // respecting if this BitField is signed or not
413 static std::int64_t code(bits_type bits) {
414 auto value = bits.to_ullong();
415 if constexpr (Signed) {
416 if (bits[width - 1]) {
417 value -= (std::uint64_t{1} << width);
418 }
419 }
420 return static_cast<std::int64_t>(value);
421 }
422
423 // ------------------------------------------------------------------------
424 // Get and encode the value from an AOD object.
425 // ------------------------------------------------------------------------
426
427 bits_type bits(const SG::AuxElement &obj) const {
428 return encode(value(obj));
429 }
430
431 // Bucket bounds [lower, upper] for the code represented by `bits`,
432 // as produced by this field's decoder (custom or built-in linear).
433 // Falls back to a degenerate {v, v} when no encoding was configured
434 // at all (plain integral pass-through field).
435 std::pair<Value, Value> range(bits_type bits) const {
436 if (m_decoder)
437 return m_decoder(bits);
438 const Value v = static_cast<Value>(code(bits));
439 return { v, v };
440 }
441
442 // ------------------------------------------------------------------------
443 // Decode this field's bits into a Value ... uses the midpoint of the range
444 // ------------------------------------------------------------------------
445
447 const auto [lo,hi] = range(bits);
448 if (lo == hi) {
449 return lo;
450 }
451
452 if constexpr (std::is_arithmetic_v<Value> && !std::is_same_v<Value, bool>) {
453 return (lo+m_valueoffset*(hi-lo));
454 } else {
455 // No well-defined midpoint for this Value type -- fall back to
456 // the lower bound rather than attempting arithmetic on it.
457 return lo;
458 }
459 }
460
461 // ------------------------------------------------------------------------
462 // Extract this field from a complete specification bitset.
463 // ------------------------------------------------------------------------
464
465 template<std::size_t N>
466 bits_type extract(const std::bitset <N> &packed) const {
467 static_assert(Hi < N, "BitField extends beyond the specification width");
468
469 bits_type result;
470
471 for (unsigned i = 0; i < width; ++i)
472 result[i] = packed[Lo + i];
473
474 return result;
475 }
476
477 // ------------------------------------------------------------------------
478 // Extract and decode this field from a complete specification bitset.
479 // ------------------------------------------------------------------------
480
481 template<std::size_t N>
482 Value decodeFrom(const std::bitset <N> &packed) const {
483 return decode(extract(packed));
484 }
485
486 template<std::size_t N>
487 void decodeAndAssignFrom(const std::bitset <N> &packed, SG::AuxElement &obj) const {
488 store( obj, decode(extract(packed)));
489 }
490
491 // ------------------------------------------------------------------------
492 // Pack this field from an AOD object into a complete bitset.
493 // ------------------------------------------------------------------------
494
495 template<std::size_t N>
496 void pack(
497 std::bitset <N> &result,
498 const SG::AuxElement &obj) const {
499 static_assert(
500 Hi < N,
501 "BitField extends beyond the specification width");
502
503 const bits_type field_bits = bits(obj);
504
505 for (unsigned i = 0; i < width; ++i)
506 result[Lo + i] = field_bits[i];
507 }
508
510 std::string_view name;
511 std::string_view description;
512 private:
513
514
515
518 Value m_valueoffset{}; // used by decode to return a value in the encoder range
519
520 SG::ConstAccessor <AuxValue> m_acc;
521 SG::Accessor <AuxValue> m_wacc;
522 };
523
524 // alias for setting the Signed bool
525 template<unsigned Lo, unsigned Hi, typename AuxValue, typename Value = AuxValue>
527 // alias for unsetting the Clamped bool
528 template<unsigned Lo, unsigned Hi, typename AuxValue, typename Value = AuxValue>
530
531
532 template<typename Field>
533 class BitFieldAccessor : public Field {
534 public:
535 BitFieldAccessor(const Field &field, const SG::AuxElement &obj) : Field(field), m_field(field), m_obj(obj) {
536 }
537
538 // this just preserves old syntax behaviour of obj.field().value() and obj.field() = ...
540 return *this;
541 }
542
543 // ------------------------------------------------------------------------
544 // Value stored in the AOD object.
545 // ------------------------------------------------------------------------
546
547 auto value(bool truncate=false) const {
548 if(truncate) return m_field.value(m_obj,true);
549 return m_field.value(m_obj);
550 }
551
552
553 BitFieldAccessor &operator=(const Field::value_type &value) {
554 m_field.store(const_cast<SG::AuxElement &>(m_obj),value);
555 return *this;
556 }
557
558 BitFieldAccessor &operator=(const Field::bits_type &bits) {
559 // Decode bits and set the value in m_obj
560 // ...
561 return operator=(m_field.decode(bits));
562 }
563
564 // Integer -> raw bits, only for non-integer and non-bool Value types
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>)
567 BitFieldAccessor& operator=(T code)
568 {
569 return operator=(m_field.decode(code));
570 }
571
572 // ------------------------------------------------------------------------
573 // Encoded representation of the AuxElement value.
574 // ------------------------------------------------------------------------
575
576 auto bits() const {
577 return m_field.bits(m_obj);
578 }
579
580
581 auto code() const {
582 return m_field.code(bits());
583 }
584
585 // ------------------------------------------------------------------------
586 // Metadata
587 // ------------------------------------------------------------------------
588 constexpr auto spec() const { return m_field; }
589
590
591 // ------------------------------------------------------------------------
592 // Extract this field from a complete packed representation.
593 // ------------------------------------------------------------------------
594
595 template<std::size_t N>
596 auto extract(const std::bitset <N> &packed) const {
597 return m_field.extract(packed);
598 }
599
600 // ------------------------------------------------------------------------
601 // Extract and decode this field from a complete packed representation.
602 // ------------------------------------------------------------------------
603
604 template<std::size_t N>
605 auto decodeFrom(const std::bitset <N> &packed) const {
606 return m_field.decodeFrom(packed);
607 }
608
609 private:
610 const Field &m_field;
612 };
613
614
615
616 struct NoBase {
617 public:
618 /*class ObjectAcc {
619 public:
620 ObjectAcc(const SG::AuxElement &) {}
621 }; -- commented out because only needed when we were making the ObjectAcc classes inherit*/
622 static constexpr auto allFields()
623 {
624 return std::tuple{};
625 }
626 };
627// ============================================================================
628// BitSpec<N>
629//
630// Common base class for concrete specifications.
631//
632// N = total width of the packed representation.
633//
634// ============================================================================
635
636 template<typename Derived, std::size_t N, typename Base = NoBase>
637 class BitSpec : public Base {
638 public:
639 static constexpr std::size_t width = N;
641 template<typename> friend class Object; // lets Object class access allFields() protected method
642 using BaseSpec = Base;
643
644
645 // example use: MySpec::field<0>().name()
646 template<std::size_t I> static constexpr decltype(auto) field() {
647 return *std::get<I>(Derived::allFields());
648 }
649
650 // example use: MySpec::numFields()
651 static constexpr std::size_t
652
654 return std::tuple_size_v < std::remove_cvref_t < decltype(Derived::allFields()) >> ;
655 }
656
657 // example use: MySpec::forEachField( [](const auto& field) { std::cout << field.name() << std::endl; } );
658 static constexpr void forEachField(auto &&func) {
659 std::apply([&](const auto *... field) { (func(*field), ...); }, Derived::allFields());
660 }
661
662 // example use: MySpec::json()
663 static constexpr std::string json() {
664 nlohmann::json j;
665 j["data_width"] = width;
666 j["fields"] = nlohmann::json::array();
667 forEachField([&](const auto &field) {
668 nlohmann::json f;
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);
674 });
675 return j.dump(4);
676 }
677
678 protected:
679
680 // this method is used in the DECLARE_FIELDS macro to create the tuple .. needed to inject the & symbol
681 template<typename... Fields>
682 static constexpr auto makeFields(Fields &... fields) {
683 return std::tuple{&fields...};
684 }
685
686
687 static constexpr auto allFields()
688 {
689 return std::tuple_cat(
690 Base::allFields(),
691 Derived::fields
692 );
693 }
694
695
696 // ------------------------------------------------------------------------
697 // Pack all fields in a field tuple.
698 // ------------------------------------------------------------------------
699 public:
700 template<typename Fields>
701 static bitset_type packFields(const Fields &fields, const SG::AuxElement &obj) {
702 bitset_type result;
703
704 std::apply(
705 [&](const auto *... field) {
706 (field->pack(result, obj), ...);
707 },
708 fields);
709
710 return result;
711 }
712
713 protected:
714 // ------------------------------------------------------------------------
715 // Validate all fields.
716 //
717 // Individual field ranges are checked at compile time via:
718 //
719 // static_assert(Hi < N)
720 //
721 // Overlap between different fields is checked here.
722 // ------------------------------------------------------------------------
723
724
725 static consteval bool validateFields()
726 {
727 return std::apply(
728 []<typename... FieldPtrs>(FieldPtrs... field) {
729 return validateFieldList<
730 std::remove_cvref_t<decltype(*field)>...
731 >();
732 },
733 Derived::fields);
734 }
735
736 private:
737 // ------------------------------------------------------------------------
738 // Compare the first field against every subsequent field.
739 // ------------------------------------------------------------------------
740
741 template<typename First, typename... Rest>
742 static consteval bool validateFieldList()
743 {
744 if constexpr (sizeof...(Rest) == 0)
745 {
746 return validateField<First>();
747 }
748 else
749 {
750 return validateField<First>() &&
751 (validateField<Rest>() && ...) &&
752 ((!checkOverlap<First, Rest>()) && ...) &&
753 validateFieldList<Rest...>();
754 }
755 }
756
757 template<typename Field>
758 static consteval bool validateField() {
759 return Field::lo <= Field::hi && Field::hi < N;
760 }
761
762 // ------------------------------------------------------------------------
763 // Check two fields for overlap.
764 // ------------------------------------------------------------------------
765
766 template<typename A, typename B>
767 static consteval bool checkOverlap() {
768 if (A::lo <= B::hi && B::lo <= A::hi) {
769 return true;
770 }
771 return false;
772 }
773
774 };
775
776}
777
778// MACROS FOR DEFINING FIELDS IN BITSPECS:
779
780
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__)
801
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
804
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__)
812
813#define FIELD_PTR(name) \
814 static inline constexpr auto name##_ptr = &name;
815
816#define FIELD_PTR_VALUE(name) name##_ptr,
817
818
819
820#define FIELD_ACCESSOR(name) \
821 BitFieldAccessor<std::remove_cvref_t<decltype(*name##_ptr)>> name{*name##_ptr,m_obj};
822
823#define DECLARE_FIELDS(...) \
824 protected: \
825 FOR_EACH(FIELD_PTR, __VA_ARGS__) \
826 public: \
827 static inline constexpr auto fields = \
828 std::tuple{ FOR_EACH(FIELD_PTR_VALUE, __VA_ARGS__) }; \
829 \
830 static_assert(validateFields(),"Invalid spec: overlapping fields or fields beyond spec"); \
831 \
832 class ObjectAcc/* : public BaseSpec::ObjectAcc*/ \
833 { \
834 public: \
835 explicit ObjectAcc(const SG::AuxElement& obj) \
836 : /*BaseSpec::ObjectAcc(obj),*/ m_obj(obj) \
837 {} \
838 protected: \
839 const SG::AuxElement& m_obj; \
840 public: \
841 \
842 FOR_EACH(FIELD_ACCESSOR, __VA_ARGS__) \
843 \
844 }
845
846
848
849#endif
Base class for elements of a container that can have aux data.
const double width
static const Attributes_t empty
doing TRTHTH Hypo selection
BitFieldAccessor(const Field &field, const SG::AuxElement &obj)
Definition BitSpec.h:535
auto decodeFrom(const std::bitset< N > &packed) const
Definition BitSpec.h:605
BitFieldAccessor & operator=(const Field::value_type &value)
Definition BitSpec.h:553
BitFieldAccessor & operator()()
Definition BitSpec.h:539
const SG::AuxElement & m_obj
Definition BitSpec.h:611
BitFieldAccessor & operator=(const Field::bits_type &bits)
Definition BitSpec.h:558
constexpr auto spec() const
Definition BitSpec.h:588
auto value(bool truncate=false) const
Definition BitSpec.h:547
auto extract(const std::bitset< N > &packed) const
Definition BitSpec.h:596
bits_type encode(Value value) const
Definition BitSpec.h:356
Value value(const SG::AuxElement &obj, bool truncate) const
Definition BitSpec.h:325
std::function< std::pair< Value, Value >(bits_type)> decoder_type
Definition BitSpec.h:232
static std::int64_t code(bits_type bits)
Definition BitSpec.h:413
std::pair< Value, Value > range(bits_type bits) const
Definition BitSpec.h:435
std::pair< std::int64_t, std::pair< bool, bool > > encodeAndCheckBoundary(const std::variant< Args... > &value) const
Definition BitSpec.h:393
std::function< bits_type(Value)> encoder_type
Definition BitSpec.h:231
void decodeAndAssignFrom(const std::bitset< N > &packed, SG::AuxElement &obj) const
Definition BitSpec.h:487
bits_type bits(const SG::AuxElement &obj) const
Definition BitSpec.h:427
Value value(const SG::AuxElement &obj) const
Definition BitSpec.h:308
bits_type encode(const std::variant< Args... > &value) const
Definition BitSpec.h:372
Value decode(bits_type bits) const
Definition BitSpec.h:446
constexpr BitField(const Params &p)
Definition BitSpec.h:294
bits_type extract(const std::bitset< N > &packed) const
Definition BitSpec.h:466
Bitset< width, Clamped, Signed > bits_type
Definition BitSpec.h:226
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)
Definition BitSpec.h:234
AuxValue & store(SG::AuxElement &obj, Value value) const
Definition BitSpec.h:330
void pack(std::bitset< N > &result, const SG::AuxElement &obj) const
Definition BitSpec.h:496
Value decodeFrom(const std::bitset< N > &packed) const
Definition BitSpec.h:482
static constexpr std::size_t width
Definition BitSpec.h:639
static constexpr void forEachField(auto &&func)
Definition BitSpec.h:658
static constexpr std::string json()
Definition BitSpec.h:663
static constexpr decltype(auto) field()
Definition BitSpec.h:646
static consteval bool validateField()
Definition BitSpec.h:758
friend class Object
Definition BitSpec.h:641
static consteval bool checkOverlap()
Definition BitSpec.h:767
static consteval bool validateFieldList()
Definition BitSpec.h:742
static constexpr auto makeFields(Fields &... fields)
Definition BitSpec.h:682
static constexpr auto allFields()
Definition BitSpec.h:687
Bitset< N > bitset_type
Definition BitSpec.h:640
static consteval bool validateFields()
Definition BitSpec.h:725
static bitset_type packFields(const Fields &fields, const SG::AuxElement &obj)
Definition BitSpec.h:701
static constexpr std::size_t numFields()
Definition BitSpec.h:653
Custom Bitset class that can handle clamping of values.
Definition BitSpec.h:125
constexpr Bitset(const std::bitset< M > &other)
Definition BitSpec.h:188
constexpr Bitset(const Bitset &)=default
constexpr Bitset(Base &&bits)
Definition BitSpec.h:184
static constexpr std::int64_t signedMin()
Definition BitSpec.h:133
constexpr Bitset(unsigned long long value)
Definition BitSpec.h:176
constexpr Bitset(Bitset &&)=default
static constexpr std::int64_t signedMax()
Definition BitSpec.h:138
static constexpr std::uint64_t unsignedMax()
Definition BitSpec.h:128
constexpr Bitset(T value)
Definition BitSpec.h:197
std::bitset< N > Base
Definition BitSpec.h:126
static constexpr std::uint64_t convert(T value)
Definition BitSpec.h:144
constexpr Bitset(const Base &bits)
Definition BitSpec.h:183
tag-value pair class.
Definition Value.h:39
STL class.
STL class.
std::map< std::string, std::string, std::less<> > parse(const std::string &list)
int r
Definition globals.cxx:22
int count(std::string s, const std::string &regx)
count how many occurances of a regx are in a string
Definition hcg.cxx:148
AlgTool to read in LArStripNeighborhoods, and run the BDT Algorithm.
Definition BitSpec.h:24
BitField< Lo, Hi, AuxValue, Value, true > SignedBitField
Definition BitSpec.h:526
BitField< Lo, Hi, AuxValue, Value, false, false > UnclampedBitField
Definition BitSpec.h:529
AuxElement(SG::AuxVectorData *container, size_t index)
Base class for elements of a container that can have aux data.
STL namespace.
std::uint64_t mask
Definition BitSpec.h:43
std::size_t shift
Definition BitSpec.h:44
static constexpr std::size_t parseNumber(std::string_view str, std::size_t &pos, std::size_t end)
Definition BitSpec.h:47
static constexpr AuxSpec parse(std::string_view spec)
Definition BitSpec.h:62
std::string_view name
Definition BitSpec.h:42
std::string_view description
Definition BitSpec.h:285
std::string_view name
Definition BitSpec.h:283
std::string_view auxvar
Definition BitSpec.h:284
static constexpr auto allFields()
Definition BitSpec.h:622