2 Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
5 * @file AthAllocators/ArenaSharedHeapSTLAllocator.icc
6 * @author scott snyder <snyder@bnl.gov>
8 * @brief STL-style allocator wrapper for @c ArenaHeapAllocator allowing
9 * the heap to be shared between containers.
13 #include "GaudiKernel/System.h"
14 #include "AthAllocators/exceptions.h"
23 * @brief Call this when an allocator is being deleted.
24 * @param a The address of calling allocator.
26 * If the address matches the address we were given when we were created,
27 * this object will be destroyed.
30 void ArenaSharedHeapSTLHeader::maybe_delete (const void* a)
39 * @brief Return the name to use for an allocator for type @c T.
42 std::string ArenaSharedHeapSTLHeader::get_name()
44 return "ArenaSharedHeapSTLAllocator<" +
45 System::typeinfoName (typeid (T)) + ">";
50 * @brief Return the heap allocator for type @c T.
53 ArenaHeapAllocator* ArenaSharedHeapSTLHeader::get_pool()
55 const static size_t index = get_index<T>();
57 // Expand the list of allocators if needed.
58 if (index >= m_allocators.size()) {
59 m_allocators.resize (index+1);
62 // Create the allocator if we haven't done so yet.
63 if (!m_allocators[index]) {
64 m_allocators[index] = new ArenaHeapAllocator
65 (ArenaHeapSTLAllocator_initParams<T> (m_nblock, get_name<T>()));
68 // Return the allocator.
69 return m_allocators[index];
74 * @brief Update the owner of this object.
75 * @param old_owner Object giving up ownership.
76 * @param new_owner Object acquiring ownership.
78 * If the current owner is @c old_owner then change the owner to @c new_owner.
81 void ArenaSharedHeapSTLHeader::update_owner (const void* old_owner,
82 const void* new_owner)
84 if (m_owner == old_owner)
90 * @brief Return the allocator index to use for type @c T.
93 size_t ArenaSharedHeapSTLHeader::get_index()
95 // Note: We're only using the registry for the name<->index
96 // mapping; we're not using it to construct the allocators
97 // for us. This, we pass in a null pointer for the constructor.
98 // (We don't construct the allocators from the registry because
99 // we cant to be able to change the number of blocks from instance
100 // to instance, but there's no way passing that to the Registry
103 std::string name = get_name<T>();
104 ArenaAllocatorRegistry* reg = ArenaAllocatorRegistry::instance();
105 size_t index = reg->lookup (name);
106 if (index == std::string::npos) {
107 index = reg->registerCreator (name, 0);
113 //===========================================================================
117 * @brief Default constructor.
118 * @param nblock Value to set in the parameters structure for the
119 * number of elements to allocate per block.
122 ArenaSharedHeapSTLAllocator<T>::ArenaSharedHeapSTLAllocator
123 (size_t nblock /*= 1000*/)
124 : m_header (nullptr),
127 // Done in two steps like this to avoid maybe-uninitialized warnings
129 m_header = new ArenaSharedHeapSTLHeader (this, nblock);
130 m_pool = m_header->get_pool<T>();
135 * @brief Copy constructor.
137 * The new STL allocator will reference the same set of underlying
138 * Arena allocators as the old one.
142 ArenaSharedHeapSTLAllocator<T>::ArenaSharedHeapSTLAllocator
143 (const ArenaSharedHeapSTLAllocator& a)
144 : m_header (a.m_header),
151 * @brief Constructor from another @c ArenaSharedHeapSTLAllocator.
153 * The new STL allocator will reference the same set of underlying
154 * Arena allocators as the old one.
159 ArenaSharedHeapSTLAllocator<T>::ArenaSharedHeapSTLAllocator
160 (const ArenaSharedHeapSTLAllocator<U>& a)
161 : m_header (a.m_header),
162 m_pool (m_header->get_pool<T>())
172 ArenaSharedHeapSTLAllocator<T>::~ArenaSharedHeapSTLAllocator()
174 m_header->maybe_delete (this);
181 * We allow assignment only if the two objects involved represent
182 * the same arena, in which case it's a no-op.
183 * In other cases, we raise an exception.
186 ArenaSharedHeapSTLAllocator<T>&
187 ArenaSharedHeapSTLAllocator<T>::operator=
188 (const ArenaSharedHeapSTLAllocator& a)
191 if (m_header != a.m_header) {
192 throw SG::ExcDifferentArenas();
194 assert (m_pool == a.m_pool);
201 * @brief Move assignment.
203 * This allows assignment between different arenas.
206 ArenaSharedHeapSTLAllocator<T>&
207 ArenaSharedHeapSTLAllocator<T>::operator= (ArenaSharedHeapSTLAllocator&& a)
209 if (this != &a && m_header != a.m_header) {
210 m_header = a.m_header;
221 void ArenaSharedHeapSTLAllocator<T>::swap (ArenaSharedHeapSTLAllocator& a)
223 if (m_header != a.m_header) {
224 std::swap (m_header, a.m_header);
225 m_header->update_owner (&a, this);
226 a.m_header->update_owner (this, &a);
227 std::swap (m_pool, a.m_pool);
233 * @brief Equality test.
235 * Two allocators should compare equal if objects allocated by one
236 * can be deallocated by the other. We check if they are referencing
241 bool ArenaSharedHeapSTLAllocator<T>::operator==
242 (const ArenaSharedHeapSTLAllocator& other) const
244 return m_header == other.m_header;
249 * @brief Inequality test.
251 * Two allocators should compare equal if objects allocated by one
252 * can be deallocated by the other. We check if they are referencing
257 bool ArenaSharedHeapSTLAllocator<T>::operator!=
258 (const ArenaSharedHeapSTLAllocator& other) const
260 return m_header != other.m_header;
265 * @brief Convert a reference to an address.
269 typename ArenaSharedHeapSTLAllocator<T>::pointer
270 ArenaSharedHeapSTLAllocator<T>::address (reference x) const
277 * @brief Allocate new objects.
278 * @param n Number of objects to allocate. Must be 1.
279 * @param hint Allocation hint. Not used.
283 typename ArenaSharedHeapSTLAllocator<T>::pointer
284 ArenaSharedHeapSTLAllocator<T>::allocate (size_type
288 , const void* /*hint = 0*/)
291 return reinterpret_cast<pointer> (poolptr()->allocate());
296 * @brief Deallocate objects.
297 * @param n Number of objects to deallocate. Must be 1.
299 * This implementation doesn't do anything.
303 void ArenaSharedHeapSTLAllocator<T>::deallocate (pointer p, size_type
310 using pointer_nc = std::remove_const_t<T>*;
311 pointer_nc pp ATLAS_THREAD_SAFE = const_cast<pointer_nc>(p);
312 poolptr()->free (reinterpret_cast<ArenaAllocatorBase::pointer> (pp));
317 * @brief Return the maximum number of objects we can allocate at once.
319 * This always returns 1.
323 typename ArenaSharedHeapSTLAllocator<T>::size_type
324 ArenaSharedHeapSTLAllocator<T>::max_size() const throw()
331 * @brief Call the @c T constructor.
332 * @param p Location of the memory.
333 * @param args Arguments to pass to the constructor.
336 template <class... Args>
338 void ArenaSharedHeapSTLAllocator<T>::construct (pointer p, Args&&... args)
340 new (p) T(std::forward<Args>(args)...);
345 * @brief Call the @c T destructor.
346 * @param p Location of the memory.
350 void ArenaSharedHeapSTLAllocator<T>::destroy (pointer p)
357 * @brief Return the hinted number of objects allocated per block.
361 size_t ArenaSharedHeapSTLAllocator<T>::nblock() const
363 return poolptr()->params().nblock;
368 * @brief Return the name of this allocator.
372 const std::string& ArenaSharedHeapSTLAllocator<T>::name() const
374 return poolptr()->name();
379 * @brief Free all allocated elements.
381 * All elements allocated are returned to the free state.
382 * @c clear should be called on them if it was provided.
383 * The elements may continue to be cached internally, without
384 * returning to the system.
387 void ArenaSharedHeapSTLAllocator<T>::reset()
394 * @brief Free all allocated elements and release memory back to the system.
396 * All elements allocated are freed, and all allocated blocks of memory
397 * are released back to the system.
398 * @c destructor should be called on them if it was provided
399 * (preceded by @c clear if provided and @c mustClear was set).
402 void ArenaSharedHeapSTLAllocator<T>::erase()
409 * @brief Set the total number of elements cached by the allocator.
410 * @param size The desired pool size.
412 * This allows changing the number of elements that are currently free
413 * but cached. Any allocated elements are not affected by this call.
415 * If @c size is greater than the total number of elements currently
416 * cached, then more will be allocated. This will preferably done
417 * with a single block, but that is not guaranteed; in addition, the
418 * allocator may allocate more elements than is requested.
420 * If @c size is smaller than the total number of elements currently
421 * cached, as many blocks as possible will be released back to the system.
422 * It may not be possible to release the number of elements requested;
423 * this should be implemented on a best-effort basis.
426 void ArenaSharedHeapSTLAllocator<T>::reserve (size_t size)
428 poolptr()->reserve (size);
433 * @brief Return the statistics block for this allocator.
436 ArenaAllocatorBase::Stats
437 ArenaSharedHeapSTLAllocator<T>::stats() const
439 return poolptr()->stats();
444 * @brief Return the statistics blocks summed up over all allocators
449 ArenaAllocatorBase::Stats ArenaSharedHeapSTLAllocator<T>::totstats() const
451 return m_header->totstats();
456 * @brief Return a pointer to the underlying allocator.
460 ArenaHeapAllocator* ArenaSharedHeapSTLAllocator<T>::poolptr()
467 * @brief Return a pointer to the underlying allocator.
471 const ArenaHeapAllocator* ArenaSharedHeapSTLAllocator<T>::poolptr() const
478 * @brief Generate printable report for all contained allocators.
479 * @param os Stream to which to write the report.
482 void ArenaSharedHeapSTLAllocator<T>::report (std::ostream& os) const
484 m_header->report(os);
489 * @brief Write-protect the memory managed by these allocators.
491 * Adjust protection on the memory managed by these allocators
492 * to disallow writes.
496 void ArenaSharedHeapSTLAllocator<T>::protect()
503 * @brief Write-enable the memory managed by these allocators.
505 * Adjust protection on the memory managed by these allocators
510 void ArenaSharedHeapSTLAllocator<T>::unprotect()
512 m_header->unprotect();
517 * @brief Hook for unprotecting an arena.
519 * Sometimes we need to ensure that an arena is unprotected before we start
520 * destroying an object that contains the arena. To do that without
521 * making assumptions about whether the arena supports an unprotect
522 * operation, call this function.
525 void maybeUnprotect (ArenaSharedHeapSTLAllocator<T>& a)