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