File indexing completed on 2025-01-18 09:11:11
0001
0002
0003
0004
0005
0006
0007
0008
0009 #pragma once
0010
0011 #include <array>
0012 #include <cassert>
0013 #include <climits>
0014 #include <ostream>
0015 #include <type_traits>
0016 #include <utility>
0017
0018 namespace Acts {
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028 template <typename T, std::size_t... BitsPerLevel>
0029 class MultiIndex {
0030 public:
0031 static_assert(std::is_integral_v<T> && std::is_unsigned_v<T>,
0032 "The underlying storage type must be an unsigned integer");
0033 static_assert(0 < sizeof...(BitsPerLevel),
0034 "At least one level must be defined");
0035 static_assert((sizeof(T) * CHAR_BIT) == (... + BitsPerLevel),
0036 "The sum of bits per level must match the underlying storage");
0037
0038
0039 using Value = T;
0040 enum : std::size_t {
0041 NumLevels = sizeof...(BitsPerLevel),
0042 };
0043
0044
0045 static constexpr MultiIndex Zeros() { return MultiIndex(0u); }
0046
0047
0048
0049
0050
0051
0052
0053 template <typename... Us>
0054 static constexpr MultiIndex Encode(Us&&... us) {
0055 static_assert(sizeof...(Us) <= NumLevels,
0056 "Can only encode as many levels as in the MultiIndex");
0057
0058 MultiIndex index(0u);
0059 std::size_t lvl = 0;
0060 for (Value val : std::array<Value, sizeof...(Us)>{us...}) {
0061 index.set(lvl++, val);
0062 }
0063 return index;
0064 }
0065
0066
0067 constexpr MultiIndex(Value encoded) : m_value(encoded) {}
0068
0069 MultiIndex() = default;
0070 MultiIndex(const MultiIndex&) = default;
0071 MultiIndex(MultiIndex&) = default;
0072 MultiIndex& operator=(const MultiIndex&) = default;
0073 MultiIndex& operator=(MultiIndex&&) noexcept = default;
0074
0075 constexpr MultiIndex& operator=(Value encoded) {
0076 m_value = encoded;
0077 return *this;
0078 }
0079
0080
0081 constexpr Value value() const { return m_value; }
0082
0083 constexpr Value level(std::size_t lvl) const {
0084 assert((lvl < NumLevels) && "Index level outside allowed range");
0085 return (m_value >> shift(lvl)) & mask(lvl);
0086 }
0087
0088 constexpr MultiIndex& set(std::size_t lvl, Value val) {
0089 assert((lvl < NumLevels) && "Index level outside allowed range");
0090
0091 Value shiftedMask = (mask(lvl) << shift(lvl));
0092
0093 Value shiftedValue = (val << shift(lvl));
0094
0095 m_value = (m_value & ~shiftedMask) | (shiftedValue & shiftedMask);
0096 return *this;
0097 }
0098
0099
0100 constexpr MultiIndex makeNextSibling(std::size_t lvl) const {
0101 assert((lvl < NumLevels) && "Index level outside allowed range");
0102
0103 Value upper = (m_value >> shift(lvl));
0104
0105 return ((upper + 1u) << shift(lvl));
0106 }
0107
0108 constexpr MultiIndex makeLastDescendant(std::size_t lvl) const {
0109 assert((lvl < NumLevels) && "Index level outside allowed range");
0110
0111 Value maskLower = (Value{1u} << shift(lvl)) - 1u;
0112
0113 return (m_value & ~maskLower) | maskLower;
0114 }
0115
0116
0117 static constexpr std::size_t bits(std::size_t lvl) {
0118 assert((lvl < NumLevels) && "Index level outside allowed range");
0119 return s_bits[lvl];
0120 }
0121
0122 private:
0123
0124 static constexpr std::array<std::size_t, NumLevels> s_bits{BitsPerLevel...};
0125 static constexpr std::size_t shift(std::size_t lvl) {
0126 std::size_t s = 0u;
0127
0128 for (std::size_t i = (lvl + 1); i < s_bits.size(); ++i) {
0129 s += s_bits[i];
0130 }
0131 return s;
0132 }
0133 static constexpr Value mask(std::size_t lvl) {
0134 return (Value{1u} << s_bits[lvl]) - 1u;
0135 }
0136
0137 Value m_value;
0138
0139 friend constexpr bool operator<(MultiIndex lhs, MultiIndex rhs) {
0140 return lhs.m_value < rhs.m_value;
0141 }
0142
0143 friend constexpr bool operator==(MultiIndex lhs, MultiIndex rhs) {
0144 return lhs.m_value == rhs.m_value;
0145 }
0146
0147 friend inline std::ostream& operator<<(std::ostream& os, MultiIndex idx) {
0148
0149 os << idx.level(0u);
0150 for (std::size_t lvl = 1; lvl < NumLevels; ++lvl) {
0151 os << '|' << idx.level(lvl);
0152 }
0153 return os;
0154 }
0155 };
0156
0157 }
0158
0159
0160 namespace std {
0161 template <typename Storage, std::size_t... BitsPerLevel>
0162 struct hash<Acts::MultiIndex<Storage, BitsPerLevel...>> {
0163 auto operator()(
0164 Acts::MultiIndex<Storage, BitsPerLevel...> idx) const noexcept {
0165 return std::hash<Storage>()(idx.value());
0166 }
0167 };
0168 }