2 * Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration.
5 * @file AthContainers/tools/JaggedVecVector.icc
6 * @author scott snyder <snyder@bnl.gov>
8 * @brief Implementation of @c IAuxTypeVector for @c JaggedVecElt types.
12#include "AthContainers/AuxTypeRegistry.h"
19 * @brief Fill in any trailing zeros at the end of this vector.
21template <class T, class ALLOC>
22void JaggedVecVectorHolder<T, ALLOC>::fillTrailingZeros()
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) {
31 if (index == 0) break;
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.
45template <class T, class ALLOC>
46JaggedVecVectorHolder<T, ALLOC>::JaggedVecVectorHolder
49 IAuxTypeVector* linkedVec,
51 : Base (auxid, vecPtr, ownFlag, false),
52 m_linkedVec (linkedVec)
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;
63template <class T, class ALLOC>
65bool JaggedVecVectorHolder<T, ALLOC>::resize (size_t sz)
68 vector_type& vec = this->vec();
70 size_t vec_sz = vec.size();
71 if (sz == vec_sz) return true;
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
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) {
99 valid = m_linkedVec->resize (payload_sz);
101 else if (vec_sz > 0) {
103 size_t payload_sz = vec.back().end();
104 zero = Elt (payload_sz);
106 const void* orig = vec.data();
107 vec.resize (sz, zero);
108 this->storeDataSpan();
109 return valid && vec.data() == orig;
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.
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.
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.
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).
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.)
139template <class T, class ALLOC>
140bool JaggedVecVectorHolder<T, ALLOC>::shift (size_t pos, ptrdiff_t offs)
143 vector_type& vec = this->vec();
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();
155 const void* orig = vec.data();
156 size_t oldsz = vec.size();
159 index_type end = vec.back().end();
162 // Add to the end, zero-filled.
163 vec.resize (vec.size() + offs, zero);
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),
174 index_type end = vec[pos-1].end();
177 std::fill_n (vec.begin() + pos, offs, zero);
179 this->storeDataSpan();
180 return vec.data() == orig;
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.
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.
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.
201 * Returns true if it is known that the vector's memory did not move,
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)
208 if (src_n <= 0) return true;
210 element_type* srcp = reinterpret_cast<element_type*> (src);
211 element_type* beg = srcp + src_pos;
212 element_type* end = beg + src_n;
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);
219 IAuxTypeVector* srcPayloadVec = srcStore.linkedVector (this->auxid());
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:
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.
237 for (size_t i = src_pos+src_n-1; ; --i) {
238 if (srcp[i].end() != 0) {
245 Shift shift (src_nPayload);
246 for (size_t i = pos + src_n - 1; vec[i].end() == 0; --i)
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,
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(),
268 this->storeDataSpan();
269 return pflag && (vec.data() == orig);
273//*****************************************************************************
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.
283template <class HOLDER>
284JaggedVecVectorT<HOLDER>::JaggedVecVectorT (auxid_t auxid,
287 std::unique_ptr<IAuxTypeVector> linkedVec)
288 : Base (auxid, &m_vec, linkedVec.get(), false),
289 m_linkedVecHolder (std::move (linkedVec))
291 m_vec.reserve (capacity);
297 * @brief Copy constructor.
299template <class HOLDER>
300JaggedVecVectorT<HOLDER>::JaggedVecVectorT (const JaggedVecVectorT& other)
301 : Base (other.auxid(), &m_vec, false, false),
303 m_linkedVecHolder (other.m_linkedVec->clone())
305 Base::m_linkedVec = m_linkedVecHolder.get();
310 * @brief Move constructor.
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))
322 * @brief Make a copy of this vector.
324template <class HOLDER>
326std::unique_ptr<IAuxTypeVector> JaggedVecVectorT<HOLDER>::clone() const
328 return std::make_unique<JaggedVecVectorT> (*this);
333 * @brief Return ownership of the linked vector.
335template <class HOLDER>
337std::unique_ptr<IAuxTypeVector> JaggedVecVectorT<HOLDER>::linkedVector()
339 return std::move (m_linkedVecHolder);