2 * Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration.
5 * @file AthContainers/tools/JaggedVecVectorFactory.icc
6 * @author scott snyder <snyder@bnl.gov>
8 * @brief Factory object that creates vectors using @c AuxTypeVector,
9 * specialized for JaggedVec.
13 #include "AthContainers/tools/AuxTypeVector.h"
14 #include "AthContainers/AuxTypeRegistry.h"
15 #include "AthContainers/exceptions.h"
22 * @brief Create a vector object of this type.
23 * @param auxid ID for the variable being created.
24 * @param size Initial size of the new vector.
25 * @param capacity Initial capacity of the new vector.
26 * @param isLinked True if this variable is linked from another one.
29 template <class T, class ALLOC>
30 std::unique_ptr<IAuxTypeVector>
31 JaggedVecVectorFactory<T, ALLOC>::create (SG::auxid_t auxid,
32 size_t size, size_t capacity,
33 [[maybe_unused]] bool isLinked) const
36 const AuxTypeRegistry& r = AuxTypeRegistry::instance();
37 auxid_t linked_id = r.linkedVariable (auxid);
39 using linkedAlloc = typename std::allocator_traits<ALLOC>::template rebind_alloc<T>;
41 std::make_unique<AuxTypeVector<T, linkedAlloc> > (linked_id, 0, 0, true);
42 return std::make_unique<AuxTypeVector_t> (auxid, size, capacity,
43 std::move (linkedVec));
48 * @brief Create a vector object of this type from a data blob.
49 * @param auxid ID for the variable being created.
50 * @param data The vector object.
51 * @param linkedVector The interface for another variable linked to this one.
52 * (We do not take ownership.)
53 * @param isPacked If true, @c data is a @c PackedContainer.
54 * @param ownFlag If true, the newly-created IAuxTypeVector object
55 * will take ownership of @c data.
56 * @param isLinked True if this variable is linked from another one.
58 * @c data should be a pointer to a
59 * std::vector<SG::JaggedVec<CONT>, ALLOC<...> > object obtained with new.
60 * For this method, isPacked and isLinked must both be false.
62 template <class CONT, class ALLOC>
63 std::unique_ptr<IAuxTypeVector>
64 JaggedVecVectorFactory<CONT, ALLOC>::createFromData (SG::auxid_t auxid,
66 IAuxTypeVector* linkedVector,
67 [[maybe_unused]] bool isPacked,
69 [[maybe_unused]] bool isLinked) const
71 assert (!isPacked && !isLinked && linkedVector != nullptr);
72 using Holder = SG::JaggedVecVectorHolder<CONT, ALLOC>;
73 using vector_type = typename Holder::vector_type;
74 return std::make_unique<Holder>
75 (auxid, reinterpret_cast<vector_type*>(data), linkedVector, ownFlag);
80 * @brief Copy elements between vectors.
81 * @param auxid The aux data item being operated on.
82 * @param dst Container for the destination vector.
83 * @param dst_index Index of the first destination element in the vector.
84 * @param src Container for the source vector.
85 * @param src_index Index of the first source element in the vector.
86 * @param n Number of elements to copy.
87 * @param for_output If true, apply thinning.
89 * @c dst and @ src can be either the same or different.
91 template <class T, class ALLOC>
92 void JaggedVecVectorFactory<T, ALLOC>::copyImpl (SG::auxid_t auxid,
95 const AuxVectorData& src,
98 bool for_output) const
102 // Check for overlaps.
104 size_t src_end = src_index + n;
105 size_t dst_end = dst_index + n;
106 if ((src_end > dst_index && src_end <= dst_end) ||
107 (dst_end > src_index && dst_end <= src_end))
109 // Overlapping copies not implemented for jagged vectors.
110 // Talk to core software if this is an issue.
111 throwJaggedVecOverlappingCopy();
115 vector_value_type* v_dst = reinterpret_cast<vector_value_type*> (dst.getDataArray (auxid));
116 const vector_value_type* v_src = &dst==&src ? v_dst : reinterpret_cast<const vector_value_type*> (src.getDataArray (auxid));
117 IAuxTypeVector* dst_lv = dst.getStore()->linkedVector (auxid);
118 const SG::auxid_t payload_auxid = dst_lv->auxid();
119 const AuxTypeRegistry& r = AuxTypeRegistry::instance();
120 const IAuxTypeVectorFactory* payload_fac = r.getFactory (payload_auxid);
122 const size_t dst_first = v_dst[dst_index].begin(dst_index);
123 size_t src_first = v_src[src_index].begin(src_index);
124 const size_t src_first_orig = src_first;
125 const size_t n_dst = v_dst[dst_index+n-1].end() - dst_first;
126 const size_t n_src = v_src[src_index+n-1].end() - src_first;
128 // First copy the Elt elements. We'll fix up the indices below.
129 std::copy_n (v_src+src_index, n, v_dst+dst_index);
131 // Adjust the size of the destination payload container.
132 if (n_src != n_dst) {
133 if (!dst_lv->shift (dst_first+n_dst, n_src - n_dst)) {
134 dst.clearCache (payload_auxid);
136 if (&dst == &src && src_first > dst_first) {
137 src_first += (n_src - n_dst);
141 // Copy the payload elements.
143 payload_fac->copyForOutput (payload_auxid, dst, dst_first, src, src_first, n_src);
146 payload_fac->copy (payload_auxid, dst, dst_first, src, src_first, n_src);
149 // Fixup the Elt entries --- first the ones we copied, then the following
150 // ones in the destination container.
151 std::for_each_n (v_dst+dst_index, n, Shift (dst_first - src_first_orig));
152 std::for_each (v_dst+dst_index+n, v_dst+dst.size_v(), Shift (n_src - n_dst));
157 * @brief Copy elements between vectors.
158 * @param auxid The aux data item being operated on.
159 * @param dst Container for the destination vector.
160 * @param dst_index Index of the first destination element in the vector.
161 * @param src Container for the source vector.
162 * @param src_index Index of the first source element in the vector.
163 * @param n Number of elements to copy.
165 * @c dst and @ src can be either the same or different.
167 template <class T, class ALLOC>
168 void JaggedVecVectorFactory<T, ALLOC>::copy (SG::auxid_t auxid,
171 const AuxVectorData& src,
175 copyImpl (auxid, dst, dst_index, src, src_index, n, false);
180 * @brief Copy elements between vectors, possibly applying thinning.
181 * @param auxid The aux data item being operated on.
182 * @param dst Container for the destination vector.
183 * @param dst_index Index of the first destination element in the vector.
184 * @param src Container for the source vector.
185 * @param src_index Index of source element in the vector.
186 * @param src_index Index of the first source element in the vector.
187 * @param n Number of elements to copy.
189 * @c dst and @ src can be either the same or different.
191 template <class CONT, class ALLOC>
192 void JaggedVecVectorFactory<CONT, ALLOC>::copyForOutput
194 AuxVectorData& dst, size_t dst_index,
195 const AuxVectorData& src, size_t src_index,
198 copyImpl (auxid, dst, dst_index, src, src_index, n, true);
203 * @brief Swap elements between vectors.
204 * @param auxid The aux data item being operated on.
205 * @param a Container for the first vector.
206 * @param aindex Index of the first element in the first vector.
207 * @param b Container for the second vector.
208 * @param bindex Index of the first element in the second vector.
209 * @param n Number of elements to swap.
211 * @c a and @ b can be either the same or different.
212 * However, the ranges should not overlap.
214 template <class T, class ALLOC>
215 void JaggedVecVectorFactory<T, ALLOC>::swap (SG::auxid_t auxid,
216 AuxVectorData& a, size_t aindex,
217 AuxVectorData& b, size_t bindex,
222 vector_value_type* v_a = reinterpret_cast<vector_value_type*> (a.getDataArray (auxid));
223 vector_value_type* v_b = &a==&b ? v_a : reinterpret_cast<vector_value_type*> (b.getDataArray (auxid));
224 IAuxTypeVector* alv = a.getStore()->linkedVector (auxid);
225 IAuxTypeVector* blv = &a==&b ? alv : b.getStore()->linkedVector (auxid);
226 const SG::auxid_t payload_auxid = alv->auxid();
227 const AuxTypeRegistry& r = AuxTypeRegistry::instance();
228 const IAuxTypeVectorFactory* payload_fac = r.getFactory (payload_auxid);
230 size_t a_first = v_a[aindex].begin(aindex);
231 size_t b_first = v_b[bindex].begin(bindex);
232 const size_t a_first_orig = a_first;
233 const size_t b_first_orig = b_first;
234 const size_t n_a = v_a[aindex+n-1].end() - a_first;
235 const size_t n_b = v_b[bindex+n-1].end() - b_first;
237 // First swap the Elt entries. We'll fix up the indices below.
238 std::swap_ranges (v_a+aindex, v_a+aindex+n, v_b+bindex);
240 // We have two payload ranges to swap, a and b.
241 // One is probably longer than the other, so we'll need to adjust the
242 // payload vector lengths.
243 // But first, swap the common part of the payloads.
244 const size_t n_common = std::min (n_a, n_b);
245 payload_fac->swap (payload_auxid, a, a_first, b, b_first, n_common);
247 // Now we move the tail; that is, the piece of one payload range
248 // that is not in the other. Define a function to reduce duplicate
249 // code. Here, 1 is the range that is longer and 2 the range
251 auto shiftTail = [payload_fac, n_common, payload_auxid]
260 // Lengthen the shorter payload to receive the extra elements from
262 if (!lv2->shift (first2 + n_common, n1 - n_common)) {
263 vd2.clearCache (payload_auxid);
265 if (&vd1 == &vd2 && first1 > first2) {
266 // Special case for self-swapping: keep indices consistent.
267 first1 += (n1 - n_common);
269 // Copy the extra elements.
270 payload_fac->copy (payload_auxid,
271 vd2, first2 + n_common, vd1, first1 + n_common,
273 // Now remove those elements from the longer one.
274 lv1->shift (first1 + n1, - (n1 - n_common));
275 if (&vd1 == &vd2 && first2 > first1) {
276 // Special case for self-swapping: keep indices consistent.
277 first2 -= (n1 - n_common);
281 // Now move the tail, depending on which is larger.
283 shiftTail (a, alv, a_first, n_a, b, blv, b_first);
285 else if (n_b > n_a) {
286 shiftTail (b, blv, b_first, n_b, a, alv, a_first);
289 // Now adjust the indices in the Elt ranges that were swapped.
290 // In the case of self-swapping, the _first indices may have changed,
291 // so need to remember to use the original values.
292 std::for_each_n (v_a+aindex, n, Shift (a_first - b_first_orig));
293 std::for_each_n (v_b+bindex, n, Shift (b_first - a_first_orig));
297 // Self-swapping case.
298 // Adjust the indices between the two ranges that were swapped
299 // (but we needn't do anything if the number of payload items
301 if (aindex < bindex) {
302 std::for_each (v_a+aindex+n, v_a+bindex, Shift (n_b - n_a));
305 std::for_each (v_a+bindex+n, v_a+aindex, Shift (n_a - n_b));
309 // Distinct container case. Adjust indices after the swapped ranges.
310 std::for_each (v_a+aindex+n, v_a+a.size_v(), Shift (n_b - n_a));
311 std::for_each (v_b+bindex+n, v_b+b.size_v(), Shift (n_a - n_b));
318 * @brief Clear a range of elements within a vector.
319 * @param auxid The aux data item being operated on.
320 * @param dst Container holding the element
321 * @param dst_index Index of the first element in the vector.
322 * @param n Number of elements to clear.
324 template <class T, class ALLOC>
325 void JaggedVecVectorFactory<T, ALLOC>::clear (SG::auxid_t auxid,
332 vector_value_type* v = reinterpret_cast<vector_value_type*> (dst.getDataArray (auxid));
333 IAuxTypeVector* lv = dst.getStore()->linkedVector (auxid);
334 size_t begin = v[dst_index].begin(dst_index);
335 size_t end = v[dst_index+n-1].end();
336 size_t n_payload = end - begin;
338 // Erase the payload elements.
339 lv->shift (end, - n_payload);
341 // Clear out the given range.
342 Elt zero = Elt (begin);
343 std::fill_n (v+dst_index, n, zero);
345 // Adjust indices for following elements.
346 std::for_each (v+dst_index+n, v+dst.size_v(), Shift (-n_payload));