ATLAS Offline Software
ArenaPoolSTLAllocator.icc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
3 */
4 /**
5  * @file AthAllocators/ArenaPoolSTLAllocator.icc
6  * @author scott snyder
7  * @date Jul 2008
8  * @brief STL-style allocator wrapper for @c ArenaPoolAllocator.
9  */
10 
11 
12 #include <cassert>
13 
14 
15 namespace SG {
16 
17 
18 
19 //****************************************************************************
20 // Generic specialization
21 //
22 
23 
24 /**
25  * @brief Constructor.
26  * @param nblock Value to set in the parameters structure for the
27  * number of elements to allocate per block.
28  * @param name Value to set in the parameters structure for the
29  * allocator name.
30  */
31 template <class T>
32 ArenaPoolSTLAllocator_initParams<T>::ArenaPoolSTLAllocator_initParams
33  (size_t nblock /*= 1000*/, const std::string& name /*= ""*/)
34  : Base (nblock, name)
35 {
36 }
37 
38 
39 /**
40  * @brief Return an initialized parameters structure.
41  */
42 template <class T>
43 ArenaAllocatorBase::Params ArenaPoolSTLAllocator_initParams<T>::params() const
44 {
45  // Do the base class stuff.
46  ArenaAllocatorBase::Params p =
47  Base::operator ArenaAllocatorBase::Params();
48 
49  // Disable ctor/dtor.
50  p.constructor = 0;
51  p.destructor = 0;
52 
53  return p;
54 }
55 
56 
57 /**
58  * @brief Default constructor.
59  * @param nblock Value to set in the parameters structure for the
60  * number of elements to allocate per block.
61  * @param name Value to set in the parameters structure for the
62  * allocator name.
63  */
64 template <class T, class VETO>
65 // False positive --- cppcheck doesn't grok template specialization
66 // cppcheck-suppress uninitMemberVar
67 ArenaPoolSTLAllocator<T, VETO>::ArenaPoolSTLAllocator
68  (size_t nblock /*= 1000*/, const std::string& name /*= ""*/)
69  : m_pool (ArenaPoolSTLAllocator_initParams<T> (nblock, name))
70 {
71 }
72 
73 
74 /**
75  * @brief Copy constructor.
76  *
77  * The @c name and @c nblock parameters are copied, but the data are not.
78  */
79 template <class T, class VETO>
80 ArenaPoolSTLAllocator<T, VETO>::ArenaPoolSTLAllocator
81  (const ArenaPoolSTLAllocator& a)
82  : m_pool (ArenaPoolSTLAllocator_initParams<T> (a.nblock(), a.name()))
83 {
84 }
85 
86 
87 /**
88  * @brief Constructor from another @c ArenaPoolSTLAllocator.
89  *
90  * The @c name and @c nblock parameters are copied, but the data are not.
91  */
92 template <class T, class VETO>
93 template <class U, class V>
94 // False positive --- cppcheck doesn't grok template specialization
95 // cppcheck-suppress uninitMemberVar
96 ArenaPoolSTLAllocator<T, VETO>::ArenaPoolSTLAllocator
97  (const ArenaPoolSTLAllocator<U, V>& a)
98  : m_pool (ArenaPoolSTLAllocator_initParams<T> (a.nblock(), a.name()))
99 {
100 }
101 
102 
103 /**
104  * @brief Move constructor.
105  *
106  * Move the data.
107  */
108 template <class T, class VETO>
109 ArenaPoolSTLAllocator<T, VETO>::ArenaPoolSTLAllocator
110  (ArenaPoolSTLAllocator&& a)
111  : m_pool (std::move (a.m_pool))
112 {
113 }
114 
115 
116 /**
117  * @brief Move constructor.
118  *
119  * Move the data.
120  */
121 template <class T, class VETO>
122 ArenaPoolSTLAllocator<T, VETO>&
123 ArenaPoolSTLAllocator<T, VETO>::operator= (ArenaPoolSTLAllocator&& a)
124 {
125  if (this != &a) {
126  m_pool = std::move (a.m_pool);
127  }
128  return *this;
129 }
130 
131 
132 /**
133  * @brief Swap.
134  */
135 template <class T, class VETO>
136 void ArenaPoolSTLAllocator<T, VETO>::swap (ArenaPoolSTLAllocator& a)
137 {
138  m_pool.swap (a.m_pool);
139 }
140 
141 
142 /**
143  * @brief Equality test.
144  *
145  * Two allocators should compare equal if objects allocated by one
146  * can be deallocated by the other. We should just check if they
147  * are the same object.
148  */
149 template <class T, class VETO>
150 inline
151 bool ArenaPoolSTLAllocator<T, VETO>::operator==
152  (const ArenaPoolSTLAllocator& other) const
153 {
154  return this == &other;
155 }
156 
157 
158 /**
159  * @brief Inequality test.
160  *
161  * Two allocators should compare equal if objects allocated by one
162  * can be deallocated by the other. We should just check if they
163  * are the same object.
164  */
165 template <class T, class VETO>
166 inline
167 bool ArenaPoolSTLAllocator<T, VETO>::operator!=
168  (const ArenaPoolSTLAllocator& other) const
169 {
170  return this != &other;
171 }
172 
173 
174 /**
175  * @brief Return allocator to use for a copy-constructed container.
176  *
177  * When we copy-construct a container, we want the new allocator
178  * to copy parameters from the old one, but not the data.
179  */
180 template <class T, class VETO>
181 inline
182 ArenaPoolSTLAllocator<T, VETO>
183 ArenaPoolSTLAllocator<T, VETO>::select_on_container_copy_construction() const
184 {
185  return ArenaPoolSTLAllocator (nblock(), name());
186 }
187 
188 
189 /**
190  * @brief Convert a reference to an address.
191  */
192 template <class T, class VETO>
193 inline
194 typename ArenaPoolSTLAllocator<T, VETO>::pointer
195 ArenaPoolSTLAllocator<T, VETO>::address (reference x) const
196 {
197  return &x;
198 }
199 
200 
201 /**
202  * @brief Allocate new objects.
203  * @param n Number of objects to allocate. Must be 1.
204  * @param hint Allocation hint. Not used.
205  */
206 template <class T, class VETO>
207 inline
208 typename ArenaPoolSTLAllocator<T, VETO>::pointer
209 ArenaPoolSTLAllocator<T, VETO>::allocate (size_type
210 #if !defined(NDEBUG) && !defined(__CLING__)
211  n
212 #endif
213  , const void* /*hint = 0*/)
214 {
215 #if !defined(__CLING__)
216  assert (n == 1);
217 #endif
218  return reinterpret_cast<pointer> (m_pool.allocate());
219 }
220 
221 
222 /**
223  * @brief Deallocate objects.
224  * @param n Number of objects to deallocate. Must be 1.
225  *
226  * This implementation doesn't do anything.
227  */
228 template <class T, class VETO>
229 inline
230 void ArenaPoolSTLAllocator<T, VETO>::deallocate (pointer, size_type
231 #if !defined(NDEBUG) && !defined(__CLING__)
232  n
233 #endif
234  )
235 {
236 #if !defined(__CLING__)
237  assert (n == 1);
238 #endif
239 }
240 
241 
242 /**
243  * @brief Return the maximum number of objects we can allocate at once.
244  *
245  * This always returns 1.
246  */
247 template <class T, class VETO>
248 inline
249 typename ArenaPoolSTLAllocator<T, VETO>::size_type
250 ArenaPoolSTLAllocator<T, VETO>::max_size() const throw()
251 {
252  return 1;
253 }
254 
255 
256 /**
257  * @brief Call the @c T constructor.
258  * @param p Location of the memory.
259  * @param args Arguments to pass to the constructor.
260  */
261 template <class T, class VETO>
262 template <class... Args>
263 inline
264 void ArenaPoolSTLAllocator<T, VETO>::construct (pointer p, Args&&... args)
265 {
266  new (p) T(std::forward<Args>(args)...);
267 }
268 
269 
270 /**
271  * @brief Call the @c T destructor.
272  * @param p Location of the memory.
273  */
274 template <class T, class VETO>
275 inline
276 void ArenaPoolSTLAllocator<T, VETO>::destroy (pointer p)
277 {
278  p->~T();
279 }
280 
281 
282 /**
283  * @brief Return the hinted number of objects allocated per block.
284  */
285 template <class T, class VETO>
286 inline
287 size_t ArenaPoolSTLAllocator<T, VETO>::nblock() const
288 {
289  return m_pool.params().nblock;
290 }
291 
292 
293 /**
294  * @brief Return the name of this allocator.
295  */
296 template <class T, class VETO>
297 inline
298 const std::string& ArenaPoolSTLAllocator<T, VETO>::name() const
299 {
300  return m_pool.name();
301 }
302 
303 
304 /**
305  * @brief Free all allocated elements.
306  *
307  * All elements allocated are returned to the free state.
308  * @c clear should be called on them if it was provided.
309  * The elements may continue to be cached internally, without
310  * returning to the system.
311  */
312 template <class T, class VETO>
313 void ArenaPoolSTLAllocator<T, VETO>::reset()
314 {
315  m_pool.reset();
316 }
317 
318 
319 /**
320  * @brief Free all allocated elements and release memory back to the system.
321  *
322  * All elements allocated are freed, and all allocated blocks of memory
323  * are released back to the system.
324  * @c destructor should be called on them if it was provided
325  * (preceded by @c clear if provided and @c mustClear was set).
326  */
327 template <class T, class VETO>
328 void ArenaPoolSTLAllocator<T, VETO>::erase()
329 {
330  m_pool.erase();
331 }
332 
333 
334 /**
335  * @brief Set the total number of elements cached by the allocator.
336  * @param size The desired pool size.
337  *
338  * This allows changing the number of elements that are currently free
339  * but cached. Any allocated elements are not affected by this call.
340  *
341  * If @c size is greater than the total number of elements currently
342  * cached, then more will be allocated. This will preferably done
343  * with a single block, but that is not guaranteed; in addition, the
344  * allocator may allocate more elements than is requested.
345  *
346  * If @c size is smaller than the total number of elements currently
347  * cached, as many blocks as possible will be released back to the system.
348  * It may not be possible to release the number of elements requested;
349  * this should be implemented on a best-effort basis.
350  */
351 template <class T, class VETO>
352 void ArenaPoolSTLAllocator<T, VETO>::reserve (size_t size)
353 {
354  m_pool.reserve (size);
355 }
356 
357 
358 /**
359  * @brief Return the statistics block for this allocator.
360  */
361 template <class T, class VETO>
362 ArenaAllocatorBase::Stats ArenaPoolSTLAllocator<T, VETO>::stats() const
363 {
364  return m_pool.stats();
365 }
366 
367 
368 /**
369  * @brief Return a pointer to the underlying allocator (may be 0).
370  */
371 template <class T, class VETO>
372 const ArenaBlockAllocatorBase* ArenaPoolSTLAllocator<T, VETO>::poolptr() const
373 {
374  return &m_pool;
375 }
376 
377 
378 /**
379  * @brief Write-protect the memory managed by this allocator.
380  *
381  * Adjust protection on the memory managed by this allocator
382  * to disallow writes.
383  */
384 template <class T, class VETO>
385 inline
386 void ArenaPoolSTLAllocator<T, VETO>::protect()
387 {
388  m_pool.protect();
389 }
390 
391 
392 /**
393  * @brief Write-enable the memory managed by this allocator.
394  *
395  * Adjust protection on the memory managed by this allocator
396  * to allow writes.
397  */
398 template <class T, class VETO>
399 inline
400 void ArenaPoolSTLAllocator<T, VETO>::unprotect()
401 {
402  m_pool.unprotect();
403 }
404 
405 
406 //****************************************************************************
407 // Pointer specialization.
408 //
409 
410 
411 /**
412  * @brief Default constructor.
413  * @param nblock Value to set in the parameters structure for the
414  * number of elements to allocate per block.
415  * @param name Value to set in the parameters structure for the
416  * allocator name.
417  */
418 template <class T, class VETO>
419 ArenaPoolSTLAllocator<T*, VETO>::ArenaPoolSTLAllocator
420  (size_t nblock /*= 1000*/, const std::string& name /*= ""*/)
421  : m_nblock (nblock),
422  m_name (name)
423 {
424 }
425 
426 
427 /**
428  * @brief Constructor from another @c ArenaPoolSTLAllocator.
429  *
430  * The @c name and @c nblock parameters are copied, but the data are not.
431  */
432 template <class T, class VETO>
433 template <class U, class V>
434 ArenaPoolSTLAllocator<T*, VETO>::ArenaPoolSTLAllocator
435  (const ArenaPoolSTLAllocator<U, V>&)
436 {
437 }
438 
439 
440 /**
441  * @brief Return the hinted number of objects allocated per block.
442  */
443 template <class T, class VETO>
444 inline
445 size_t ArenaPoolSTLAllocator<T*, VETO>::nblock() const
446 {
447  return m_nblock;
448 }
449 
450 
451 /**
452  * @brief Return the name of this allocator.
453  */
454 template <class T, class VETO>
455 inline
456 const std::string& ArenaPoolSTLAllocator<T*, VETO>::name() const
457 {
458  return m_name;
459 }
460 
461 
462 //****************************************************************************
463 // Vetoed specialization.
464 //
465 
466 #define ATHVETO typename std::enable_if<!std::is_pointer_v<T>, T>::type
467 
468 /**
469  * @brief Default constructor.
470  * @param nblock Value to set in the parameters structure for the
471  * number of elements to allocate per block.
472  * @param name Value to set in the parameters structure for the
473  * allocator name.
474  */
475 template <class T>
476 // cppcheck-suppress uninitMemberVar ; false positive
477 ArenaPoolSTLAllocator<T, ATHVETO>::ArenaPoolSTLAllocator
478  (size_t nblock /*= 1000*/, const std::string& name /*= ""*/)
479  : m_nblock (nblock),
480  m_name (name),
481  m_poolptr (0)
482 {
483 }
484 
485 
486 /**
487  * @brief Constructor from another @c ArenaPoolSTLAllocator.
488  *
489  * The @c name and @c nblock parameters are copied, but the data are not.
490  */
491 template <class T>
492 template <class U, class V>
493 ArenaPoolSTLAllocator<T, ATHVETO>::ArenaPoolSTLAllocator
494  (const ArenaPoolSTLAllocator<U, V>& a)
495  : m_nblock (a.nblock()),
496  m_name (a.name()),
497  m_poolptr (a.poolptr())
498 {
499 }
500 
501 
502 /**
503  * @brief Return the hinted number of objects allocated per block.
504  */
505 template <class T>
506 inline
507 size_t ArenaPoolSTLAllocator<T, ATHVETO>::nblock() const
508 {
509  return m_nblock;
510 }
511 
512 
513 /**
514  * @brief Return the name of this allocator.
515  */
516 template <class T>
517 inline
518 const std::string& ArenaPoolSTLAllocator<T, ATHVETO>::name() const
519 {
520  return m_name;
521 }
522 
523 
524 /**
525  * @brief Return the statistics block for this allocator.
526  */
527 template <class T>
528 ArenaAllocatorBase::Stats
529 ArenaPoolSTLAllocator<T, ATHVETO>::stats() const
530 {
531  if (m_poolptr) {
532  return m_poolptr->stats();
533  }
534  return ArenaAllocatorBase::Stats();
535 }
536 
537 
538 /**
539  * @brief Return a pointer to the underlying allocator (may be 0).
540  */
541 template <class T>
542 const ArenaBlockAllocatorBase* ArenaPoolSTLAllocator<T, ATHVETO>::poolptr() const
543 {
544  return m_poolptr;
545 }
546 
547 
548 //****************************************************************************
549 // Non-const variant.
550 //
551 
552 
553 /**
554  * @brief Constructor.
555  * @param a Allocator to reference.
556  * @param poolptr_nc Non-const pointer to the underlying allocator.
557  */
558 template <class T>
559 template <class U, class V>
560 ArenaNonConstPoolSTLAllocator<T>::ArenaNonConstPoolSTLAllocator
561  (const ArenaPoolSTLAllocator<U, V>& a,
562  ArenaBlockAllocatorBase* poolptr_nc)
563  : ArenaPoolSTLAllocator<T, T>(a),
564  m_poolptr_nc (poolptr_nc)
565 {
566 }
567 
568 
569 /**
570  * @brief Free all allocated elements.
571  *
572  * All elements allocated are returned to the free state.
573  * @c clear should be called on them if it was provided.
574  * The elements may continue to be cached internally, without
575  * returning to the system.
576  */
577 template <class T>
578 void ArenaNonConstPoolSTLAllocator<T>::reset()
579 {
580  if (m_poolptr_nc)
581  m_poolptr_nc->reset();
582 }
583 
584 
585 /**
586  * @brief Free all allocated elements and release memory back to the system.
587  *
588  * All elements allocated are freed, and all allocated blocks of memory
589  * are released back to the system.
590  * @c destructor should be called on them if it was provided
591  * (preceded by @c clear if provided and @c mustClear was set).
592  */
593 template <class T>
594 void ArenaNonConstPoolSTLAllocator<T>::erase()
595 {
596  if (m_poolptr_nc)
597  m_poolptr_nc->erase();
598 }
599 
600 
601 /**
602  * @brief Set the total number of elements cached by the allocator.
603  * @param size The desired pool size.
604  *
605  * This allows changing the number of elements that are currently free
606  * but cached. Any allocated elements are not affected by this call.
607  *
608  * If @c size is greater than the total number of elements currently
609  * cached, then more will be allocated. This will preferably done
610  * with a single block, but that is not guaranteed; in addition, the
611  * allocator may allocate more elements than is requested.
612  *
613  * If @c size is smaller than the total number of elements currently
614  * cached, as many blocks as possible will be released back to the system.
615  * It may not be possible to release the number of elements requested;
616  * this should be implemented on a best-effort basis.
617  */
618 template <class T>
619 void ArenaNonConstPoolSTLAllocator<T>::reserve (size_t size)
620 {
621  if (m_poolptr_nc)
622  m_poolptr_nc->reserve (size);
623 }
624 
625 
626 /**
627  * @brief Write-protect the memory managed by this allocator.
628  *
629  * Adjust protection on the memory managed by this allocator
630  * to disallow writes.
631  */
632 template <class T>
633 inline
634 void ArenaNonConstPoolSTLAllocator<T>::protect()
635 {
636  if (m_poolptr_nc)
637  m_poolptr_nc->protect();
638 }
639 
640 
641 /**
642  * @brief Write-enable the memory managed by this allocator.
643  *
644  * Adjust protection on the memory managed by this allocator
645  * to allow writes.
646  */
647 template <class T>
648 inline
649 void ArenaNonConstPoolSTLAllocator<T>::unprotect()
650 {
651  if (m_poolptr_nc)
652  m_poolptr_nc->unprotect();
653 }
654 
655 
656 /**
657  * @brief Return an allocator supporting non-const methods from
658  * a non-const container reference.
659  * @param c The (non-const) container.
660  */
661 template <class T>
662 template <class CONT>
663 ArenaNonConstPoolSTLAllocator<T>
664 ArenaPoolSTLAllocator<T, ATHVETO>::get_allocator ATLAS_NOT_CONST_THREAD_SAFE (CONT& c)
665 {
666  // Must be called with a non-const object.
667  typename std::remove_const<CONT>::type& cc = c;
668  ArenaPoolSTLAllocator<T, T> a (cc.get_allocator());
669  return ArenaNonConstPoolSTLAllocator<T> (a,
670  const_cast<ArenaBlockAllocatorBase*>(a.poolptr()));
671 }
672 
673 
674 #undef ATHVETO
675 
676 
677 /**
678  * @brief Hook for unprotecting an arena.
679  *
680  * Sometimes we need to ensure that an arena is unprotected before we start
681  * destroying an object that contains the arena. To do that without
682  * making assumptions about whether the arena supports an unprotect
683  * operation, call this function.
684  */
685 template <class T, class VETO>
686 void maybeUnprotect (ArenaPoolSTLAllocator<T, VETO>& a)
687 {
688  a.unprotect();
689 }
690 
691 
692 } // namespace SG