ATLAS Offline Software
DataVectorWithAlloc.icc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration.
3  */
4 /**
5  * @file AthContainers/DataVectorWithAlloc.icc
6  * @author scott snyder <snyder@bnl.gov>
7  * @date Aug, 2021
8  * @brief DataVector using a custom allocator for the elements.
9  */
10 
11 
12 #include "AthAllocators/exceptions.h"
13 
14 
15 //=== Smart pointer.
16 
17 
18 template <class DV, class ALLOC>
19 inline
20 DataVectorWithAlloc<DV, ALLOC>::UPDeleter::UPDeleter() noexcept
21  : m_heap (nullptr)
22 {
23 }
24 
25 
26 template <class DV, class ALLOC>
27 inline
28 DataVectorWithAlloc<DV, ALLOC>::UPDeleter::UPDeleter (elt_allocator_type& heap) noexcept
29  : m_heap (&heap)
30 {
31 }
32 
33 
34 template <class DV, class ALLOC>
35 inline
36 void DataVectorWithAlloc<DV, ALLOC>::UPDeleter::operator() (value_type p)
37 {
38  using base_value_type_nc = std::remove_const_t<base_value_type>;
39  base_value_type_nc* pp ATLAS_THREAD_SAFE = const_cast<base_value_type_nc*>(DV::do_cast_nc (p));
40  m_heap->destroy (pp);
41  m_heap->deallocate (pp, 1);
42 }
43 
44 
45 template <class DV, class ALLOC>
46 inline
47 const typename DataVectorWithAlloc<DV, ALLOC>::elt_allocator_type*
48 DataVectorWithAlloc<DV, ALLOC>::UPDeleter::heap() const noexcept
49 {
50  return m_heap;
51 }
52 
53 
54 template <class DV, class ALLOC>
55 inline
56 DataVectorWithAlloc<DV, ALLOC>::Ptr::Ptr (std::nullptr_t) noexcept
57 {
58 }
59 
60 
61 template <class DV, class ALLOC>
62 inline
63 DataVectorWithAlloc<DV, ALLOC>::Ptr::operator bool() const noexcept
64 {
65  return static_cast<bool>(m_ptr);
66 }
67 
68 
69 template <class DV, class ALLOC>
70 inline
71 typename DataVectorWithAlloc<DV, ALLOC>::Ptr&
72 DataVectorWithAlloc<DV, ALLOC>::Ptr::operator= (std::nullptr_t) noexcept
73 {
74  m_ptr = nullptr;
75  return *this;
76 }
77 
78 
79 template <class DV, class ALLOC>
80 inline
81 void DataVectorWithAlloc<DV, ALLOC>::Ptr::swap (Ptr& other) noexcept
82 {
83  m_ptr.swap (other.m_ptr);
84 }
85 
86 
87 template <class DV, class ALLOC>
88 inline
89 typename DataVectorWithAlloc<DV, ALLOC>::Ptr::pointer
90 DataVectorWithAlloc<DV, ALLOC>::Ptr::get() const noexcept
91 {
92  return m_ptr.get();
93 }
94 
95 
96 template <class DV, class ALLOC>
97 inline
98 typename std::add_lvalue_reference<typename DV::base_value_type>::type
99 DataVectorWithAlloc<DV, ALLOC>::Ptr::operator*() const
100 {
101  return *m_ptr;
102 }
103 
104 
105 template <class DV, class ALLOC>
106 inline
107 typename DataVectorWithAlloc<DV, ALLOC>::Ptr::pointer
108 DataVectorWithAlloc<DV, ALLOC>::Ptr::operator->() const noexcept
109 {
110  return m_ptr.get();
111 }
112 
113 
114 template <class DV, class ALLOC>
115 inline
116 bool
117 DataVectorWithAlloc<DV, ALLOC>::Ptr::operator== (const Ptr& other) const noexcept
118 {
119  return m_ptr == other.m_ptr;
120 }
121 
122 
123 template <class DV, class ALLOC>
124 inline
125 bool
126 DataVectorWithAlloc<DV, ALLOC>::Ptr::operator< (const Ptr& other) const noexcept
127 {
128  return m_ptr < other.m_ptr;
129 }
130 
131 
132 template <class DV, class ALLOC>
133 inline
134 bool
135 DataVectorWithAlloc<DV, ALLOC>::Ptr::operator== (std::nullptr_t) const noexcept
136 {
137  return m_ptr == nullptr;
138 }
139 
140 
141 template <class DV, class ALLOC>
142 inline
143 bool
144 DataVectorWithAlloc<DV, ALLOC>::Ptr::operator!= (std::nullptr_t) const noexcept
145 {
146  return m_ptr != nullptr;
147 }
148 
149 
150 template <class DV, class ALLOC>
151 inline
152 DataVectorWithAlloc<DV, ALLOC>::Ptr::Ptr (pointer p, UPDeleter&& d) noexcept
153  : m_ptr (p, std::move(d))
154 {
155 }
156 
157 
158 template <class DV, class ALLOC>
159 inline
160 typename DataVectorWithAlloc<DV, ALLOC>::Ptr::pointer
161 DataVectorWithAlloc<DV, ALLOC>::Ptr::release() noexcept
162 {
163  return m_ptr.release();
164 }
165 
166 
167 template <class DV, class ALLOC>
168 inline
169 void
170 DataVectorWithAlloc<DV, ALLOC>::Ptr::checkHeap (const elt_allocator_type* other_heap) const
171 {
172  const elt_allocator_type* this_heap = m_ptr.get_deleter().heap();
173  if (this_heap && this_heap != other_heap) {
174  SG::throwExcAllocOwnership();
175  }
176 }
177 
178 
179 //=== Constructors, destructors, assignment.
180 
181 
182 /**
183  * @brief Default constructor.
184  * @param eltAlloc The element allocator.
185  */
186 template <class DV, class ALLOC>
187 DataVectorWithAlloc<DV, ALLOC>::DataVectorWithAlloc
188  (elt_allocator_type&& eltAlloc /*= elt_allocator_type()*/)
189 {
190  auto del = std::make_unique<HeapDeleter> (std::move (eltAlloc));
191  m_heap = &del->heap();
192  DV::clear (std::move (del));
193 }
194 
195 
196 /**
197  * @brief Sized constructor.
198  * @param n The size of the container.
199  * @param eltAlloc The element allocator.
200  *
201  * Note that unlike the standard vector constructor, you can't specify
202  * an initial value here. The container will be initialized with 0's.
203  */
204 template <class DV, class ALLOC>
205 DataVectorWithAlloc<DV, ALLOC>::DataVectorWithAlloc
206  (size_type n,
207  elt_allocator_type&& eltAlloc /*= elt_allocator_type()*/)
208 {
209  auto del = std::make_unique<HeapDeleter> (std::move (eltAlloc));
210  m_heap = &del->heap();
211  DV::clear (std::move (del));
212  DV::resize (n);
213 }
214 
215 
216 /**
217  * @brief Move constructor.
218  * @param rhs The container from which to move.
219  *
220  * Any auxiliary data will be moved along with the container contents.
221  *
222  * The existing allocator is moved. @c rhs will be left with a new,
223  * default-initialized, allocator.
224  */
225 template <class DV, class ALLOC>
226 DataVectorWithAlloc<DV, ALLOC>::DataVectorWithAlloc
227  (DataVectorWithAlloc&& rhs)
228  : DV (std::move (rhs)),
229  m_heap (rhs.m_heap)
230 {
231  auto del = std::make_unique<HeapDeleter> (elt_allocator_type());
232  rhs.m_heap = &del->heap();
233  static_cast<DV&>(rhs).clear (std::move (del));
234 }
235 
236 
237 /**
238  * @brief Move assignment.
239  * @param rhs The container from which to move.
240  *
241  * Any auxiliary data will be moved along with the container contents.
242  *
243  * The existing allocator is moved. @c rhs will be left with a new,
244  * default-initialized, allocator.
245  */
246 template <class DV, class ALLOC>
247 DataVectorWithAlloc<DV, ALLOC>&
248 DataVectorWithAlloc<DV, ALLOC>::operator= (DataVectorWithAlloc&& rhs)
249 {
250  if (this != &rhs) {
251  DV::operator= (std::move (rhs));
252  m_heap = rhs.m_heap;
253  auto del = std::make_unique<HeapDeleter> (elt_allocator_type());
254  rhs.m_heap = &del->heap();
255  static_cast<DV&>(rhs).clear (std::move (del));
256  }
257  return *this;
258 }
259 
260 
261 /**
262  * @brief Destructor.
263  */
264 template <class DV, class ALLOC>
265 DataVectorWithAlloc<DV, ALLOC>::~DataVectorWithAlloc()
266 {
267  // If the heap memory was protected, unprotect it now.
268  try {
269  SG::maybeUnprotect (*m_heap);
270  }
271  catch (const SG::ExcProtection&) {
272  // Got an error from mprotect...
273  std::abort();
274  }
275 }
276 
277 
278 /**
279  * @brief Return the underlying allocator.
280  */
281 template <class DV, class ALLOC>
282 inline
283 const typename DataVectorWithAlloc<DV, ALLOC>::elt_allocator_type&
284 DataVectorWithAlloc<DV, ALLOC>::elt_allocator() const
285 {
286  return *m_heap;
287 }
288 
289 
290 /**
291  * @brief Return the underlying allocator.
292  */
293 template <class DV, class ALLOC>
294 inline
295 typename DataVectorWithAlloc<DV, ALLOC>::elt_allocator_type&
296 DataVectorWithAlloc<DV, ALLOC>::elt_allocator()
297 {
298  return *m_heap;
299 }
300 
301 
302 //=== Size and capacity.
303 
304 
305 /**
306  * @fn void reserve (size_type n)
307  * @brief Attempt to preallocate enough memory for a specified number
308  * of elements.
309  * @param n Number of elements required.
310  */
311 template <class DV, class ALLOC>
312 void DataVectorWithAlloc<DV, ALLOC>::reserve (size_type n)
313 {
314  DV::reserve (n);
315  m_heap->reserve (n);
316 }
317 
318 
319 /**
320  * @brief Change the vector capacity to match the current size.
321  *
322  * Note: this does not affect auxiliary data.
323  */
324 template <class DV, class ALLOC>
325 void DataVectorWithAlloc<DV, ALLOC>::shrink_to_fit()
326 {
327  DV::shrink_to_fit();
328  m_heap->reserve (size());
329 }
330 
331 
332 //=== Element access.
333 
334 
335 /**
336  * @brief Access an element, as an lvalue.
337  * @param n Array index to access.
338  * @return Proxy to the element at @a n.
339  *
340  * No bounds checking is done.
341  * Note that we return a proxy object rather than a reference;
342  * the proxy will handle deleting an owned element if it's assigned to.
343  */
344 template <class DV, class ALLOC>
345 inline
346 typename DataVectorWithAlloc<DV, ALLOC>::ElementProxy
347 DataVectorWithAlloc<DV, ALLOC>::operator[] (size_type n)
348 {
349  return to_element_proxy (this->m_pCont.begin() + n);
350 }
351 
352 
353 /**
354  * @brief Access an element, as an lvalue.
355  * @param n Array index to access.
356  * @return Proxy to the element at @a n.
357  *
358  * Will raise @c std::out_of_range if the index is out-of-bounds.
359  * Note that we return a proxy object rather than a reference;
360  * the proxy will handle deleting an owned element if it's assigned to.
361  */
362 template <class DV, class ALLOC>
363 inline
364 typename DataVectorWithAlloc<DV, ALLOC>::ElementProxy
365 DataVectorWithAlloc<DV, ALLOC>::at (size_type n)
366 {
367  if (n >= this->size())
368  throw std::out_of_range ("DataVector::at range check");
369  return to_element_proxy (this->m_pCont.begin() + n);
370 }
371 
372 
373 /**
374  * @brief Access the first element in the collection as an lvalue.
375  * @return Proxy to the first element in the collection.
376  *
377  * No checking is done to ensure that the container is not empty.
378  * Note that we return a proxy object rather than a reference;
379  * the proxy will handle deleting an owned element if it's assigned to.
380  */
381 template <class DV, class ALLOC>
382 inline
383 typename DataVectorWithAlloc<DV, ALLOC>::ElementProxy
384 DataVectorWithAlloc<DV, ALLOC>::front ()
385 {
386  return to_element_proxy (this->m_pCont.begin());
387 }
388 
389 
390 /**
391  * @brief Access the last element in the collection as an lvalue.
392  * @return Proxy to the last element in the collection.
393  *
394  * No checking is done to ensure that the container is not empty.
395  * Note that we return a proxy object rather than a reference;
396  * the proxy will handle deleting an owned element if it's assigned to.
397  */
398 template <class DV, class ALLOC>
399 inline
400 typename DataVectorWithAlloc<DV, ALLOC>::ElementProxy
401 DataVectorWithAlloc<DV, ALLOC>::back ()
402 {
403  return to_element_proxy (this->m_pCont.end()-1);
404 }
405 
406 
407 //=== Iterator creation.
408 
409 
410 /**
411  * @brief Return an @c iterator pointing at the beginning
412  * of the collection.
413  * @return An @c iterator.
414  *
415  * Note that dereferencing the iterator will yield a proxy rather
416  * than a reference; the proxy will handle deleting an owned element
417  * if it's assigned to.
418  */
419 template <class DV, class ALLOC>
420 inline
421 typename DataVectorWithAlloc<DV, ALLOC>::iterator
422 DataVectorWithAlloc<DV, ALLOC>::begin() noexcept
423 {
424  return to_my_iterator (DV::begin());
425 }
426 
427 
428 /**
429  * @brief Return an @c iterator pointing past the end
430  * of the collection.
431  * @return An @c iterator.
432  *
433  * Note that dereferencing the iterator will yield a proxy rather
434  * than a reference; the proxy will handle deleting an owned element
435  * if it's assigned to.
436  */
437 template <class DV, class ALLOC>
438 inline
439 typename DataVectorWithAlloc<DV, ALLOC>::iterator
440 DataVectorWithAlloc<DV, ALLOC>::end() noexcept
441 {
442  return to_my_iterator (DV::end());
443 }
444 
445 
446 /**
447  * @brief Return a @c reverse_iterator pointing past the end
448  * of the collection.
449  * @return A @c reverse_iterator.
450  *
451  * Note that dereferencing the iterator will yield a proxy rather
452  * than a reference; the proxy will handle deleting an owned element
453  * if it's assigned to.
454  */
455 template <class DV, class ALLOC>
456 inline
457 typename DataVectorWithAlloc<DV, ALLOC>::reverse_iterator
458 DataVectorWithAlloc<DV, ALLOC>::rbegin() noexcept
459 {
460  return reverse_iterator (to_my_iterator (DV::end()));
461 }
462 
463 
464 /**
465  * @brief Return a @c reverse_iterator pointing at the beginning
466  * of the collection.
467  * @return A @c reverse_iterator.
468  *
469  * Note that dereferencing the iterator will yield a proxy rather
470  * than a reference; the proxy will handle deleting an owned element
471  * if it's assigned to.
472  */
473 template <class DV, class ALLOC>
474 inline
475 typename DataVectorWithAlloc<DV, ALLOC>::reverse_iterator
476 DataVectorWithAlloc<DV, ALLOC>::rend() noexcept
477 {
478  return reverse_iterator (to_my_iterator (DV::begin()));
479 }
480 
481 
482 //=== Insertion operations.
483 
484 
485 /**
486  * @brief Add an element to the end of the collection.
487  * @param pElem The element to add to the collection.
488  *
489  * Note: this method may only be called using the most derived
490  * @c DataVector in the hierarchy.
491  *
492  * Returns the pushed pointer.
493  */
494 template <class DV, class ALLOC>
495 inline
496 typename DataVectorWithAlloc<DV, ALLOC>::value_type
497 DataVectorWithAlloc<DV, ALLOC>::push_back (Ptr pElem)
498 {
499  pElem.checkHeap (m_heap);
500  typename DV::value_type p = pElem.release();
501  DV::push_back (p);
502  return p;
503 }
504 
505 
506 /**
507  * @brief Add an element to the end of the collection.
508  * @param pElem The element to add to the collection.
509  *
510  * Note: this method may only be called using the most derived
511  * @c DataVector in the hierarchy.
512  *
513  * For @c DataVector, this is like the same as @c push_back, and
514  * it returns the pushed element.
515  * It's included just for interface compatibility with `std::vector`.
516  */
517 template <class DV, class ALLOC>
518 inline
519 typename DataVectorWithAlloc<DV, ALLOC>::value_type
520 DataVectorWithAlloc<DV, ALLOC>::emplace_back (Ptr pElem)
521 {
522  return push_back (std::move (pElem));
523 }
524 
525 
526 /**
527  * @brief Add a new element to the collection.
528  * @param position Iterator before which the element will be added.
529  * @param pElem The element to add to the collection.
530  * @return An iterator that points to the inserted data.
531  *
532  * The container's ownership policy will determine if it takes ownership
533  * of the new element.
534  *
535  * Note: this method may only be called using the most derived
536  * @c DataVector in the hierarchy.
537  */
538 template <class DV, class ALLOC>
539 inline
540 typename DataVectorWithAlloc<DV, ALLOC>::iterator
541 DataVectorWithAlloc<DV, ALLOC>::insert(iterator position, Ptr pElem)
542 {
543  pElem.checkHeap (m_heap);
544  return to_my_iterator
545  (DV::insert (to_base_iterator (position), pElem.release()));
546 }
547 
548 
549 /**
550  * @brief Add a new element to the collection.
551  * @param position Iterator before which the element will be added.
552  * @param pElem The element to add to the collection.
553  * @return An iterator that points to the inserted data.
554  *
555  * Note: this method may only be called using the most derived
556  * @c DataVector in the hierarchy.
557  *
558  * For @c DataVector, this is just the same as @c insert.
559  * It's included just for interface compatibility with `std::vector`.
560  */
561 template <class DV, class ALLOC>
562 inline
563 typename DataVectorWithAlloc<DV, ALLOC>::iterator
564 DataVectorWithAlloc<DV, ALLOC>::emplace(iterator position, Ptr pElem)
565 {
566  return this->insert (position, std::move(pElem));
567 }
568 
569 
570 //=== Erasure operations.
571 
572 
573 /**
574  * @brief Remove element at a given position.
575  * @param position Iterator pointing to the element to be removed.
576  * @return An iterator pointing to the next element (or @c end()).
577  *
578  * The pointed-to element will be deleted.
579  */
580 template <class DV, class ALLOC>
581 inline
582 typename DataVectorWithAlloc<DV, ALLOC>::iterator
583 DataVectorWithAlloc<DV, ALLOC>::erase(iterator position)
584 {
585  return to_my_iterator (DV::erase (to_base_iterator (position)));
586 }
587 
588 
589 /**
590  * @brief Remove a range of elements.
591  * @param first Iterator pointing to the first element to be removed.
592  * @param last Iterator pointing one past the last element to be removed.
593  * @return An iterator pointing to the element pointed to by @a last
594  * prior to erasing (or @c end()).
595  *
596  * The removed elements will be deleted.
597  */
598 template <class DV, class ALLOC>
599 inline
600 typename DataVectorWithAlloc<DV, ALLOC>::iterator
601 DataVectorWithAlloc<DV, ALLOC>::erase(iterator first, iterator last)
602 {
603  return to_my_iterator
604  (DV::erase (to_base_iterator (first),
605  to_base_iterator (last)));
606 }
607 
608 
609 /**
610  * @brief clear()
611  * @brief Erase all the elements in the collection.
612  *
613  * The removed elements will be deleted.
614  */
615 template <class DV, class ALLOC>
616 inline
617 void DataVectorWithAlloc<DV, ALLOC>::clear()
618 {
619  DV::clear();
620 }
621 
622 
623 //=== Swap and sort.
624 
625 
626 /**
627  * @brief Swap this collection with another.
628  * @param rhs The collection with which to swap.
629  *
630  * Ownership is swapped along with the collection content.
631  *
632  * Note: this method may only be called using the most-derived
633  * @c DataVector in the hierarchy. The @a rhs must also be
634  * referenced using the most-derived @c DataVector.
635  */
636 template <class DV, class ALLOC>
637 inline
638 void DataVectorWithAlloc<DV, ALLOC>::swap (DataVectorWithAlloc& rhs)
639 {
640  DV::swap (rhs);
641  std::swap (m_heap, rhs.m_heap);
642 }
643 
644 
645 /**
646  * @brief Swap the referents of two @c DataVector iterators.
647  * @param a The first iterator for the swap.
648  * @param b The second iterator for the swap.
649  *
650  * The iterators must both refer to the same container.
651  */
652 template <class DV, class ALLOC>
653 inline
654 void DataVectorWithAlloc<DV, ALLOC>::iter_swap (iterator a, iterator b)
655 {
656  if (a.container() != b.container()) {
657  throw SG::ExcBadIterSwap();
658  }
659  DV::iter_swap (to_base_iterator (a),
660  to_base_iterator (b));
661 }
662 
663 
664 //=== Non-standard operations.
665 
666 
667 /**
668  * @brief Swap one element out of the container.
669  * @param index Index of the element in the container to swap.
670  * @param newElem New element to put in the container.
671  * May be 0.
672  * @param oldElem Reference to receive the element removed from the
673  * container.
674  *
675  * Reference @a oldElem is initialized with element @a index of the
676  * collection (no bounds checking). Then element @a index is set
677  * to @c newElem.
678  *
679  * Note: this method may only be called using the most derived
680  * @c DataVector in the hierarchy.
681  */
682 template <class DV, class ALLOC>
683 inline
684 void
685 DataVectorWithAlloc<DV, ALLOC>::swapElement (size_type index,
686  Ptr newElem,
687  Ptr& oldElem)
688 {
689  newElem.checkHeap (m_heap);
690  typename DV::value_type pnew = newElem.release();
691  typename DV::value_type pold = nullptr;
692  DV::swapElement (index, pnew, pold);
693  oldElem = Ptr (pold, UPDeleter (*m_heap));
694 }
695 
696 
697 /**
698  * @brief Swap one element out of the container.
699  * @param pos The element in the container to swap.
700  * @param newElem New element to put in the container.
701  * May be 0.
702  * @param oldElem Reference to receive the element removed from the
703  * container.
704  *
705  * Reference @a oldElem is initialized with element @a pos of the
706  * collection (no bounds checking). Then element @a index is set
707  * to @c newElem.
708  *
709  * Note: this method may only be called using the most derived
710  * @c DataList in the hierarchy.
711  */
712 template <class DV, class ALLOC>
713 inline
714 void
715 DataVectorWithAlloc<DV, ALLOC>::swapElement (iterator pos,
716  Ptr newElem,
717  Ptr& oldElem)
718 {
719  newElem.checkHeap (m_heap);
720  typename DV::value_type pnew = newElem.release();
721  typename DV::value_type pold = nullptr;
722  DV::swapElement (to_base_iterator(pos), pnew, pold);
723  oldElem = Ptr (pold, UPDeleter (*m_heap));
724 }
725 
726 
727 /**
728  * @brief Return a pointer to this object, as a const @c DataVector.
729  */
730 template <class DV, class ALLOC>
731 inline
732 const DV*
733 DataVectorWithAlloc<DV, ALLOC>::asDataVector() const
734 {
735  return static_cast<const DV*>(this);
736 }
737 
738 
739 /**
740  * @brief Cast from a @c DataVector to a @c DataVectorWithAlloc.
741  * @param dv Pointer to object to cast.
742  *
743  * Return @c DV cast to a @c DataVectorWithAlloc.
744  */
745 template <class DV, class ALLOC>
746 const DataVectorWithAlloc<DV, ALLOC>*
747 DataVectorWithAlloc<DV, ALLOC>::fromDataVector (const DV* dv)
748 {
749  if (typeid (*dv) == typeid (DataVectorWithAlloc))
750  return static_cast<const DataVectorWithAlloc*> (dv);
751  return nullptr;
752 }
753 
754 
755 /**
756  * @brief Reset indices / reorder aux data after elements have been permuted.
757  * @param beg Start of the range of elements to process.
758  * @param end End of the range of elements to process.
759  */
760 template <class DV, class ALLOC>
761 inline
762 void DataVectorWithAlloc<DV, ALLOC>::resortAux (iterator beg, iterator end)
763 {
764  DV::resortAux (to_base_iterator(beg), to_base_iterator(end));
765 }
766 
767 
768 /**
769  * @brief Convert to @c AuxVectorBase.
770  *
771  * Needed to get @x AuxVectorBase from a @c DataVectorWithAlloc.
772  * Present in @c DataVector as well for consistency.
773  */
774 template <class DV, class ALLOC>
775 inline
776 const SG::AuxVectorBase& DataVectorWithAlloc<DV, ALLOC>::auxbase() const
777 {
778  return *this;
779 }
780 
781 
782 /**
783  * @brief Allocate a new vector element.
784  *
785  * Arguments will be forwarded to the element constructor.
786  */
787 template <class DV, class ALLOC>
788 template <class... Args>
789 typename DataVectorWithAlloc<DV, ALLOC>::Ptr
790 DataVectorWithAlloc<DV, ALLOC>::allocate (Args&&... args)
791 {
792  typename elt_allocator_type::pointer p = m_heap->allocate(1);
793  try {
794  m_heap->construct (p, std::forward<Args>(args)...);
795  }
796  catch (...) {
797  m_heap->deallocate (p, 1);
798  throw;
799  }
800  return Ptr (p, UPDeleter (*m_heap));
801 }
802 
803 
804 //=== Relational operators.
805 
806 
807 /**
808  * @brief Vector ordering relation.
809  * @param b A @c DataVectorWithAlloc of the same type as @a *this.
810  * @return True iff @a *this is lexicographically less than @a b.
811  *
812  * This is a total ordering relation. It is linear in the size of the
813  * vectors. Comparisons are done on the pointer values of the elements.
814  *
815  * See @c std::lexicographical_compare() for how the determination is made.
816  */
817 template <class DV, class ALLOC>
818 inline
819 bool DataVectorWithAlloc<DV, ALLOC>::operator< (const DataVectorWithAlloc& b) const
820 {
821  return static_cast<const DV&>(*this) < static_cast<const DV&>(b);
822 }
823 
824 
825 /// Based on operator<
826 template <class DV, class ALLOC>
827 inline
828 bool DataVectorWithAlloc<DV, ALLOC>::operator> (const DataVectorWithAlloc& b) const
829 {
830  return static_cast<const DV&>(*this) > static_cast<const DV&>(b);
831 }
832 
833 
834 /// Based on operator<
835 template <class DV, class ALLOC>
836 inline
837 bool DataVectorWithAlloc<DV, ALLOC>::operator<= (const DataVectorWithAlloc& b) const
838 {
839  return static_cast<const DV&>(*this) <= static_cast<const DV&>(b);
840 }
841 
842 
843 /// Based on operator<
844 template <class DV, class ALLOC>
845 inline
846 bool DataVectorWithAlloc<DV, ALLOC>::operator>= (const DataVectorWithAlloc& b) const
847 {
848  return static_cast<const DV&>(*this) >= static_cast<const DV&>(b);
849 }
850 
851 
852 /**
853  * @brief Vector equality comparison.
854  * @param b A @c DataVectorWithAlloc of the same type as @a *this.
855  * @return True iff the size and elements of the vectors are equal.
856  *
857  * This is an equivalence relation. It is linear in the size of the
858  * vectors. Vectors are considered equivalent if their sizes are equal,
859  * and if corresponding elements compare equal.
860  */
861 template <class DV, class ALLOC>
862 inline
863 bool DataVectorWithAlloc<DV, ALLOC>::operator== (const DataVectorWithAlloc& b) const
864 {
865  return static_cast<const DV&>(*this) == static_cast<const DV&>(b);
866 }
867 
868 
869 /// Based on operator==
870 template <class DV, class ALLOC>
871 inline
872 bool DataVectorWithAlloc<DV, ALLOC>::operator!= (const DataVectorWithAlloc& b) const
873 {
874  return static_cast<const DV&>(*this) != static_cast<const DV&>(b);
875 }
876 
877 
878 //=== Private helpers.
879 
880 
881 /**
882  * @brief Handle element assignment.
883  * @param pos Position in the container to assign.
884  * @param newElem The new element to assign.
885  *
886  * Auxiliary data are copied if appropriate.
887  */
888 template <class DV, class ALLOC>
889 inline
890 void
891 DataVectorWithAlloc<DV, ALLOC>::assignElement (typename BaseContainer::iterator pos,
892  Ptr newElem)
893 {
894  newElem.checkHeap (m_heap);
895  DV::assignElement (pos, newElem.release());
896 }
897 
898 
899 /**
900  * @brief Convert a @c DataVectorWithAlloc::iterator to an iterator
901  * of the base @c DataVector.
902  * @param it The @c DataVectorWithAlloc::iterator to convert.
903  */
904 template <class DV, class ALLOC>
905 inline
906 typename DV::iterator
907 DataVectorWithAlloc<DV, ALLOC>::to_base_iterator (iterator it)
908 {
909  return typename DV::iterator (it.base(), it.container());
910 }
911 
912 
913 /**
914  * @brief Convert an iterator of the base @c DataVector to
915  * a @c DataVectorWithAlloc::iterator.
916  * @param it The base @c DataVector iterator to convert.
917  */
918 template <class DV, class ALLOC>
919 inline
920 typename DataVectorWithAlloc<DV, ALLOC>::iterator
921 DataVectorWithAlloc<DV, ALLOC>::to_my_iterator (typename DV::iterator it)
922 {
923  return iterator (it.base(), this);
924 }
925 
926 
927 /**
928  * @brief Convert an iterator of the base @c vector to
929  * an @c ElementProxy for the @c DataVectorWithAlloc.
930  * @param it The base @c vector iterator to convert.
931  */
932 template <class DV, class ALLOC>
933 inline
934 typename DataVectorWithAlloc<DV, ALLOC>::ElementProxy
935 DataVectorWithAlloc<DV, ALLOC>::to_element_proxy (typename BaseContainer::iterator i)
936 {
937  return ElementProxy (i, this);
938 }
939 
940 
941 template <class DV, class ALLOC>
942 DataVectorWithAlloc<DV, ALLOC>::HeapDeleter::HeapDeleter (elt_allocator_type&& heap)
943  : m_heap (std::move (heap))
944 {
945 }
946 
947 
948 template <class DV, class ALLOC>
949 typename DataVectorWithAlloc<DV, ALLOC>::elt_allocator_type&
950 DataVectorWithAlloc<DV, ALLOC>::HeapDeleter::heap() noexcept
951 {
952  return m_heap;
953 }
954 
955 
956 template <class DV, class ALLOC>
957 void DataVectorWithAlloc<DV, ALLOC>::HeapDeleter::doDelete (value_type p)
958 {
959  if (p) {
960  using base_value_type_nc = std::remove_const_t<base_value_type>;
961  base_value_type_nc* pp ATLAS_THREAD_SAFE = const_cast<base_value_type_nc*>(DV::do_cast_nc (p));
962  m_heap.destroy (pp);
963  m_heap.deallocate (pp, 1);
964  }
965 }
966 
967 
968 template <class DV, class ALLOC>
969 void DataVectorWithAlloc<DV, ALLOC>::HeapDeleter::doDelete
970  (typename PtrVector::iterator first,
971  typename PtrVector::iterator last)
972 {
973  for (; first != last; ++first) {
974  if (*first) {
975  using base_value_type_nc = std::remove_const_t<base_value_type>;
976  base_value_type_nc* pp ATLAS_THREAD_SAFE = const_cast<base_value_type_nc*>(DV::do_cast_nc (*first));
977  m_heap.destroy (pp);
978  m_heap.deallocate (pp, 1);
979  }
980  }
981 }