ATLAS Offline Software
Loading...
Searching...
No Matches
JaggedVecVectorFactory.icc
Go to the documentation of this file.
1/*
2 * Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration.
3 */
4/**
5 * @file AthContainers/tools/JaggedVecVectorFactory.icc
6 * @author scott snyder <snyder@bnl.gov>
7 * @date Apr, 2024
8 * @brief Factory object that creates vectors using @c AuxTypeVector,
9 * specialized for JaggedVec.
10 */
11
12
13#include "AthContainers/tools/AuxTypeVector.h"
14#include "AthContainers/AuxTypeRegistry.h"
15#include "AthContainers/exceptions.h"
16
17
18namespace SG {
19
20
21/**
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.
27 * Must be false.
28 */
29template <class T, class ALLOC>
30std::unique_ptr<IAuxTypeVector>
31JaggedVecVectorFactory<T, ALLOC>::create (SG::auxid_t auxid,
32 size_t size, size_t capacity,
33 [[maybe_unused]] bool isLinked) const
34{
35 assert (!isLinked);
36 const AuxTypeRegistry& r = AuxTypeRegistry::instance();
37 auxid_t linked_id = r.linkedVariable (auxid);
38
39 using linkedAlloc = typename std::allocator_traits<ALLOC>::template rebind_alloc<T>;
40 auto linkedVec =
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));
44}
45
46
47/**
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.
57 *
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.
61 */
62template <class CONT, class ALLOC>
63std::unique_ptr<IAuxTypeVector>
64JaggedVecVectorFactory<CONT, ALLOC>::createFromData (SG::auxid_t auxid,
65 void* data,
66 IAuxTypeVector* linkedVector,
67 [[maybe_unused]] bool isPacked,
68 bool ownFlag,
69 [[maybe_unused]] bool isLinked) const
70{
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);
76}
77
78
79/**
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.
88 *
89 * @c dst and @ src can be either the same or different.
90 */
91template <class T, class ALLOC>
92void JaggedVecVectorFactory<T, ALLOC>::copyImpl (SG::auxid_t auxid,
93 AuxVectorData& dst,
94 size_t dst_index,
95 const AuxVectorData& src,
96 size_t src_index,
97 size_t n,
98 bool for_output) const
99{
100 if (n == 0) return;
101
102 // Check for overlaps.
103 if (&src == &dst) {
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))
108 {
109 // Overlapping copies not implemented for jagged vectors.
110 // Talk to core software if this is an issue.
111 throwJaggedVecOverlappingCopy();
112 }
113 }
114
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);
121
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;
127
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);
130
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);
135 }
136 if (&dst == &src && src_first > dst_first) {
137 src_first += (n_src - n_dst);
138 }
139 }
140
141 // Copy the payload elements.
142 if (for_output) {
143 payload_fac->copyForOutput (payload_auxid, dst, dst_first, src, src_first, n_src);
144 }
145 else {
146 payload_fac->copy (payload_auxid, dst, dst_first, src, src_first, n_src);
147 }
148
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));
153}
154
155
156/**
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.
164 *
165 * @c dst and @ src can be either the same or different.
166 */
167template <class T, class ALLOC>
168void JaggedVecVectorFactory<T, ALLOC>::copy (SG::auxid_t auxid,
169 AuxVectorData& dst,
170 size_t dst_index,
171 const AuxVectorData& src,
172 size_t src_index,
173 size_t n) const
174{
175 copyImpl (auxid, dst, dst_index, src, src_index, n, false);
176}
177
178
179/**
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.
188 *
189 * @c dst and @ src can be either the same or different.
190 */
191template <class CONT, class ALLOC>
192void JaggedVecVectorFactory<CONT, ALLOC>::copyForOutput
193 (SG::auxid_t auxid,
194 AuxVectorData& dst, size_t dst_index,
195 const AuxVectorData& src, size_t src_index,
196 size_t n) const
197{
198 copyImpl (auxid, dst, dst_index, src, src_index, n, true);
199}
200
201
202/**
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.
210 *
211 * @c a and @ b can be either the same or different.
212 * However, the ranges should not overlap.
213 */
214template <class T, class ALLOC>
215void JaggedVecVectorFactory<T, ALLOC>::swap (SG::auxid_t auxid,
216 AuxVectorData& a, size_t aindex,
217 AuxVectorData& b, size_t bindex,
218 size_t n) const
219{
220 if (n == 0) return;
221
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);
229
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;
236
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);
239
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);
246
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
250 // that is shorter.
251 auto shiftTail = [payload_fac, n_common, payload_auxid]
252 (AuxVectorData& vd1,
253 IAuxTypeVector* lv1,
254 size_t& first1,
255 const size_t n1,
256 AuxVectorData& vd2,
257 IAuxTypeVector* lv2,
258 size_t& first2)
259 {
260 // Lengthen the shorter payload to receive the extra elements from
261 // the longer one.
262 if (!lv2->shift (first2 + n_common, n1 - n_common)) {
263 vd2.clearCache (payload_auxid);
264 }
265 if (&vd1 == &vd2 && first1 > first2) {
266 // Special case for self-swapping: keep indices consistent.
267 first1 += (n1 - n_common);
268 }
269 // Copy the extra elements.
270 payload_fac->copy (payload_auxid,
271 vd2, first2 + n_common, vd1, first1 + n_common,
272 n1 - 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);
278 }
279 };
280
281 // Now move the tail, depending on which is larger.
282 if (n_a > n_b) {
283 shiftTail (a, alv, a_first, n_a, b, blv, b_first);
284 }
285 else if (n_b > n_a) {
286 shiftTail (b, blv, b_first, n_b, a, alv, a_first);
287 }
288
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));
294
295 if (n_a != n_b) {
296 if (&a == &b) {
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
300 // was the same).
301 if (aindex < bindex) {
302 std::for_each (v_a+aindex+n, v_a+bindex, Shift (n_b - n_a));
303 }
304 else {
305 std::for_each (v_a+bindex+n, v_a+aindex, Shift (n_a - n_b));
306 }
307 }
308 else {
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));
312 }
313 }
314}
315
316
317/**
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.
323 */
324template <class T, class ALLOC>
325void JaggedVecVectorFactory<T, ALLOC>::clear (SG::auxid_t auxid,
326 AuxVectorData& dst,
327 size_t dst_index,
328 size_t n) const
329{
330 if (n == 0) return;
331
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;
337
338 // Erase the payload elements.
339 lv->shift (end, - n_payload);
340
341 // Clear out the given range.
342 Elt zero = Elt (begin);
343 std::fill_n (v+dst_index, n, zero);
344
345 // Adjust indices for following elements.
346 std::for_each (v+dst_index+n, v+dst.size_v(), Shift (-n_payload));
347}
348
349
350} // namespace SG