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 Create and add a number of new elements to the end of the container.
508  * @param n The number of new elements to add.
509  * The elements will be created by calling allocate().
510  *
511  * Note: this method may only be called using the most derived
512  * @c DataVector in the hierarchy.
513  *
514  * Returns the original size of the vector.
515  */
516 template <class DV, class ALLOC>
517 inline
518 auto
519 DataVectorWithAlloc<DV, ALLOC>::push_new (size_type n) ->size_type
520 {
521  auto alloc = [&]() {
522  typename elt_allocator_type::pointer p = m_heap->allocate(1);
523  // Note: not protected against exceptions.
524  m_heap->construct (p);
525  return p;
526  };
527  return DV::push_new (n, alloc);
528 }
529 
530 
531 /**
532  * @brief Add an element to the end of the collection.
533  * @param pElem The element to add to the collection.
534  *
535  * Note: this method may only be called using the most derived
536  * @c DataVector in the hierarchy.
537  *
538  * For @c DataVector, this is like the same as @c push_back, and
539  * it returns the pushed element.
540  * It's included just for interface compatibility with `std::vector`.
541  */
542 template <class DV, class ALLOC>
543 inline
544 typename DataVectorWithAlloc<DV, ALLOC>::value_type
545 DataVectorWithAlloc<DV, ALLOC>::emplace_back (Ptr pElem)
546 {
547  return push_back (std::move (pElem));
548 }
549 
550 
551 /**
552  * @brief Add a new element to the collection.
553  * @param position Iterator before which the element will be added.
554  * @param pElem The element to add to the collection.
555  * @return An iterator that points to the inserted data.
556  *
557  * The container's ownership policy will determine if it takes ownership
558  * of the new element.
559  *
560  * Note: this method may only be called using the most derived
561  * @c DataVector in the hierarchy.
562  */
563 template <class DV, class ALLOC>
564 inline
565 typename DataVectorWithAlloc<DV, ALLOC>::iterator
566 DataVectorWithAlloc<DV, ALLOC>::insert(iterator position, Ptr pElem)
567 {
568  pElem.checkHeap (m_heap);
569  return to_my_iterator
570  (DV::insert (to_base_iterator (position), pElem.release()));
571 }
572 
573 
574 /**
575  * @brief Add a new element to the collection.
576  * @param position Iterator before which the element will be added.
577  * @param pElem The element to add to the collection.
578  * @return An iterator that points to the inserted data.
579  *
580  * Note: this method may only be called using the most derived
581  * @c DataVector in the hierarchy.
582  *
583  * For @c DataVector, this is just the same as @c insert.
584  * It's included just for interface compatibility with `std::vector`.
585  */
586 template <class DV, class ALLOC>
587 inline
588 typename DataVectorWithAlloc<DV, ALLOC>::iterator
589 DataVectorWithAlloc<DV, ALLOC>::emplace(iterator position, Ptr pElem)
590 {
591  return this->insert (position, std::move(pElem));
592 }
593 
594 
595 //=== Erasure operations.
596 
597 
598 /**
599  * @brief Remove element at a given position.
600  * @param position Iterator pointing to the element to be removed.
601  * @return An iterator pointing to the next element (or @c end()).
602  *
603  * The pointed-to element will be deleted.
604  */
605 template <class DV, class ALLOC>
606 inline
607 typename DataVectorWithAlloc<DV, ALLOC>::iterator
608 DataVectorWithAlloc<DV, ALLOC>::erase(iterator position)
609 {
610  return to_my_iterator (DV::erase (to_base_iterator (position)));
611 }
612 
613 
614 /**
615  * @brief Remove a range of elements.
616  * @param first Iterator pointing to the first element to be removed.
617  * @param last Iterator pointing one past the last element to be removed.
618  * @return An iterator pointing to the element pointed to by @a last
619  * prior to erasing (or @c end()).
620  *
621  * The removed elements will be deleted.
622  */
623 template <class DV, class ALLOC>
624 inline
625 typename DataVectorWithAlloc<DV, ALLOC>::iterator
626 DataVectorWithAlloc<DV, ALLOC>::erase(iterator first, iterator last)
627 {
628  return to_my_iterator
629  (DV::erase (to_base_iterator (first),
630  to_base_iterator (last)));
631 }
632 
633 
634 /**
635  * @brief clear()
636  * @brief Erase all the elements in the collection.
637  *
638  * The removed elements will be deleted.
639  */
640 template <class DV, class ALLOC>
641 inline
642 void DataVectorWithAlloc<DV, ALLOC>::clear()
643 {
644  DV::clear();
645 }
646 
647 
648 //=== Swap and sort.
649 
650 
651 /**
652  * @brief Swap this collection with another.
653  * @param rhs The collection with which to swap.
654  *
655  * Ownership is swapped along with the collection content.
656  *
657  * Note: this method may only be called using the most-derived
658  * @c DataVector in the hierarchy. The @a rhs must also be
659  * referenced using the most-derived @c DataVector.
660  */
661 template <class DV, class ALLOC>
662 inline
663 void DataVectorWithAlloc<DV, ALLOC>::swap (DataVectorWithAlloc& rhs)
664 {
665  DV::swap (rhs);
666  std::swap (m_heap, rhs.m_heap);
667 }
668 
669 
670 /**
671  * @brief Swap the referents of two @c DataVector iterators.
672  * @param a The first iterator for the swap.
673  * @param b The second iterator for the swap.
674  *
675  * The iterators must both refer to the same container.
676  */
677 template <class DV, class ALLOC>
678 inline
679 void DataVectorWithAlloc<DV, ALLOC>::iter_swap (iterator a, iterator b)
680 {
681  if (a.container() != b.container()) {
682  throw SG::ExcBadIterSwap();
683  }
684  DV::iter_swap (to_base_iterator (a),
685  to_base_iterator (b));
686 }
687 
688 
689 //=== Non-standard operations.
690 
691 
692 /**
693  * @brief Swap one element out of the container.
694  * @param index Index of the element in the container to swap.
695  * @param newElem New element to put in the container.
696  * May be 0.
697  * @param oldElem Reference to receive the element removed from the
698  * container.
699  *
700  * Reference @a oldElem is initialized with element @a index of the
701  * collection (no bounds checking). Then element @a index is set
702  * to @c newElem.
703  *
704  * Note: this method may only be called using the most derived
705  * @c DataVector in the hierarchy.
706  */
707 template <class DV, class ALLOC>
708 inline
709 void
710 DataVectorWithAlloc<DV, ALLOC>::swapElement (size_type index,
711  Ptr newElem,
712  Ptr& oldElem)
713 {
714  newElem.checkHeap (m_heap);
715  typename DV::value_type pnew = newElem.release();
716  typename DV::value_type pold = nullptr;
717  DV::swapElement (index, pnew, pold);
718  oldElem = Ptr (pold, UPDeleter (*m_heap));
719 }
720 
721 
722 /**
723  * @brief Swap one element out of the container.
724  * @param pos The element in the container to swap.
725  * @param newElem New element to put in the container.
726  * May be 0.
727  * @param oldElem Reference to receive the element removed from the
728  * container.
729  *
730  * Reference @a oldElem is initialized with element @a pos of the
731  * collection (no bounds checking). Then element @a index is set
732  * to @c newElem.
733  *
734  * Note: this method may only be called using the most derived
735  * @c DataList in the hierarchy.
736  */
737 template <class DV, class ALLOC>
738 inline
739 void
740 DataVectorWithAlloc<DV, ALLOC>::swapElement (iterator pos,
741  Ptr newElem,
742  Ptr& oldElem)
743 {
744  newElem.checkHeap (m_heap);
745  typename DV::value_type pnew = newElem.release();
746  typename DV::value_type pold = nullptr;
747  DV::swapElement (to_base_iterator(pos), pnew, pold);
748  oldElem = Ptr (pold, UPDeleter (*m_heap));
749 }
750 
751 
752 /**
753  * @brief Return a pointer to this object, as a const @c DataVector.
754  */
755 template <class DV, class ALLOC>
756 inline
757 const DV*
758 DataVectorWithAlloc<DV, ALLOC>::asDataVector() const
759 {
760  return static_cast<const DV*>(this);
761 }
762 
763 
764 /**
765  * @brief Cast from a @c DataVector to a @c DataVectorWithAlloc.
766  * @param dv Pointer to object to cast.
767  *
768  * Return @c DV cast to a @c DataVectorWithAlloc.
769  */
770 template <class DV, class ALLOC>
771 const DataVectorWithAlloc<DV, ALLOC>*
772 DataVectorWithAlloc<DV, ALLOC>::fromDataVector (const DV* dv)
773 {
774  if (typeid (*dv) == typeid (DataVectorWithAlloc))
775  return static_cast<const DataVectorWithAlloc*> (dv);
776  return nullptr;
777 }
778 
779 
780 /**
781  * @brief Reset indices / reorder aux data after elements have been permuted.
782  * @param beg Start of the range of elements to process.
783  * @param end End of the range of elements to process.
784  */
785 template <class DV, class ALLOC>
786 inline
787 void DataVectorWithAlloc<DV, ALLOC>::resortAux (iterator beg, iterator end)
788 {
789  DV::resortAux (to_base_iterator(beg), to_base_iterator(end));
790 }
791 
792 
793 /**
794  * @brief Convert to @c AuxVectorBase.
795  *
796  * Needed to get @x AuxVectorBase from a @c DataVectorWithAlloc.
797  * Present in @c DataVector as well for consistency.
798  */
799 template <class DV, class ALLOC>
800 inline
801 const SG::AuxVectorBase& DataVectorWithAlloc<DV, ALLOC>::auxbase() const
802 {
803  return *this;
804 }
805 
806 
807 /**
808  * @brief Allocate a new vector element.
809  *
810  * Arguments will be forwarded to the element constructor.
811  */
812 template <class DV, class ALLOC>
813 template <class... Args>
814 typename DataVectorWithAlloc<DV, ALLOC>::Ptr
815 DataVectorWithAlloc<DV, ALLOC>::allocate (Args&&... args)
816 {
817  typename elt_allocator_type::pointer p = m_heap->allocate(1);
818  try {
819  m_heap->construct (p, std::forward<Args>(args)...);
820  }
821  catch (...) {
822  m_heap->deallocate (p, 1);
823  throw;
824  }
825  return Ptr (p, UPDeleter (*m_heap));
826 }
827 
828 
829 //=== Relational operators.
830 
831 
832 /**
833  * @brief Vector ordering relation.
834  * @param b A @c DataVectorWithAlloc of the same type as @a *this.
835  * @return True iff @a *this is lexicographically less than @a b.
836  *
837  * This is a total ordering relation. It is linear in the size of the
838  * vectors. Comparisons are done on the pointer values of the elements.
839  *
840  * See @c std::lexicographical_compare() for how the determination is made.
841  */
842 template <class DV, class ALLOC>
843 inline
844 bool DataVectorWithAlloc<DV, ALLOC>::operator< (const DataVectorWithAlloc& b) const
845 {
846  return static_cast<const DV&>(*this) < static_cast<const DV&>(b);
847 }
848 
849 
850 /// Based on operator<
851 template <class DV, class ALLOC>
852 inline
853 bool DataVectorWithAlloc<DV, ALLOC>::operator> (const DataVectorWithAlloc& b) const
854 {
855  return static_cast<const DV&>(*this) > static_cast<const DV&>(b);
856 }
857 
858 
859 /// Based on operator<
860 template <class DV, class ALLOC>
861 inline
862 bool DataVectorWithAlloc<DV, ALLOC>::operator<= (const DataVectorWithAlloc& b) const
863 {
864  return static_cast<const DV&>(*this) <= static_cast<const DV&>(b);
865 }
866 
867 
868 /// Based on operator<
869 template <class DV, class ALLOC>
870 inline
871 bool DataVectorWithAlloc<DV, ALLOC>::operator>= (const DataVectorWithAlloc& b) const
872 {
873  return static_cast<const DV&>(*this) >= static_cast<const DV&>(b);
874 }
875 
876 
877 /**
878  * @brief Vector equality comparison.
879  * @param b A @c DataVectorWithAlloc of the same type as @a *this.
880  * @return True iff the size and elements of the vectors are equal.
881  *
882  * This is an equivalence relation. It is linear in the size of the
883  * vectors. Vectors are considered equivalent if their sizes are equal,
884  * and if corresponding elements compare equal.
885  */
886 template <class DV, class ALLOC>
887 inline
888 bool DataVectorWithAlloc<DV, ALLOC>::operator== (const DataVectorWithAlloc& b) const
889 {
890  return static_cast<const DV&>(*this) == static_cast<const DV&>(b);
891 }
892 
893 
894 /// Based on operator==
895 template <class DV, class ALLOC>
896 inline
897 bool DataVectorWithAlloc<DV, ALLOC>::operator!= (const DataVectorWithAlloc& b) const
898 {
899  return static_cast<const DV&>(*this) != static_cast<const DV&>(b);
900 }
901 
902 
903 //=== Private helpers.
904 
905 
906 /**
907  * @brief Handle element assignment.
908  * @param pos Position in the container to assign.
909  * @param newElem The new element to assign.
910  *
911  * Auxiliary data are copied if appropriate.
912  */
913 template <class DV, class ALLOC>
914 inline
915 void
916 DataVectorWithAlloc<DV, ALLOC>::assignElement (typename BaseContainer::iterator pos,
917  Ptr newElem)
918 {
919  newElem.checkHeap (m_heap);
920  DV::assignElement (pos, newElem.release());
921 }
922 
923 
924 /**
925  * @brief Convert a @c DataVectorWithAlloc::iterator to an iterator
926  * of the base @c DataVector.
927  * @param it The @c DataVectorWithAlloc::iterator to convert.
928  */
929 template <class DV, class ALLOC>
930 inline
931 typename DV::iterator
932 DataVectorWithAlloc<DV, ALLOC>::to_base_iterator (iterator it)
933 {
934  return typename DV::iterator (it.base(), it.container());
935 }
936 
937 
938 /**
939  * @brief Convert an iterator of the base @c DataVector to
940  * a @c DataVectorWithAlloc::iterator.
941  * @param it The base @c DataVector iterator to convert.
942  */
943 template <class DV, class ALLOC>
944 inline
945 typename DataVectorWithAlloc<DV, ALLOC>::iterator
946 DataVectorWithAlloc<DV, ALLOC>::to_my_iterator (typename DV::iterator it)
947 {
948  return iterator (it.base(), this);
949 }
950 
951 
952 /**
953  * @brief Convert an iterator of the base @c vector to
954  * an @c ElementProxy for the @c DataVectorWithAlloc.
955  * @param it The base @c vector iterator to convert.
956  */
957 template <class DV, class ALLOC>
958 inline
959 typename DataVectorWithAlloc<DV, ALLOC>::ElementProxy
960 DataVectorWithAlloc<DV, ALLOC>::to_element_proxy (typename BaseContainer::iterator i)
961 {
962  return ElementProxy (i, this);
963 }
964 
965 
966 template <class DV, class ALLOC>
967 DataVectorWithAlloc<DV, ALLOC>::HeapDeleter::HeapDeleter (elt_allocator_type&& heap)
968  : m_heap (std::move (heap))
969 {
970 }
971 
972 
973 template <class DV, class ALLOC>
974 typename DataVectorWithAlloc<DV, ALLOC>::elt_allocator_type&
975 DataVectorWithAlloc<DV, ALLOC>::HeapDeleter::heap() noexcept
976 {
977  return m_heap;
978 }
979 
980 
981 template <class DV, class ALLOC>
982 void DataVectorWithAlloc<DV, ALLOC>::HeapDeleter::doDelete (value_type p)
983 {
984  if (p) {
985  using base_value_type_nc = std::remove_const_t<base_value_type>;
986  base_value_type_nc* pp ATLAS_THREAD_SAFE = const_cast<base_value_type_nc*>(DV::do_cast_nc (p));
987  m_heap.destroy (pp);
988  m_heap.deallocate (pp, 1);
989  }
990 }
991 
992 
993 template <class DV, class ALLOC>
994 void DataVectorWithAlloc<DV, ALLOC>::HeapDeleter::doDelete
995  (typename PtrVector::iterator first,
996  typename PtrVector::iterator last)
997 {
998  for (; first != last; ++first) {
999  if (*first) {
1000  using base_value_type_nc = std::remove_const_t<base_value_type>;
1001  base_value_type_nc* pp ATLAS_THREAD_SAFE = const_cast<base_value_type_nc*>(DV::do_cast_nc (*first));
1002  m_heap.destroy (pp);
1003  m_heap.deallocate (pp, 1);
1004  }
1005  }
1006 }