ATLAS Offline Software
Loading...
Searching...
No Matches
ConcurrentBitset.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
10
11
13#include <bit>
14
15
16namespace CxxUtils {
17
18
19//*********************************************************************************
20// Constructors, destructors, assignment.
21
22
28 : m_impl (new (nbits) Impl (nbits))
29{
30}
31
32
41{
42 // Be careful: don't read other.m_impl more than once. It may change
43 // at any time.
44 const Impl* otherImpl = other.m_impl;
45 // cppcheck-suppress useInitializationList
46 m_impl = new (otherImpl->nbits()) Impl (*otherImpl);
47}
48
49
61ConcurrentBitset::ConcurrentBitset (std::initializer_list<bit_t> l,
62 bit_t nbits /*= 0*/)
63{
64 if (nbits == 0) {
65 // Set the size of the set based on the maximum value in the list.
66 auto max_it = std::max_element (l.begin(), l.end());
67 if (max_it != l.end()) {
68 nbits = *max_it + 1;
69 }
70 // Round up.
71 nbits = (nbits + BLOCKSIZE-1) & ~MASK;
72 }
73 m_impl = new (nbits) Impl (nbits);
74 for (bit_t b : l) {
75 set (b);
76 }
77}
78
79
88{
89 other.emptyGarbage();
90 Impl* impl = other.m_impl;
91 other.m_impl = nullptr;
92 m_impl = impl;
93}
94
95
104
105
114{
115 if (this != &other) {
116 const Impl* otherImpl = other.m_impl;
117 expand (otherImpl->nbits());
118 (*m_impl).assign (*otherImpl);
119 }
120 return *this;
121}
122
123
132{
133 if (this != &other) {
134 emptyGarbage();
135 other.emptyGarbage();
136 delete m_impl;
137 Impl* impl = other.m_impl;
138 other.m_impl = nullptr;
139 m_impl = impl;
140 }
141 return *this;
142}
143
144
154{
155 lock_t lock (m_mutex);
156 for (Impl* p : m_garbage) {
157 free (p);
158 }
159 m_garbage.clear();
160}
161
162
168{
169 // Need to take out the lock.
170 lock_t lock (m_mutex);
171 // Check the size again while we're holding the lock.
172 bit_t nbits = (*m_impl).nbits();
173 if (new_nbits > nbits) {
174 // We need to expand. Allocate a new implementation and initialize it,
175 // copying from the existing implementation.
176 Impl* i = new (new_nbits) Impl (*m_impl, new_nbits);
177
178 // Remember that we need to delete the old object.
179 m_garbage.push_back (m_impl);
180
181 // Publish the new one.
182 m_impl = i;
183 }
184}
185
186
187//*********************************************************************************
188// Implementation.
190
196{
197 bit_t n = 0;
198 for (bit_t i=0; i<m_nblocks; i++) {
199 n += std::popcount (m_data[i].load());
200 }
201 return n;
202}
204
209{
210 for (bit_t i = 0; i < m_nblocks; i++) {
211 if (m_data[i]) return false;
212 }
213 return true;
214}
215
216
221{
222 if (m_nblocks == 0) {
223 return true;
224 }
225
226 // Check all blocks except the last.
227 for (bit_t i = 0; i < m_nblocks-1; i++) {
228 if (m_data[i] != ~static_cast<Block_t>(0)) return false;
229 }
230 // Special case for the last, since the last block may not be full.
232 return false;
233 }
234 return true;
235}
236
237
245{
246 for (bit_t i=0; i<m_nblocks; i++) {
247 m_data[i].store (~static_cast<Block_t>(0), std::memory_order_relaxed);
248 }
249 std::atomic_thread_fence (std::memory_order_seq_cst);
250 if (m_nblocks > 0) {
251 m_hwm = m_nblocks-1;
252 }
253}
254
255
263{
264 for (bit_t i=0; i<m_nblocks; i++) {
265 m_data[i] ^= ~static_cast<Block_t>(0);
266 }
267 if (m_nblocks > 0) {
268 m_hwm = m_nblocks-1;
269 }
270}
271
272
273} // namespace CxxUtils
Variable-sized bitset allowing (mostly) concurrent access.
bit_t nbits() const
Return the number of bits in the set.
std::atomic< size_t > m_hwm
High-water mark: index of last block with a 1 bit.
void set()
Turn on all bits in the set.
bool all() const
Return true if all bits in the set are 1.
bit_t count() const
Count the number of 1 bits in the set.
void flip()
Flip the state of all bits in the set.
size_t m_nbits
Number of bits in the container.
bool none() const
Return true if there are no 1 bits in the set.
size_t m_nblocks
Number of blocks in the container.
std::atomic< Block_t > m_data[1]
The set data.
void emptyGarbage()
Clean up old versions of the set.
void expandOol(bit_t new_nbits)
Expand the container: out-of-line portion.
std::lock_guard< mutex_t > lock_t
unsigned long Block_t
Internal type used to hold the bitset data.
ConcurrentBitset(bit_t nbits=0)
Constructor.
void expand(bit_t new_nbits)
Expand the container.
static const size_t BLOCKSIZE
Size, in bits, of Block_t.
std::atomic< Impl * > m_impl
The current implementation object.
ConcurrentBitset & set()
Turn on all bits in the set.
std::vector< Impl * > m_garbage
Old implementation objects, pending deletion.
ConcurrentBitset & operator=(const ConcurrentBitset &other)
Assignment.
static const size_t MASK
Mask to select out the bit offset within one Block_t.
constexpr T ones(unsigned int n)
Return a bit mask with the lower n bits set.
Definition ones.h:25