ATLAS Offline Software
Loading...
Searching...
No Matches
IdentifierMask.h
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4#ifndef EVENTCONTAINERS_IDENTIFIERMASK_H
5#define EVENTCONTAINERS_IDENTIFIERMASK_H
6
7#include <vector>
8#include <cstdint>
9#include <bit>
10#include <cassert>
11
12namespace EventContainers {
13
18public:
20 static constexpr size_t BitsPerWord = 64;
22 static constexpr size_t Mask = BitsPerWord - 1;
24 static constexpr size_t MaskShift = std::countr_one(Mask);
25
26 explicit IdentifierMask(size_t maxHash)
27 //Since each uint64_t in the vector can hold 64 bits,
28 //we need to divide the total number of required bits (maxHash) by 64
29 //to find the number of elements needed in the vector
30 : m_bits((maxHash + Mask) / BitsPerWord, 0), m_maxHash(maxHash) {}
31
33 void set(size_t hash) {
34 assert (hash < m_maxHash); //change to a contract in c++26
35 // hash >> 6: Efficiently divides by 64 to find the vector index
36 // hash & Mask: Efficiently computes hash % 64 to find the bit position within the word
37 m_bits[hash >> MaskShift] |= (1ULL << (hash & Mask));
38 }
39
41 bool test(size_t hash) const {
42 assert (hash < m_maxHash); //change to a contract in c++26
43 return (m_bits[hash >> MaskShift] >> (hash & Mask)) & 1ULL;
44 }
45
47 void unset(size_t hash) {
48 assert (hash < m_maxHash); //change to a contract in c++26
49 m_bits[hash >> MaskShift] &= ~(1ULL << (hash & Mask));
50 }
51
53 void clear() {
54 std::fill(m_bits.begin(), m_bits.end(), 0);
55 }
56
59 template<typename Func>
60 void forEachSetBit(Func&& f) const {
61 for (size_t block_idx = 0; block_idx < m_bits.size(); ++block_idx) {
62 uint64_t word = m_bits[block_idx];
63
64 // Skip empty blocks of 64 bits entirely
65 while (word != 0) {
66 // Returns the number of trailing zeros, which is the index of the first '1' bit
67 // countr_zero uses the TZCNT or BSF instruction (1 clock cycle)
68 int bit_idx = std::countr_zero(word);
69
70 // (block_idx << 6): Multiply block index by 64 to get the base bit position
71 // Then add the bit_idx within that block to get the absolute hash value
72 // Execute user logic
73 f((block_idx << MaskShift) + bit_idx);
74
75 // Brian Kernighan’s Algorithm: Clears the least significant bit set to 1.
76 // This allows the 'while' loop to jump directly to the next set bit.
77 // Suggested by Google Gemini and verified by maskTest.cxx
78 word &= (word - 1);
79 }
80 }
81 }
82
84 size_t size() const { return m_maxHash; }
85
87 size_t count() const {
88 size_t total = 0;
89 for (uint64_t word : m_bits) total += std::popcount(word);
90 return total;
91 }
92
93private:
94 std::vector<uint64_t> m_bits;
95 size_t m_maxHash;
96};
97
98} // namespace EventContainers
99#endif
static constexpr size_t BitsPerWord
Bits per storage unit (64).
void forEachSetBit(Func &&f) const
Execute a lambda for every set bit The lambda should accept a size_t index.
bool test(size_t hash) const
Check if a hash is present.
void set(size_t hash)
Mark a hash as present.
size_t count() const
Return a count of the bits set to 1.
void clear()
Reset all bits to 0.
std::vector< uint64_t > m_bits
static constexpr size_t MaskShift
Mask shift value for this word size.
void unset(size_t hash)
Remove a hash from the mask (Set bit to 0).
static constexpr size_t Mask
Mask for the bit index (63).
size_t size() const
Return the total size of the mask.