ATLAS Offline Software
Loading...
Searching...
No Matches
JaggedVecVector.icc
Go to the documentation of this file.
1/*
2 * Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration.
3 */
4/**
5 * @file AthContainers/tools/JaggedVecVector.icc
6 * @author scott snyder <snyder@bnl.gov>
7 * @date Mar, 2024
8 * @brief Implementation of @c IAuxTypeVector for @c JaggedVecElt types.
9 */
10
11
12#include "AthContainers/AuxTypeRegistry.h"
13
14
15namespace SG {
16
17
18/**
19 * @brief Fill in any trailing zeros at the end of this vector.
20 */
21template <class T, class ALLOC>
22void JaggedVecVectorHolder<T, ALLOC>::fillTrailingZeros()
23{
24 vector_type& vec = this->vec();
25 if (vec.empty()) return;
26 if (vec.back().end() == 0) {
27 if (size_t n_payload = m_linkedVec->getDataSpan().size) {
28 Shift shift (n_payload);
29 for (size_t index = vec.size()-1; vec[index].end() == 0; --index) {
30 shift (vec[index]);
31 if (index == 0) break;
32 }
33 }
34 }
35}
36
37
38/**
39 * @brief Constructor.
40 * @param auxid The auxid of the variable this vector represents.
41 * @param vecPtr Pointer to the object.
42 * @param linkedVec Interface for the linked vector of DataLinks.
43 * @param ownFlag If true, take ownership of the object.
44 */
45template <class T, class ALLOC>
46JaggedVecVectorHolder<T, ALLOC>::JaggedVecVectorHolder
47 (auxid_t auxid,
48 vector_type* vecPtr,
49 IAuxTypeVector* linkedVec,
50 bool ownFlag)
51 : Base (auxid, vecPtr, ownFlag, false),
52 m_linkedVec (linkedVec)
53{
54}
55
56
57/**
58 * @brief Change the size of the vector.
59 * @param sz The new vector size.
60 * Returns true if it is known that iterators have not been invalidated;
61 * false otherwise.
62 */
63template <class T, class ALLOC>
64inline
65bool JaggedVecVectorHolder<T, ALLOC>::resize (size_t sz)
66{
67 bool valid = true;
68 vector_type& vec = this->vec();
69 Elt zero;
70 size_t vec_sz = vec.size();
71 if (sz == vec_sz) return true;
72 if (sz < vec_sz) {
73 size_t payload_sz = sz > 0 ? vec[sz-1].end() : 0;
74 if (payload_sz == 0 && vec.back().end() == 0) {
75 payload_sz = m_linkedVec->getDataSpan().size;
76 if (sz > 0 && payload_sz > 0) {
77 // At this point, we're dealing with trailing zeros, and we can have
78 // one of two cases:
79 //
80 // 0 0 0 1 2 3 0 0 0
81 // a b
82 //
83 // If we try to resize to b, then we're just removing trailing zeros
84 // and shouldn't touch the payload. But if we're resizing to a,
85 // then we also need to free the entire payload.
86 // There's no way to distinguish between these by looking
87 // just at the resize point, end, and total payload size.
88 // We need to scan from the resize point to the end to see if
89 // there's anything nonzero. If so, then we remove the entire
90 // payload; other wise, we leave it alone.
91 for (size_t i = sz; i < vec_sz; ++i) {
92 if (vec[i].end() != 0) {
93 payload_sz = 0;
94 break;
95 }
96 }
97 }
98 }
99 valid = m_linkedVec->resize (payload_sz);
100 }
101 else if (vec_sz > 0) {
102 fillTrailingZeros();
103 size_t payload_sz = vec.back().end();
104 zero = Elt (payload_sz);
105 }
106 const void* orig = vec.data();
107 vec.resize (sz, zero);
108 this->storeDataSpan();
109 return valid && vec.data() == orig;
110}
111
112
113/**
114 * @brief Shift the elements of the vector.
115 * @param pos The starting index for the shift.
116 * @param offs The (signed) amount of the shift.
117 *
118 * This operation shifts the elements in the vectors for all
119 * aux data items, to implement an insertion or deletion.
120 * @c offs may be either positive or negative.
121 *
122 * If @c offs is positive, then the container is growing.
123 * The container size should be increased by @c offs,
124 * the element at @c pos moved to @c pos + @c offs,
125 * and similarly for following elements.
126 * The elements between @c pos and @c pos + @c offs should
127 * be default-initialized.
128 *
129 * If @c offs is negative, then the container is shrinking.
130 * The element at @c pos should be moved to @c pos + @c offs,
131 * and similarly for following elements.
132 * The container should then be shrunk by @c -offs elements
133 * (running destructors as appropriate).
134 *
135 * Returns true if it is known that iterators have not been invalidated;
136 * false otherwise. (Will always return false when increasing the size
137 * of an empty container.)
138 */
139template <class T, class ALLOC>
140bool JaggedVecVectorHolder<T, ALLOC>::shift (size_t pos, ptrdiff_t offs)
141{
142 fillTrailingZeros();
143 vector_type& vec = this->vec();
144 if (offs < 0) {
145 if (-offs > static_cast<ptrdiff_t>(pos)) offs = -pos;
146 size_t ppos = pos < vec.size() ? vec[pos].begin(pos) : m_linkedVec->size();
147 ptrdiff_t poffs = - (ppos - vec[pos+offs].begin(pos+offs));
148 m_linkedVec->shift (ppos, poffs);
149 vec.erase (vec.begin() + pos+offs, vec.begin() + pos);
150 std::for_each (vec.begin() + pos+offs, vec.end(), Shift (poffs));
151 this->storeDataSpan();
152 return true;
153 }
154 else if (offs > 0) {
155 const void* orig = vec.data();
156 size_t oldsz = vec.size();
157 Elt zero;
158 if (!vec.empty()) {
159 index_type end = vec.back().end();
160 zero = Elt (end);
161 }
162 // Add to the end, zero-filled.
163 vec.resize (vec.size() + offs, zero);
164 if (oldsz != pos) {
165 // Shift existing elements. If we're just extending,
166 // then we can skip this.
167 std::copy (vec.rbegin() + offs,
168 vec.rbegin() + (offs+oldsz-pos),
169 vec.rbegin());
170 if (pos == 0) {
171 zero = Elt (0);
172 }
173 else {
174 index_type end = vec[pos-1].end();
175 zero = Elt (end);
176 }
177 std::fill_n (vec.begin() + pos, offs, zero);
178 }
179 this->storeDataSpan();
180 return vec.data() == orig;
181 }
182 return true;
183}
184
185
186/**
187 * @brief Insert elements into the vector via move semantics.
188 * @param pos The starting index of the insertion.
189 * @param src Start of the vector containing the range of elements to insert.
190 * @param src_pos Position of the first element to insert.
191 * @param src_n Number of elements to insert.
192 * @param srcStore The source store.
193 *
194 * The size of the container will be increased by @c src_n, with the elements
195 * starting at @c pos copied to @c pos+src_n.
196 *
197 * The contents of the source range will then be moved to our vector
198 * starting at @c pos. This will be done via move semantics if possible;
199 * otherwise, it will be done with a copy.
200 *
201 * Returns true if it is known that the vector's memory did not move,
202 * false otherwise.
203 */
204template <class T, class ALLOC>
205bool JaggedVecVectorHolder<T, ALLOC>::insertMove
206 (size_t pos, void* src, size_t src_pos, size_t src_n, IAuxStore& srcStore)
207{
208 if (src_n <= 0) return true;
209 fillTrailingZeros();
210 element_type* srcp = reinterpret_cast<element_type*> (src);
211 element_type* beg = srcp + src_pos;
212 element_type* end = beg + src_n;
213
214 vector_type& vec = this->vec();
215 const element_type* orig = vec.data();
216 const size_t ppos = vec[pos].begin(pos);
217 vec.insert (vec.begin() + pos, beg, end);
218
219 IAuxTypeVector* srcPayloadVec = srcStore.linkedVector (this->auxid());
220
221 // Fill trailing zeros in the copied elements.
222 if (vec[pos + src_n - 1].end() == 0) {
223 size_t src_sz = srcStore.size();
224 if (srcp[src_sz-1].end() == 0) {
225 if (size_t src_nPayload = srcPayloadVec->getDataSpan().size) {
226 // Similarly to the case in resize() above, we have two possibilities
227 // here. Suppose the vector from which we're inserting looks like:
228 //
229 // 0 0 1 2 0 0
230 //
231 // If we insert 1 element starting from index 0, then we don't
232 // want to do this adjustment. But if we insert 5 elements,
233 // then we do. Again, we can't tell the difference looking
234 // at the insertion position; we need to look at the elements
235 // between the insertion position and the end.
236 bool adjust = false;
237 for (size_t i = src_pos+src_n-1; ; --i) {
238 if (srcp[i].end() != 0) {
239 adjust = true;
240 break;
241 }
242 if (i == 0) break;
243 }
244 if (adjust) {
245 Shift shift (src_nPayload);
246 for (size_t i = pos + src_n - 1; vec[i].end() == 0; --i)
247 {
248 shift (vec[i]);
249 if (i == pos) break;
250 }
251 }
252 }
253 }
254 }
255
256 size_t begidx = src_pos > 0 ? srcp[src_pos-1].end() : 0;
257 size_t npayload = vec[pos+src_n-1].end() - begidx;
258 T* srcPayload = reinterpret_cast<T*> (srcPayloadVec->toPtr());
259 bool pflag = m_linkedVec->insertMove (ppos,
260 srcPayload,
261 begidx,
262 npayload,
263 srcStore);
264 std::for_each (vec.begin() + pos, vec.begin() + pos + src_n,
265 Shift (ppos - begidx));
266 std::for_each (vec.begin() + pos + src_n, vec.end(),
267 Shift (npayload));
268 this->storeDataSpan();
269 return pflag && (vec.data() == orig);
270}
271
272
273//*****************************************************************************
274
275
276/**
277 * @brief Constructor. Makes a new vector.
278 * @param auxid The auxid of the variable this vector represents.
279 * @param size Initial size of the new vector.
280 * @param capacity Initial capacity of the new vector.
281 * @param linkedVec Ownership of the linked vector.
282 */
283template <class HOLDER>
284JaggedVecVectorT<HOLDER>::JaggedVecVectorT (auxid_t auxid,
285 size_t size,
286 size_t capacity,
287 std::unique_ptr<IAuxTypeVector> linkedVec)
288 : Base (auxid, &m_vec, linkedVec.get(), false),
289 m_linkedVecHolder (std::move (linkedVec))
290{
291 m_vec.reserve (capacity);
292 m_vec.resize (size);
293}
294
295
296/**
297 * @brief Copy constructor.
298 */
299template <class HOLDER>
300JaggedVecVectorT<HOLDER>::JaggedVecVectorT (const JaggedVecVectorT& other)
301 : Base (other.auxid(), &m_vec, false, false),
302 m_vec (other.m_vec),
303 m_linkedVecHolder (other.m_linkedVec->clone())
304{
305 Base::m_linkedVec = m_linkedVecHolder.get();
306}
307
308
309/**
310 * @brief Move constructor.
311 */
312template <class HOLDER>
313JaggedVecVectorT<HOLDER>::JaggedVecVectorT (JaggedVecVectorT&& other)
314 : Base (other.auxid(), &m_vec, false, other.m_linkedVec),
315 m_vec (std::move (other.m_vec)),
316 m_linkedVecHolder (std::move (other.m_linkedVecHolder))
317{
318}
319
320
321/**
322 * @brief Make a copy of this vector.
323 */
324template <class HOLDER>
325inline
326std::unique_ptr<IAuxTypeVector> JaggedVecVectorT<HOLDER>::clone() const
327{
328 return std::make_unique<JaggedVecVectorT> (*this);
329}
330
331
332/**
333 * @brief Return ownership of the linked vector.
334 */
335template <class HOLDER>
336inline
337std::unique_ptr<IAuxTypeVector> JaggedVecVectorT<HOLDER>::linkedVector()
338{
339 return std::move (m_linkedVecHolder);
340}
341
342
343} // namespace SG