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 ArenaPoolSTLAllocator<T, ATHVETO>::ArenaPoolSTLAllocator
477  (size_t nblock /*= 1000*/, const std::string& name /*= ""*/)
478  : m_nblock (nblock),
479  m_name (name),
480  m_poolptr (0)
481 {
482 }
483 
484 
485 /**
486  * @brief Constructor from another @c ArenaPoolSTLAllocator.
487  *
488  * The @c name and @c nblock parameters are copied, but the data are not.
489  */
490 template <class T>
491 template <class U, class V>
492 ArenaPoolSTLAllocator<T, ATHVETO>::ArenaPoolSTLAllocator
493  (const ArenaPoolSTLAllocator<U, V>& a)
494  : m_nblock (a.nblock()),
495  m_name (a.name()),
496  m_poolptr (a.poolptr())
497 {
498 }
499 
500 
501 /**
502  * @brief Return the hinted number of objects allocated per block.
503  */
504 template <class T>
505 inline
506 size_t ArenaPoolSTLAllocator<T, ATHVETO>::nblock() const
507 {
508  return m_nblock;
509 }
510 
511 
512 /**
513  * @brief Return the name of this allocator.
514  */
515 template <class T>
516 inline
517 const std::string& ArenaPoolSTLAllocator<T, ATHVETO>::name() const
518 {
519  return m_name;
520 }
521 
522 
523 /**
524  * @brief Return the statistics block for this allocator.
525  */
526 template <class T>
527 ArenaAllocatorBase::Stats
528 ArenaPoolSTLAllocator<T, ATHVETO>::stats() const
529 {
530  if (m_poolptr) {
531  return m_poolptr->stats();
532  }
533  return ArenaAllocatorBase::Stats();
534 }
535 
536 
537 /**
538  * @brief Return a pointer to the underlying allocator (may be 0).
539  */
540 template <class T>
541 const ArenaBlockAllocatorBase* ArenaPoolSTLAllocator<T, ATHVETO>::poolptr() const
542 {
543  return m_poolptr;
544 }
545 
546 
547 //****************************************************************************
548 // Non-const variant.
549 //
550 
551 
552 /**
553  * @brief Constructor.
554  * @param a Allocator to reference.
555  * @param poolptr_nc Non-const pointer to the underlying allocator.
556  */
557 template <class T>
558 template <class U, class V>
559 ArenaNonConstPoolSTLAllocator<T>::ArenaNonConstPoolSTLAllocator
560  (const ArenaPoolSTLAllocator<U, V>& a,
561  ArenaBlockAllocatorBase* poolptr_nc)
562  : ArenaPoolSTLAllocator<T, T>(a),
563  m_poolptr_nc (poolptr_nc)
564 {
565 }
566 
567 
568 /**
569  * @brief Free all allocated elements.
570  *
571  * All elements allocated are returned to the free state.
572  * @c clear should be called on them if it was provided.
573  * The elements may continue to be cached internally, without
574  * returning to the system.
575  */
576 template <class T>
577 void ArenaNonConstPoolSTLAllocator<T>::reset()
578 {
579  if (m_poolptr_nc)
580  m_poolptr_nc->reset();
581 }
582 
583 
584 /**
585  * @brief Free all allocated elements and release memory back to the system.
586  *
587  * All elements allocated are freed, and all allocated blocks of memory
588  * are released back to the system.
589  * @c destructor should be called on them if it was provided
590  * (preceded by @c clear if provided and @c mustClear was set).
591  */
592 template <class T>
593 void ArenaNonConstPoolSTLAllocator<T>::erase()
594 {
595  if (m_poolptr_nc)
596  m_poolptr_nc->erase();
597 }
598 
599 
600 /**
601  * @brief Set the total number of elements cached by the allocator.
602  * @param size The desired pool size.
603  *
604  * This allows changing the number of elements that are currently free
605  * but cached. Any allocated elements are not affected by this call.
606  *
607  * If @c size is greater than the total number of elements currently
608  * cached, then more will be allocated. This will preferably done
609  * with a single block, but that is not guaranteed; in addition, the
610  * allocator may allocate more elements than is requested.
611  *
612  * If @c size is smaller than the total number of elements currently
613  * cached, as many blocks as possible will be released back to the system.
614  * It may not be possible to release the number of elements requested;
615  * this should be implemented on a best-effort basis.
616  */
617 template <class T>
618 void ArenaNonConstPoolSTLAllocator<T>::reserve (size_t size)
619 {
620  if (m_poolptr_nc)
621  m_poolptr_nc->reserve (size);
622 }
623 
624 
625 /**
626  * @brief Write-protect the memory managed by this allocator.
627  *
628  * Adjust protection on the memory managed by this allocator
629  * to disallow writes.
630  */
631 template <class T>
632 inline
633 void ArenaNonConstPoolSTLAllocator<T>::protect()
634 {
635  if (m_poolptr_nc)
636  m_poolptr_nc->protect();
637 }
638 
639 
640 /**
641  * @brief Write-enable the memory managed by this allocator.
642  *
643  * Adjust protection on the memory managed by this allocator
644  * to allow writes.
645  */
646 template <class T>
647 inline
648 void ArenaNonConstPoolSTLAllocator<T>::unprotect()
649 {
650  if (m_poolptr_nc)
651  m_poolptr_nc->unprotect();
652 }
653 
654 
655 /**
656  * @brief Return an allocator supporting non-const methods from
657  * a non-const container reference.
658  * @param c The (non-const) container.
659  */
660 template <class T>
661 template <class CONT>
662 ArenaNonConstPoolSTLAllocator<T>
663 ArenaPoolSTLAllocator<T, ATHVETO>::get_allocator ATLAS_NOT_CONST_THREAD_SAFE (CONT& c)
664 {
665  // Must be called with a non-const object.
666  typename std::remove_const<CONT>::type& cc = c;
667  ArenaPoolSTLAllocator<T, T> a (cc.get_allocator());
668  return ArenaNonConstPoolSTLAllocator<T> (a,
669  const_cast<ArenaBlockAllocatorBase*>(a.poolptr()));
670 }
671 
672 
673 #undef ATHVETO
674 
675 
676 /**
677  * @brief Hook for unprotecting an arena.
678  *
679  * Sometimes we need to ensure that an arena is unprotected before we start
680  * destroying an object that contains the arena. To do that without
681  * making assumptions about whether the arena supports an unprotect
682  * operation, call this function.
683  */
684 template <class T, class VETO>
685 void maybeUnprotect (ArenaPoolSTLAllocator<T, VETO>& a)
686 {
687  a.unprotect();
688 }
689 
690 
691 } // namespace SG