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