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
27ConcurrentBitset::ConcurrentBitset (bit_t nbits /*= 0*/)
28 : m_impl (new (nbits) Impl (nbits))
29{
30}
31
32
40ConcurrentBitset::ConcurrentBitset (const ConcurrentBitset& other)
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
87ConcurrentBitset::ConcurrentBitset (ConcurrentBitset&& other)
88{
89 other.emptyGarbage();
90 Impl* impl = other.m_impl;
91 other.m_impl = nullptr;
92 m_impl = impl;
93}
94
95
99ConcurrentBitset::~ConcurrentBitset()
100{
101 delete m_impl;
102 emptyGarbage();
103}
104
105
113ConcurrentBitset& ConcurrentBitset::operator= (const ConcurrentBitset& other)
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
131ConcurrentBitset& ConcurrentBitset::operator= (ConcurrentBitset&& other)
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
153void ConcurrentBitset::emptyGarbage()
154{
156 for (Impl* p : m_garbage) {
157 free (p);
158 }
159 m_garbage.clear();
160}
161
162
167void ConcurrentBitset::expandOol (bit_t new_nbits)
168{
169 // Need to take out the lock.
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.
189
190
194ConcurrentBitset::bit_t
195ConcurrentBitset::Impl::count() const
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}
203
204
208bool ConcurrentBitset::Impl::none() const
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
220bool ConcurrentBitset::Impl::all() const
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.
231 if (m_data[m_nblocks] != ones<Block_t> (m_nbits - (m_nblocks-1)*BLOCKSIZE)) {
232 return false;
233 }
234 return true;
235}
236
237
244void ConcurrentBitset::Impl::set()
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
262void ConcurrentBitset::Impl::flip()
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.
virtual void lock()=0
Interface to allow an object to lock itself when made const in SG.
consteval T ones(unsigned int n)
Return a bit mask with the lower n bits set.
std::unique_ptr< StringPoolImpl > m_impl
Definition StringPool.h:137
Implementation object.
STL class.
void emptyGarbage()
Clean up old versions of the set.
ConcurrentBitset(bit_t nbits=0)
Constructor.
mutex_t m_mutex
Mutex protecting the container.
std::lock_guard< mutex_t > lock_t
std::atomic< Impl * > m_impl
The current implementation object.
std::vector< Impl * > m_garbage
Old implementation objects, pending deletion.
l
Printing final latex table to .tex output file.