ATLAS Offline Software
Loading...
Searching...
No Matches
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
19template <class DV, class ALLOC>
20inline
21DataVectorWithAlloc<DV, ALLOC>::UPDeleter::UPDeleter() noexcept
22 : m_heap (nullptr)
23{
24}
25
26
27template <class DV, class ALLOC>
28inline
29DataVectorWithAlloc<DV, ALLOC>::UPDeleter::UPDeleter (elt_allocator_type& heap) noexcept
30 : m_heap (&heap)
31{
32}
33
34
35template <class DV, class ALLOC>
36inline
37void 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
46template <class DV, class ALLOC>
47inline
48const typename DataVectorWithAlloc<DV, ALLOC>::elt_allocator_type*
49DataVectorWithAlloc<DV, ALLOC>::UPDeleter::heap() const noexcept
50{
51 return m_heap;
52}
53
54
55template <class DV, class ALLOC>
56inline
57DataVectorWithAlloc<DV, ALLOC>::Ptr::Ptr (std::nullptr_t) noexcept
58{
59}
60
61
62template <class DV, class ALLOC>
63inline
64DataVectorWithAlloc<DV, ALLOC>::Ptr::operator bool() const noexcept
65{
66 return static_cast<bool>(m_ptr);
67}
68
69
70template <class DV, class ALLOC>
71inline
72typename DataVectorWithAlloc<DV, ALLOC>::Ptr&
73DataVectorWithAlloc<DV, ALLOC>::Ptr::operator= (std::nullptr_t) noexcept
74{
75 m_ptr = nullptr;
76 return *this;
77}
78
79
80template <class DV, class ALLOC>
81inline
82void DataVectorWithAlloc<DV, ALLOC>::Ptr::swap (Ptr& other) noexcept
83{
84 m_ptr.swap (other.m_ptr);
85}
86
87
88template <class DV, class ALLOC>
89inline
90typename DataVectorWithAlloc<DV, ALLOC>::Ptr::pointer
91DataVectorWithAlloc<DV, ALLOC>::Ptr::get() const noexcept
92{
93 return m_ptr.get();
94}
95
96
97template <class DV, class ALLOC>
98inline
99typename std::add_lvalue_reference<typename DV::base_value_type>::type
100DataVectorWithAlloc<DV, ALLOC>::Ptr::operator*() const
101{
102 return *m_ptr;
103}
104
105
106template <class DV, class ALLOC>
107inline
108typename DataVectorWithAlloc<DV, ALLOC>::Ptr::pointer
109DataVectorWithAlloc<DV, ALLOC>::Ptr::operator->() const noexcept
110{
111 return m_ptr.get();
112}
113
114
115template <class DV, class ALLOC>
116inline
117bool
118DataVectorWithAlloc<DV, ALLOC>::Ptr::operator== (const Ptr& other) const noexcept
119{
120 return m_ptr == other.m_ptr;
121}
122
123
124template <class DV, class ALLOC>
125inline
126bool
127DataVectorWithAlloc<DV, ALLOC>::Ptr::operator< (const Ptr& other) const noexcept
128{
129 return m_ptr < other.m_ptr;
130}
131
132
133template <class DV, class ALLOC>
134inline
135bool
136DataVectorWithAlloc<DV, ALLOC>::Ptr::operator== (std::nullptr_t) const noexcept
137{
138 return m_ptr == nullptr;
139}
140
141
142template <class DV, class ALLOC>
143inline
144bool
145DataVectorWithAlloc<DV, ALLOC>::Ptr::operator!= (std::nullptr_t) const noexcept
146{
147 return m_ptr != nullptr;
148}
149
150
151template <class DV, class ALLOC>
152inline
153DataVectorWithAlloc<DV, ALLOC>::Ptr::Ptr (pointer p, UPDeleter&& d) noexcept
154 : m_ptr (p, std::move(d))
155{
156}
157
158
159template <class DV, class ALLOC>
160inline
161typename DataVectorWithAlloc<DV, ALLOC>::Ptr::pointer
162DataVectorWithAlloc<DV, ALLOC>::Ptr::release() noexcept
163{
164 return m_ptr.release();
165}
166
167
168template <class DV, class ALLOC>
169inline
170void
171DataVectorWithAlloc<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 */
187template <class DV, class ALLOC>
188DataVectorWithAlloc<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 */
205template <class DV, class ALLOC>
206DataVectorWithAlloc<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 */
226template <class DV, class ALLOC>
227DataVectorWithAlloc<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 */
247template <class DV, class ALLOC>
248DataVectorWithAlloc<DV, ALLOC>&
249DataVectorWithAlloc<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 */
265template <class DV, class ALLOC>
266DataVectorWithAlloc<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 */
282template <class DV, class ALLOC>
283inline
284const typename DataVectorWithAlloc<DV, ALLOC>::elt_allocator_type&
285DataVectorWithAlloc<DV, ALLOC>::elt_allocator() const
286{
287 return *m_heap;
288}
289
290
291/**
292 * @brief Return the underlying allocator.
293 */
294template <class DV, class ALLOC>
295inline
296typename DataVectorWithAlloc<DV, ALLOC>::elt_allocator_type&
297DataVectorWithAlloc<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 */
312template <class DV, class ALLOC>
313void 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 */
325template <class DV, class ALLOC>
326void 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 */
345template <class DV, class ALLOC>
346inline
347typename DataVectorWithAlloc<DV, ALLOC>::ElementProxy
348DataVectorWithAlloc<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 */
363template <class DV, class ALLOC>
364inline
365typename DataVectorWithAlloc<DV, ALLOC>::ElementProxy
366DataVectorWithAlloc<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 */
382template <class DV, class ALLOC>
383inline
384typename DataVectorWithAlloc<DV, ALLOC>::ElementProxy
385DataVectorWithAlloc<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 */
399template <class DV, class ALLOC>
400inline
401typename DataVectorWithAlloc<DV, ALLOC>::ElementProxy
402DataVectorWithAlloc<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 */
420template <class DV, class ALLOC>
421inline
422typename DataVectorWithAlloc<DV, ALLOC>::iterator
423DataVectorWithAlloc<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 */
438template <class DV, class ALLOC>
439inline
440typename DataVectorWithAlloc<DV, ALLOC>::iterator
441DataVectorWithAlloc<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 */
456template <class DV, class ALLOC>
457inline
458typename DataVectorWithAlloc<DV, ALLOC>::reverse_iterator
459DataVectorWithAlloc<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 */
474template <class DV, class ALLOC>
475inline
476typename DataVectorWithAlloc<DV, ALLOC>::reverse_iterator
477DataVectorWithAlloc<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 */
495template <class DV, class ALLOC>
496inline
497typename DataVectorWithAlloc<DV, ALLOC>::value_type
498DataVectorWithAlloc<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 */
517template <class DV, class ALLOC>
518inline
519auto
520DataVectorWithAlloc<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 */
543template <class DV, class ALLOC>
544inline
545typename DataVectorWithAlloc<DV, ALLOC>::value_type
546DataVectorWithAlloc<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 */
564template <class DV, class ALLOC>
565inline
566typename DataVectorWithAlloc<DV, ALLOC>::iterator
567DataVectorWithAlloc<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 */
587template <class DV, class ALLOC>
588inline
589typename DataVectorWithAlloc<DV, ALLOC>::iterator
590DataVectorWithAlloc<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 */
606template <class DV, class ALLOC>
607inline
608typename DataVectorWithAlloc<DV, ALLOC>::iterator
609DataVectorWithAlloc<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 */
624template <class DV, class ALLOC>
625inline
626typename DataVectorWithAlloc<DV, ALLOC>::iterator
627DataVectorWithAlloc<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 */
641template <class DV, class ALLOC>
642inline
643void 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 */
662template <class DV, class ALLOC>
663inline
664void 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 */
678template <class DV, class ALLOC>
679inline
680void 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 */
708template <class DV, class ALLOC>
709inline
710void
711DataVectorWithAlloc<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 */
738template <class DV, class ALLOC>
739inline
740void
741DataVectorWithAlloc<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 */
756template <class DV, class ALLOC>
757inline
758const DV*
759DataVectorWithAlloc<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 */
771template <class DV, class ALLOC>
772const DataVectorWithAlloc<DV, ALLOC>*
773DataVectorWithAlloc<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 */
786template <class DV, class ALLOC>
787inline
788void 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 */
800template <class DV, class ALLOC>
801inline
802const 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 */
813template <class DV, class ALLOC>
814template <class... Args>
815typename DataVectorWithAlloc<DV, ALLOC>::Ptr
816DataVectorWithAlloc<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 */
843template <class DV, class ALLOC>
844inline
845bool 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<
852template <class DV, class ALLOC>
853inline
854bool 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<
861template <class DV, class ALLOC>
862inline
863bool 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<
870template <class DV, class ALLOC>
871inline
872bool 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 */
887template <class DV, class ALLOC>
888inline
889bool 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==
896template <class DV, class ALLOC>
897inline
898bool 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 */
914template <class DV, class ALLOC>
915inline
916void
917DataVectorWithAlloc<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 */
930template <class DV, class ALLOC>
931inline
932typename DV::iterator
933DataVectorWithAlloc<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 */
944template <class DV, class ALLOC>
945inline
946typename DataVectorWithAlloc<DV, ALLOC>::iterator
947DataVectorWithAlloc<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 */
958template <class DV, class ALLOC>
959inline
960typename DataVectorWithAlloc<DV, ALLOC>::ElementProxy
961DataVectorWithAlloc<DV, ALLOC>::to_element_proxy (typename BaseContainer::iterator i)
962{
963 return ElementProxy (i, this);
964}
965
966
967template <class DV, class ALLOC>
968DataVectorWithAlloc<DV, ALLOC>::HeapDeleter::HeapDeleter (elt_allocator_type&& heap)
969 : m_heap (std::move (heap))
970{
971}
972
973
974template <class DV, class ALLOC>
975typename DataVectorWithAlloc<DV, ALLOC>::elt_allocator_type&
976DataVectorWithAlloc<DV, ALLOC>::HeapDeleter::heap() noexcept
977{
978 return m_heap;
979}
980
981
982template <class DV, class ALLOC>
983void 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
994template <class DV, class ALLOC>
995void 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}