ATLAS Offline Software
Loading...
Searching...
No Matches
ColumnVectorWrapper.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
6
7
8//
9// includes
10//
11
13
17
18#include <boost/core/demangle.hpp>
19
20#include <algorithm>
21#include <stdexcept>
22
23//
24// method implementations
25//
26
27namespace columnar
28{
29 ColumnVectorHeader ::
30 ColumnVectorHeader ()
31 {
33
34 // we always reserve the first column as having a null value
35 m_elements.at(nullIndex).debugName = "<null>";
36 m_elements.at(nullIndex).isOptional = true;
37
38 // we always reserve the second column as the size column
39 m_elements.at(sizeIndex).debugName = "<size>";
40 m_elements.at(sizeIndex).type = &typeid(std::size_t);
41 m_elements.at(sizeIndex).isOptional = false;
42 m_elements.at(sizeIndex).readOnly = true;
43 }
44
45
46
47 [[nodiscard]] std::size_t ColumnVectorHeader ::
48 addColumn (const ColumnInfo& columnInfo)
49 {
50 // Check for existing column with the same name (deduplication for multi-tool support)
51 auto iter = m_nameToIndex.find(columnInfo.name);
52 if (iter != m_nameToIndex.end())
53 {
54 auto& existingHeader = m_elements.at(iter->second);
55
56 // Variant link key columns with different targets get auto-renamed
57 if (!columnInfo.keyColumnForVariantLink.empty() && !existingHeader.keyColumnForVariantLink.empty() && existingHeader.variantLinkTargetNames != columnInfo.variantLinkTargetNames)
58 {
59 std::string uniqueName;
60 for (unsigned suffix = 1; ; ++suffix)
61 {
62 uniqueName = columnInfo.name + "." + std::to_string(suffix);
63 if (m_nameToIndex.find(uniqueName) == m_nameToIndex.end())
64 break;
65 }
66 ColumnInfo renamedInfo = columnInfo;
67 renamedInfo.name = std::move(uniqueName);
68 return addColumn(renamedInfo);
69 }
70
71 // Check that relevant fields match
72 if (existingHeader.type != columnInfo.type)
73 throw std::runtime_error("column " + columnInfo.name + " type mismatch");
74 if (existingHeader.offsetName != columnInfo.offsetName)
75 throw std::runtime_error("column " + columnInfo.name + " offset name mismatch: " + existingHeader.offsetName + " vs " + columnInfo.offsetName);
76 if (existingHeader.isOffset != columnInfo.isOffset)
77 throw std::runtime_error("column " + columnInfo.name + " isOffset mismatch");
78 if (existingHeader.fixedDimensions != columnInfo.fixedDimensions)
79 throw std::runtime_error("column " + columnInfo.name + " fixed dimensions mismatch");
80 if (existingHeader.soleLinkTargetName != columnInfo.soleLinkTargetName)
81 throw std::runtime_error("column " + columnInfo.name + " sole link target name mismatch");
82 if (existingHeader.soleLinkTargetClid != columnInfo.soleLinkTargetClid)
83 throw std::runtime_error("column " + columnInfo.name + " sole link target clid mismatch");
84 if (existingHeader.isVariantLink != columnInfo.isVariantLink)
85 throw std::runtime_error("column " + columnInfo.name + " isVariantLink mismatch");
86 if (existingHeader.variantLinkTargetNames != columnInfo.variantLinkTargetNames)
87 throw std::runtime_error("column " + columnInfo.name + " variant link target names mismatch");
88 if (existingHeader.keyColumnForVariantLink != columnInfo.keyColumnForVariantLink)
89 throw std::runtime_error("column " + columnInfo.name + " key column for variant link mismatch");
90
91 // Handle access mode conflicts
92 if (columnInfo.accessMode == ColumnAccessMode::output && existingHeader.readOnly)
93 throw std::runtime_error("column " + columnInfo.name + " already registered as input, cannot register as output");
94 // Promote to read-write if new column needs write access (update mode)
95 if (columnInfo.accessMode == ColumnAccessMode::update)
96 existingHeader.readOnly = false;
97 // If existing is already non-readOnly (output or update), keep it that way
98 return iter->second;
99 }
100
101 m_elements.emplace_back();
102 m_elements.at(sizeIndex).arraySize = m_elements.size();
103
104 auto& header = m_elements.back();
105 header.debugName = columnInfo.name;
106 header.type = columnInfo.type;
107 header.accessMode = columnInfo.accessMode;
108 header.offsetName = columnInfo.offsetName;
109 header.soleLinkTargetName = columnInfo.soleLinkTargetName;
110 header.soleLinkTargetClid = columnInfo.soleLinkTargetClid;
111 header.isVariantLink = columnInfo.isVariantLink;
112 header.variantLinkTargetNames = columnInfo.variantLinkTargetNames;
113 header.keyColumnForVariantLink = columnInfo.keyColumnForVariantLink;
114 header.fixedDimensions = columnInfo.fixedDimensions;
115
116 switch (columnInfo.accessMode)
117 {
119 break;
121 header.readOnly = false;
122 break;
124 header.readOnly = false;
125 break;
126 }
127 for (unsigned dim : columnInfo.fixedDimensions)
128 header.arraySize *= dim;
129 header.isOffset = columnInfo.isOffset;
130 if (!columnInfo.isOptional)
131 header.isOptional = false;
132 if (!columnInfo.offsetName.empty())
133 header.offsetIndex = unsetIndex;
134
135 const std::size_t newIndex = m_elements.size() - 1;
136 m_nameToIndex.emplace(columnInfo.name, newIndex);
137 return newIndex;
138 }
139
140
141
142 void ColumnVectorHeader ::
143 setOffsetColumn (std::size_t columnIndex, std::size_t offsetIndex)
144 {
145 if (columnIndex >= m_elements.size())
146 throw std::logic_error ("column index out of range");
147 if (offsetIndex >= m_elements.size())
148 throw std::logic_error ("offset index out of range");
149 auto& column = m_elements.at(columnIndex);
150 auto& offset = m_elements.at(offsetIndex);
151 if (!offset.isOffset)
152 throw std::runtime_error ("trying to set " + offset.debugName + " as offset column for " + column.debugName + ", but it is not marked as offset column");
153 if (column.offsetIndex != unsetIndex && column.offsetIndex != offsetIndex)
154 throw std::runtime_error ("trying to set " + offset.debugName + " as offset column for " + column.debugName + ", but it is already set to " + m_elements.at(column.offsetIndex).debugName);
155 column.offsetIndex = offsetIndex;
156 }
157
158
159
160 void ColumnVectorHeader ::
161 checkSelf () const
162 {
163 if (m_elements.size() < numFixedColumns)
164 throw std::logic_error ("header has too few m_elements, expected at least " + std::to_string(numFixedColumns) + " but got " + std::to_string(m_elements.size()));
165 if (m_elements[sizeIndex].arraySize != m_elements.size())
166 throw std::logic_error ("size column has wrong array size, expected " + std::to_string(m_elements.size()) + " but got " + std::to_string(m_elements[sizeIndex].arraySize));
167
168 // skipping the first column, which is always the null column
169 // and behaves in a funny manner
170 for (std::size_t columnIndex = 1u; columnIndex != m_elements.size(); ++ columnIndex)
171 {
172 const auto& column = m_elements[columnIndex];
173 if (column.debugName.empty())
174 throw std::logic_error ("column " + std::to_string(columnIndex) + " has no name");
175 if (column.type == nullptr)
176 throw std::logic_error ("column " + column.debugName + " has no type");
177 if (column.isOffset && *column.type != typeid(ColumnarOffsetType))
178 throw std::logic_error ("column " + column.debugName + " is an offset column that is of type " + boost::core::demangle(column.type->name()) + " instead of ColumnarOffsetType");
179 }
180
181 for (std::size_t columnIndex = 1u; columnIndex != m_elements.size(); ++ columnIndex)
182 {
183 const auto& column = m_elements[columnIndex];
184 if (column.offsetIndex != nullIndex)
185 {
186 if (column.offsetIndex == unsetIndex)
187 throw std::logic_error ("column " + column.debugName + " has an offset index that was never set");
188 if (column.offsetIndex >= m_elements.size())
189 throw std::logic_error ("column " + column.debugName + " has invalid offset index " + std::to_string(column.offsetIndex) + " (max is " + std::to_string(m_elements.size()-1) + ")");
190 const auto& offsetElement = m_elements[column.offsetIndex];
191 if (!offsetElement.isOffset)
192 throw std::logic_error ("column " + column.debugName + " has offset index that is not marked as offset");
193 }
194 }
195 }
196
197
198
199 void ColumnVectorHeader ::
200 checkData (std::span<const void* const> data) const
201 {
202 if (data.size() != m_elements.size())
203 throw std::logic_error ("data vector has wrong size, expected " + std::to_string(m_elements.size()) + " but got " + std::to_string(data.size()));
204 if (data[nullIndex] != nullptr)
205 throw std::logic_error ("null column is not set to a nullptr value");
206 const auto* sizeVector = static_cast<const std::size_t*>(data[sizeIndex]);
207 for (std::size_t columnIndex = 0u; columnIndex != m_elements.size(); ++ columnIndex)
208 {
209 const auto& column = m_elements[columnIndex];
210 if (data[columnIndex] == nullptr)
211 {
212 if (column.isOptional)
213 continue;
214 if (column.offsetIndex != nullIndex && data[column.offsetIndex] == nullptr)
215 continue;
216 throw std::logic_error ("column " + column.debugName + " was not set");
217 }
218 if (column.isOffset)
219 {
220 const auto size = sizeVector[columnIndex];
221 if (size < 1)
222 throw std::runtime_error ("offset column " + column.debugName + " has size " + std::to_string(size) + ", but needs at least 1 element");
223 auto *offsets = static_cast<const ColumnarOffsetType*>(data[columnIndex]);
224 if (offsets[0] != 0)
225 throw std::runtime_error ("offset column doesn't start with 0: " + column.debugName);
226 for (std::size_t i = 1u; i != size; ++ i)
227 {
228 if (offsets[i] < offsets[i-1])
229 throw std::runtime_error ("offset column " + column.debugName + " is not monotonically increasing at index " + std::to_string(i) + ": " + std::to_string(offsets[i-1]) + " > " + std::to_string(offsets[i]));
230 }
231 }
232 }
233 for (std::size_t columnIndex = 0u; columnIndex != m_elements.size(); ++ columnIndex)
234 {
235 if (data[columnIndex] == nullptr)
236 continue;
237 const auto& column = m_elements[columnIndex];
238 std::size_t expectedSize = 1u;
239 if (column.offsetIndex != ColumnVectorHeader::nullIndex)
240 {
241 if (data[column.offsetIndex] == nullptr)
242 throw std::runtime_error ("column " + column.debugName + " uses offset column " + m_elements[column.offsetIndex].debugName + " that is not set");
243 const auto offsetIndex = column.offsetIndex;
244 auto *offsetsPtr = static_cast<const ColumnarOffsetType*>(data[offsetIndex]);
245 expectedSize = offsetsPtr[sizeVector[offsetIndex]-1];
246 }
247 expectedSize *= column.arraySize;
248
249 if (column.isOffset)
250 expectedSize += 1u;
251
252 if (sizeVector[columnIndex] != expectedSize)
253 throw std::runtime_error ("column size doesn't match expected size: " + column.debugName + ", found " + std::to_string (sizeVector[columnIndex]) + " vs exptected=" + std::to_string (expectedSize) + " isOffset=" + std::to_string (column.isOffset));
254 }
255 }
256
257
258
259 ColumnVectorData ::
260 ColumnVectorData (const ColumnVectorHeader *val_header)
261 : m_header (val_header),
262 m_data (val_header->numColumns(), nullptr),
263 m_dataSize (val_header->numColumns(), 0u)
264 {
266 }
267
268
269
270 void ColumnVectorData ::
271 setColumnVoid (std::size_t columnIndex, std::size_t size, const void *dataPtr, const std::type_info& type, bool isConst)
272 {
273 if (columnIndex == ColumnVectorHeader::nullIndex)
274 throw std::logic_error ("cannot set the null column");
275 if (columnIndex >= m_header->numColumns())
276 throw std::logic_error ("invalid column index: " + std::to_string(columnIndex) + " (max is " + std::to_string(m_header->numColumns()-1) + ")");
277 auto& header = m_header->getColumn (columnIndex);
278
279 // If dataPtr is null, we use a dummy value to avoid issues in which
280 // we check whether a column exists by checking for a null pointer,
281 // which would return false for columns that were set with a
282 // nullptr.
283 if (dataPtr == nullptr)
284 {
285 if (size != 0) [[unlikely]]
286 throw std::logic_error ("dataPtr is null but size is not zero for column: " + header.debugName);
287 static const unsigned dummyValue = 0;
288 dataPtr = &dummyValue;
289 }
290
291 if (type != *header.type)
292 throw std::runtime_error ("invalid type for column: " + header.debugName);
293 if (isConst && !header.readOnly)
294 throw std::runtime_error ("assigning const vector to a column that is not read-only: " + header.debugName);
295 if (m_data[columnIndex] != nullptr)
296 throw std::runtime_error ("column filled multiple times: " + header.debugName);
297 auto *castDataPtr ATLAS_THREAD_SAFE = const_cast<void*>(dataPtr);
298 m_data[columnIndex] = castDataPtr;
299 m_dataSize[columnIndex] = size;
300 }
301
302
303
304 std::pair<std::size_t,const void*> ColumnVectorData ::
305 getColumnVoid (std::size_t columnIndex, const std::type_info *type, bool isConst) const
306 {
307 if (columnIndex >= m_header->numColumns())
308 throw std::runtime_error ("invalid column index: " + std::to_string(columnIndex) + " (max is " + std::to_string(m_header->numColumns()-1) + ")");
309
310 auto& header = m_header->getColumn (columnIndex);
311 if (*type != *header.type)
312 throw std::runtime_error ("invalid type for column: " + header.debugName);
313 if (!isConst && header.readOnly)
314 throw std::runtime_error ("retrieving non-const vector from a read-only column: " + header.debugName);
315 if (m_data[columnIndex] != nullptr)
316 return std::make_pair (m_dataSize[columnIndex], m_data[columnIndex]);
317 else
318 return std::make_pair (0u, nullptr);
319 }
320
321
322
323 void ColumnVectorData ::
324 callNoCheck (const IColumnarTool& tool)
325 {
326 tool.callVoid (m_data.data());
327 }
328
329
330
331 std::unordered_map<std::string, ColumnInfo> ColumnVectorHeader ::
332 getAllColumnInfo () const
333 {
334 std::unordered_map<std::string, ColumnInfo> result;
335 // Skip the fixed columns (null and size)
336 for (std::size_t i = numFixedColumns; i < m_elements.size(); ++i)
337 {
338 const auto& header = m_elements[i];
339 ColumnInfo info;
340 info.name = header.debugName;
341 info.index = static_cast<unsigned>(i);
342 info.type = header.type;
343 info.accessMode = header.accessMode;
344 info.offsetName = header.offsetName;
345 info.fixedDimensions = header.fixedDimensions;
346 info.isOffset = header.isOffset;
347 info.isOptional = header.isOptional;
348 info.soleLinkTargetName = header.soleLinkTargetName;
349 info.soleLinkTargetClid = header.soleLinkTargetClid;
350 info.isVariantLink = header.isVariantLink;
351 info.variantLinkTargetNames = header.variantLinkTargetNames;
352 info.keyColumnForVariantLink = header.keyColumnForVariantLink;
353 result.emplace(info.name, std::move(info));
354 }
355 return result;
356 }
357}
char data[hepevt_bytes_allocation_ATLAS]
Definition HepEvt.cxx:11
size_t size() const
Number of registered mappings.
Define macros for attributes used to control the static checker.
#define ATLAS_THREAD_SAFE
const ColumnVectorHeader * m_header
void setColumn(std::size_t columnIndex, std::size_t size, CT *dataPtr)
set the data for the given column
std::vector< std::size_t > m_dataSize
the header information for the entire columnar data vector
std::size_t addColumn(const ColumnInfo &columnInfo)
add a column for the given ColumnInfo, returning its index
static constexpr std::size_t nullIndex
the index used for an invalid index (always has to be 0)
static constexpr std::size_t numFixedColumns
the number of fix elements in the columnar data vector
std::unordered_map< std::string, std::size_t > m_nameToIndex
map from column name to index for deduplication
static constexpr std::size_t unsetIndex
the number used for an unset but non-null index
std::vector< ColumnVectorElementHeader > m_elements
the elements in the columnar data vector
static constexpr std::size_t sizeIndex
the index used for the column size column
an interface for tools that operate on columnar data
@ update
an updateable column
Definition ColumnInfo.h:28
@ output
an output column
Definition ColumnInfo.h:25
@ input
an input column
Definition ColumnInfo.h:22
std::size_t ColumnarOffsetType
the type used for the size and offsets in the columnar data
#define unlikely(x)
a struct that contains meta-information about each column that's needed to interface the column with ...
Definition ColumnInfo.h:36
std::string offsetName
the name of the offset column used for this column (or empty string for none)
Definition ColumnInfo.h:75
std::string soleLinkTargetName
for simple link columns: the name of the target container
Definition ColumnInfo.h:132
std::string keyColumnForVariantLink
if this is a key column for a variant link, the name of the associated link column
Definition ColumnInfo.h:192
std::uint32_t soleLinkTargetClid
for simple link columns: the CLID of the target container
Definition ColumnInfo.h:146
std::vector< unsigned > fixedDimensions
the fixed dimensions this column has (if any)
Definition ColumnInfo.h:83
bool isOptional
whether this column is optional
Definition ColumnInfo.h:122
std::vector< std::string > variantLinkTargetNames
for variant link key columns: the names of the containers we can link to
Definition ColumnInfo.h:177
std::string name
the name of the column
Definition ColumnInfo.h:43
bool isOffset
whether this is an offset column
Definition ColumnInfo.h:93
ColumnAccessMode accessMode
the access mode for the column
Definition ColumnInfo.h:59
bool isVariantLink
whether this is a variant link column
Definition ColumnInfo.h:154
const std::type_info * type
the type of the individual entries in the column
Definition ColumnInfo.h:55