ATLAS Offline Software
VariantLinkColumn.h
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3 */
4 
6 
7 
8 #ifndef COLUMNAR_VARIANT_VARIANT_LINK_COLUMN_H
9 #define COLUMNAR_VARIANT_VARIANT_LINK_COLUMN_H
10 
15 
16 namespace columnar
17 {
37 
38  template<ContainerIdConcept CIBase,ContainerIdConcept... CIList>
40  {
43  public:
44 
45  using CI = VariantContainerId<CIBase,CIList...>;
47 
49 
50  ObjectLink (const LinkType* val_link)
51  : m_link (val_link)
52  {}
53 
54  const typename CI::xAODObjectIdType* getXAODObject () const
55  {
56  if (m_link->isValid())
57  {
58  return **m_link;
59  } else
60  {
61  return nullptr;
62  }
63  }
64 
66  explicit operator bool () const noexcept
67  {
68  return m_link->isValid();
69  }
70 
72  [[nodiscard]] bool has_value () const noexcept
73  {
74  return m_link->isValid();
75  }
76 
78  [[nodiscard]] OptObjectId<CI,CM> opt_value () const
79  {
81  }
82 
88  template<ContainerIdConcept CI2>
89  [[nodiscard]] bool isContainer () const
90  {
91  static constexpr unsigned variantIndex = CI::template getVariantIndex<CI2>();
92  static_assert (variantIndex < CI::numVariants, "invalid container id");
93  return m_link->isValid() && dynamic_cast<typename CI2::xAODObjectRangeType*>(m_link->getStorableObjectPointer());
94  }
95 
97  template<ContainerIdConcept CI2>
98  [[nodiscard]] bool operator == (ObjectId<CI2,CM> id) const
99  {
100  static constexpr unsigned variantIndex = CI::template getVariantIndex<CI2>();
101  static_assert (variantIndex < CI::numVariants, "invalid container id");
102  return m_link->isValid() && (**m_link) == &id.getXAODObject();
103  }
104 
110  [[nodiscard]] bool operator == (const ObjectLink<CI,CM>& obj) const
111  {
112  return m_link == obj.m_link;
113  }
114 
116  template<ContainerIdConcept CI2>
117  [[nodiscard]] OptObjectId<CI2,CM> tryGetVariant () const
118  {
119  static constexpr unsigned variantIndex = CI::template getVariantIndex<CI2>();
120  static_assert (variantIndex < CI::numVariants, "invalid container id");
121  if (m_link->isValid())
122  {
123  return OptObjectId<CI2,CM> (dynamic_cast<const typename CI2::xAODObjectIdType*>(**m_link));
124  } else
125  return OptObjectId<CI2,CM> ();
126  }
127 
130  private:
131 
132  const LinkType* m_link = nullptr;
133  };
134  template<typename... CIList>
136  {
137  return str << obj.getXAODObject() << "/" << obj.getXAODObject()->type();
138  }
139 
140  // in xAOD mode we can do a fairly straightforward conversion from
141  // ElementLink as the logic is inside ObjectLink
142  template<ContainerIdConcept CIBase,typename... CIList>
144  {
145  using CI = VariantContainerId<CIBase,CIList...>;
149  static constexpr bool isNativeType = false;
150  static constexpr bool useConvertInput = true;
151  static constexpr bool useConvertWithDataInput = false;
152  static constexpr bool useConvertOutput = true;
153  static ColumnInfo& updateColumnInfo (ColumnarTool<CM>& /*columnBase*/, ColumnInfo& info) {return info;}
154  static auto convertInput (const LinkType& value) {
155  return ObjectLink<VariantContainerId<CIBase,CIList...>,ColumnarModeXAOD> (&value);
156  };
157  template<ContainerIdConcept CI2>
158  requires (CI::template isValidContainer<CI2>())
159  static auto convertOutput (const ObjectId<CI2,ColumnarModeXAOD>& obj) noexcept
160  {
161  auto* container = static_cast<const typename CIBase::xAODElementLinkType*>(obj.getXAODObjectNoexcept().container());
162  return LinkType(*container, obj.getXAODObjectNoexcept().index());
163  }
165  };
166 
167 
168 
169  template<ContainerIdConcept CIBase,ContainerIdConcept... CIList>
171  {
174  public:
175 
176  using CI = VariantContainerId<CIBase,CIList...>;
178 
179  ObjectLink (typename CM::LinkIndexType val_link, const typename CM::LinkKeyType* val_keys, void** val_data)
180  : m_link (val_link), m_keys (val_keys), m_data (val_data)
181  {}
182 
183  const typename CI::xAODObjectIdType* getXAODObject () const
184  {
185  throw std::logic_error ("can't call xAOD function in columnar mode");
186  }
187 
189  explicit operator bool () const noexcept
190  {
191  return m_link != invalidObjectIndex;
192  }
193 
195  [[nodiscard]] bool has_value () const noexcept
196  {
197  return m_link != invalidObjectIndex;
198  }
199 
201  [[nodiscard]] OptObjectId<CI,CM> opt_value () const
202  {
203  if (m_link == CM::invalidLinkValue)
204  return OptObjectId<CI,CM> ();
205  const auto key = getLinkKey();
206  for (unsigned i = 0; i < CI::numVariants; ++ i)
207  {
208  if (m_keys[i] == key)
209  return OptObjectId<CI,CM> (m_data, i, getLinkIndex());
210  }
211  // not sure whether we should throw here or return a nullopt, but
212  // throwing is probably the safer default. if it becomes an issue
213  // we can revisit this.
214  throw std::runtime_error ("link key does not match any known container: " + std::to_string(key));
215  }
216 
222  template<ContainerIdConcept CI2>
223  [[nodiscard]] bool isContainer () const
224  {
225  static constexpr unsigned variantIndex = CI::template getVariantIndex<CI2>();
226  static_assert (variantIndex < CI::numVariants, "invalid container id");
227  return getLinkKey() == m_keys[variantIndex];
228  }
229 
231  template<ContainerIdConcept CI2>
232  [[nodiscard]] bool operator == (ObjectId<CI2,CM> id) const
233  {
234  static constexpr unsigned variantIndex = CI::template getVariantIndex<CI2>();
235  static_assert (variantIndex < CI::numVariants, "invalid container id");
236  return getLinkIndex() == id.getIndex() && getLinkKey() == m_keys[variantIndex];
237  }
238 
244  [[nodiscard]] bool operator == (const ObjectLink<CI,CM>& obj) const
245  {
246  if (m_keys == obj.m_keys)
247  return m_link == obj.m_link;
248  if (getLinkIndex() != obj.getLinkIndex())
249  return false;
250  const auto thisKey = getLinkKey();
251  const auto thatKey = obj.getLinkKey();
252  for (unsigned i = 0; i < CI::numVariants; ++ i)
253  {
254  if (m_keys[i] == thisKey)
255  {
256  if (obj.m_keys[i] == thatKey)
257  return true;
258  else
259  return false;
260  } else if (obj.m_keys[i] == thatKey)
261  return false;
262  }
263  return false;
264  }
265 
267  template<ContainerIdConcept CI2>
268  [[nodiscard]] OptObjectId<CI2,CM> tryGetVariant () const
269  {
270  static constexpr unsigned variantIndex = CI::template getVariantIndex<CI2>();
271  static_assert (variantIndex < CI::numVariants, "invalid container id");
272  if (getLinkKey() == m_keys[variantIndex])
273  return OptObjectId<CI2,CM> (m_data, getLinkIndex());
274  else
275  return OptObjectId<CI2,CM> ();
276  }
277 
278  [[nodiscard]] auto getLinkIndex () const noexcept
279  {
280  return CM::getLinkIndex (m_link);
281  }
282 
283  [[nodiscard]] auto getLinkKey () const noexcept
284  {
285  return CM::getLinkKey (m_link);
286  }
287 
290  private:
291 
292  typename CM::LinkIndexType m_link = 0;
293  const CM::LinkKeyType* m_keys = nullptr;
294  void** m_data = nullptr;
295  };
296  template<typename... CIList>
298  {
299  return str << obj.getLinkKey() << "/" << obj.getLinkIndex();
300  }
301 
302 
303 
304  // in external mode we need to use a vector column, as well as an
305  // extra column to contain our keys in order.
308  {
311  public:
312 
313  using VariantCI = VariantContainerId<CIBase,CIList...>;
315  static constexpr std::array containerIdNames = {CIList::idName...};
316 
317  AccessorTemplate () = default;
318 
319  AccessorTemplate (ColumnarTool<CM>& columnBase, const std::string& name, ColumnInfo&& info = {})
320  {
321  std::string dataName = std::string (CI::idName) + "." + name;
322  std::string keysName = std::string (CI::idName) + "." + name + ".keys";
323 
324  auto dataInfo = info;
325  dataInfo.offsetName = CI::idName;
326  dataInfo.variantLinkKeyColumn = keysName;
327  dataInfo.linkTargetNames.reserve (VariantCI::numVariants);
328  for (unsigned i = 0; i < VariantCI::numVariants; ++ i)
329  dataInfo.linkTargetNames.emplace_back (containerIdNames[i]);
330  auto keyInfo = info;
331  keyInfo.accessMode = ColumnAccessMode::input;
332  keyInfo.fixedDimensions.push_back (VariantCI::numVariants);
333 
334  m_dataData = std::make_unique<ColumnAccessorDataArray> (&m_dataIndex, &m_dataData, &typeid (typename CM::LinkIndexType), CAM);
335  columnBase.addColumn (dataName, m_dataData.get(), std::move (dataInfo));
336  m_keysData = std::make_unique<ColumnAccessorDataArray> (&m_keysIndex, &m_keysData, &typeid (typename CM::LinkKeyType), ColumnAccessMode::input);
337  columnBase.addColumn (keysName, m_keysData.get(), std::move (keyInfo));
338  }
339 
341  {
342  moveAccessor (m_dataIndex, m_dataData, that.m_dataIndex, that.m_dataData);
343  moveAccessor (m_keysIndex, m_keysData, that.m_keysIndex, that.m_keysData);
344  }
345 
347  {
348  if (this != &that)
349  {
350  moveAccessor (m_dataIndex, m_dataData, that.m_dataIndex, that.m_dataData);
351  moveAccessor (m_keysIndex, m_keysData, that.m_keysIndex, that.m_keysData);
352  }
353  return *this;
354  }
355 
356  auto operator () (ObjectId<CI,CM> id) const noexcept
358  {
359  auto *data = static_cast<const typename CM::LinkIndexType*>(id.getData()[m_dataIndex]);
360  auto *keys = static_cast<const typename CM::LinkKeyType*>(id.getData()[m_keysIndex]);
361  return ObjectLink<VariantContainerId<CIBase,CIList...>,ColumnarModeArray> (data[id.getIndex()], keys, id.getData());
362  }
363 
364  template<ContainerIdConcept CI2>
365  requires (CAM == ColumnAccessMode::output && VariantCI::template isValidContainer<CI2>())
366  void set (ObjectId<CI,CM> id, ObjectId<CI2,ColumnarModeArray> obj) const noexcept
367  {
368  auto *data = static_cast<typename CM::LinkIndexType*>(id.getData()[m_dataIndex]);
369  auto *keys = static_cast<const typename CM::LinkKeyType*>(id.getData()[m_keysIndex]);
370  data[id.getIndex()] = CM::mergeLinkKeyIndex (keys[VariantCI::template getVariantIndex<CI2>()], obj.getIndex());
371  }
372 
373  [[nodiscard]] bool isAvailable (ObjectId<CI,CM> id) const noexcept
374  {
375  auto *data = static_cast<const typename CM::LinkIndexType*>(id.getData()[m_dataIndex]);
376  return data != nullptr;
377  }
378 
379 
380 
383  private:
384 
385  unsigned m_dataIndex = 0u;
386  std::unique_ptr<ColumnAccessorDataArray> m_dataData;
387  unsigned m_keysIndex = 0u;
388  std::unique_ptr<ColumnAccessorDataArray> m_keysData;
389  };
390 
391 
392 
393  // in external mode we need to use a vector column, as well as an
394  // extra column to contain our keys in order.
396  class AccessorTemplate<CI,std::vector<ObjectLink<VariantContainerId<CIBase,CIList...>,ColumnarModeArray>>,ColumnAccessMode::input,ColumnarModeArray> final
397  {
400  public:
401 
402  using VariantCI = VariantContainerId<CIBase,CIList...>;
405  static constexpr std::array containerIdNames = {CIList::idName...};
406 
407  AccessorTemplate () = default;
408 
409  AccessorTemplate (ColumnarTool<CM>& columnBase, const std::string& name, ColumnInfo&& info = {})
410  {
411  std::string offsetName = std::string (CI::idName) + "." + name + ".offset";
412  std::string dataName = std::string (CI::idName) + "." + name + ".data";
413  std::string keysName = std::string (CI::idName) + "." + name + ".keys";
414 
415  auto offsetInfo = info;
416  offsetInfo.offsetName = CI::idName;
417  offsetInfo.isOffset = true;
418  auto dataInfo = info;
419  dataInfo.offsetName = offsetName;
420  dataInfo.variantLinkKeyColumn = keysName;
421  dataInfo.linkTargetNames.reserve (VariantCI::numVariants);
422  for (unsigned i = 0; i < VariantCI::numVariants; ++ i)
423  dataInfo.linkTargetNames.emplace_back (containerIdNames[i]);
424  auto keyInfo = info;
425  keyInfo.fixedDimensions.push_back (VariantCI::numVariants);
426 
427  m_offsetData = std::make_unique<ColumnAccessorDataArray> (&m_offsetIndex, &m_offsetData, &typeid (ColumnarOffsetType), ColumnAccessMode::input);
428  columnBase.addColumn (offsetName, m_offsetData.get(), std::move (offsetInfo));
429  m_dataData = std::make_unique<ColumnAccessorDataArray> (&m_dataIndex, &m_dataData, &typeid (typename CM::LinkIndexType), ColumnAccessMode::input);
430  columnBase.addColumn (dataName, m_dataData.get(), std::move (dataInfo));
431  m_keysData = std::make_unique<ColumnAccessorDataArray> (&m_keysIndex, &m_keysData, &typeid (typename CM::LinkKeyType), ColumnAccessMode::input);
432  columnBase.addColumn (keysName, m_keysData.get(), std::move (keyInfo));
433  }
434 
436  {
437  moveAccessor (m_offsetIndex, m_offsetData, that.m_offsetIndex, that.m_offsetData);
438  moveAccessor (m_dataIndex, m_dataData, that.m_dataIndex, that.m_dataData);
439  moveAccessor (m_keysIndex, m_keysData, that.m_keysIndex, that.m_keysData);
440  }
441 
443  {
444  if (this != &that)
445  {
446  moveAccessor (m_offsetIndex, m_offsetData, that.m_offsetIndex, that.m_offsetData);
447  moveAccessor (m_dataIndex, m_dataData, that.m_dataIndex, that.m_dataData);
448  moveAccessor (m_keysIndex, m_keysData, that.m_keysIndex, that.m_keysData);
449  }
450  return *this;
451  }
452 
453  auto operator () (ObjectId<CI,CM> id) const noexcept
454  {
455  auto *offset = static_cast<const ColumnarOffsetType*>(id.getData()[m_offsetIndex]);
456  auto *data = static_cast<const typename CM::LinkIndexType*>(id.getData()[m_dataIndex]);
457  auto *keys = static_cast<const typename CM::LinkKeyType*>(id.getData()[m_keysIndex]);
458  return detail::VectorConvertView ([keys,data=id.getData()](typename CM::LinkIndexType value) {return ObjectLink<VariantContainerId<CIBase,CIList...>,ColumnarModeArray> (value, keys,data);}, std::span<const typename CM::LinkIndexType> (data + offset[id.getIndex()], offset[id.getIndex()+1]-offset[id.getIndex()]));
459  }
460 
463  private:
464 
465  unsigned m_offsetIndex = 0u;
466  std::unique_ptr<ColumnAccessorDataArray> m_offsetData;
467  unsigned m_dataIndex = 0u;
468  std::unique_ptr<ColumnAccessorDataArray> m_dataData;
469  unsigned m_keysIndex = 0u;
470  std::unique_ptr<ColumnAccessorDataArray> m_keysData;
471  };
472 
473  template<ContainerIdConcept CIBase,ContainerIdConcept... CIList,typename ELT>
475  {
476  using CI = VariantContainerId<CIBase,CIList...>;
480  static constexpr bool isNativeType = false;
481  static constexpr bool useConvertInput = true;
482  static constexpr bool useConvertWithDataInput = false;
483  static ColumnInfo& updateColumnInfo (ColumnarTool<CM>& /*columnBase*/, ColumnInfo& info) {return info;}
485  return value.opt_value();
486  };
487  };
488 }
489 
490 #endif
data
char data[hepevt_bytes_allocation_ATLAS]
Definition: HepEvt.cxx:11
VariantOptObjectId.h
InDetSimDataHelpers::getData
const InDetSimData * getData(const InDetSimDataCollection &coll, const Identifier &id)
Definition: InDetSimDataDict.h:24
columnar::VariantContainerId
a "variant" ContainerId
Definition: VariantDef.h:98
LinkColumn.h
columnar::ColumnAccessMode::input
@ input
an input column
columnar::ColumnTypeTraits::useConvertWithDataInput
static constexpr bool useConvertWithDataInput
Definition: ColumnAccessor.h:99
columnar::ColumnTypeTraits::useConvertInput
static constexpr bool useConvertInput
Definition: ColumnAccessor.h:98
VariantDef.h
columnar::moveAccessor
void moveAccessor(unsigned &dataIndex, std::unique_ptr< ColumnAccessorDataArray > &accessorData, unsigned &sourceIndex, std::unique_ptr< ColumnAccessorDataArray > &sourceData)
Definition: ColumnAccessorDataArray.cxx:30
m_data
std::vector< T > m_data
Definition: TrackTruthMatchingBaseAlg.cxx:660
columnar::ColumnTypeTraits< LinkCastColumn< VariantContainerId< CIBase, CIList... >, ELT >, ColumnarModeArray >::updateColumnInfo
static ColumnInfo & updateColumnInfo(ColumnarTool< CM > &, ColumnInfo &info)
Definition: VariantLinkColumn.h:483
columnar::getXAODObject
xAODContainer & getXAODObject() const noexcept
Definition: ObjectRange.h:151
taskman.template
dictionary template
Definition: taskman.py:314
athena.value
value
Definition: athena.py:124
columnar::m_offsetIndex
unsigned m_offsetIndex
Definition: VectorColumn.h:115
columnar::OptObjectId
a class representing a single optional object (electron, muons, etc.)
Definition: ContainerId.h:179
columnar::operator=
AccessorTemplate & operator=(AccessorTemplate &&that)
Definition: VectorColumn.h:88
const
bool const RAWDATA *ch2 const
Definition: LArRodBlockPhysicsV0.cxx:560
MuonR4::to_string
std::string to_string(const SectorProjector proj)
Definition: MsTrackSeeder.cxx:66
CI
std::map< std::string, HypoJetVector >::const_iterator CI
Definition: xAODJetCollector.h:18
Trk::u
@ u
Enums for curvilinear frames.
Definition: ParamDefs.h:77
columnar::ColumnAccessMode::output
@ output
an output column
columnar::operator==
bool operator==(const ObjectId< CI, ColumnarModeXAOD > &lhs, const ObjectId< CI, ColumnarModeXAOD > &rhs)
Definition: ObjectId.h:82
columnar::VariantContainerId::xAODObjectIdType
typename CIBase::xAODObjectIdType xAODObjectIdType
the xAOD type to use with ObjectId
Definition: VariantDef.h:114
columnar::ColumnInfo
a struct that contains meta-information about each column that's needed to interface the column with ...
Definition: ColumnInfo.h:35
columnar::ColumnarModeArray::LinkIndexType
std::size_t LinkIndexType
the type used for columns that represent element links
Definition: ColumnarDef.h:68
lumiFormat.i
int i
Definition: lumiFormat.py:85
vector
Definition: MultiHisto.h:13
VectorColumn.h
columnar::ColumnAccessMode
ColumnAccessMode
an enum for the different access modes for a column
Definition: ColumnInfo.h:19
columnar::ColumnTypeTraits::isNativeType
static constexpr bool isNativeType
Definition: ColumnAccessor.h:97
columnar::final
CM final
Definition: ColumnAccessor.h:106
lumiFormat.array
array
Definition: lumiFormat.py:91
columnar::ObjectId
a class representing a single object (electron, muons, etc.)
Definition: ContainerId.h:178
columnar::isAvailable
bool isAvailable(ObjectId< CI, CM > id) const noexcept
Definition: ColumnAccessor.h:181
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:240
columnar::NativeColumn
a type wrapper to force AccessorTemplate to treat the type as native
Definition: ColumnAccessor.h:120
columnar::invalidObjectIndex
constexpr ColumnarOffsetType invalidObjectIndex
the value for an invalid element index
Definition: IColumnarTool.h:25
columnar::detail::VectorConvertView
VectorConvertView(FunctionType &&, ViewType &&) -> VectorConvertView< std::remove_cv_t< FunctionType >, std::remove_cv_t< ViewType >>
columnar::set
void set(ObjectId< CI, CM > id, T &&value) const noexcept
Definition: ColumnAccessor.h:218
python.Dumpers.typename
def typename(t)
Definition: Dumpers.py:193
columnar::ColumnarModeArray::LinkKeyType
std::uint8_t LinkKeyType
the type used for the key column
Definition: ColumnarDef.h:77
columnar::ColumnarModeArray
Definition: ColumnarDef.h:33
columnar::ContainerIdConcept
concept ContainerIdConcept
concept for a container id
Definition: ContainerId.h:171
columnar::ColumnTypeTraits
a trait class to provide information about the column type
Definition: ColumnAccessor.h:96
columnar
Definition: ClusterDef.h:16
columnar::m_offsetData
std::unique_ptr< ColumnAccessorDataArray > m_offsetData
Definition: VectorColumn.h:116
columnar::ColumnarTool
the base class for all columnar components
Definition: ColumnAccessorDataArray.h:17
columnar::ColumnarModeXAOD
Definition: ColumnarDef.h:18
columnar::requires
requires requires
Definition: VariantAccessor.h:22
columnar::m_dataData
std::unique_ptr< ColumnAccessorDataArray > m_dataData
Definition: VectorColumn.h:118
convertTimingResiduals.offset
offset
Definition: convertTimingResiduals.py:71
columnar::ColumnTypeTraits< LinkCastColumn< VariantContainerId< CIBase, CIList... >, ELT >, ColumnarModeArray >::convertInput
static UserType convertInput(const ColumnType &value)
Definition: VariantLinkColumn.h:484
str
Definition: BTagTrackIpAccessor.cxx:11
python.Bindings.keys
keys
Definition: Control/AthenaPython/python/Bindings.py:801
columnar::AccessorTemplate
the raw column accessor template class
Definition: ColumnAccessor.h:81
columnar::LinkCastColumn
a special column type that behaves like an OptObjectId, but applies an internal cast in xAOD mode
Definition: LinkColumn.h:25
columnar::operator()
decltype(auto) operator()(ObjectId< CI, CM > id) const noexcept
Definition: ColumnAccessor.h:173
python.PyAthena.obj
obj
Definition: PyAthena.py:132
xAOD::bool
setBGCode setTAP setLVL2ErrorBits bool
Definition: TrigDecision_v1.cxx:60
columnar::ColumnarOffsetType
std::size_t ColumnarOffsetType
the type used for the size and offsets in the columnar data
Definition: IColumnarTool.h:20
python.ParticleTypeUtil.info
def info
Definition: ParticleTypeUtil.py:87
columnar::m_dataIndex
unsigned m_dataIndex
Definition: VectorColumn.h:117
columnar::operator<<
std::ostream & operator<<(std::ostream &str, const ObjectId< CI, ColumnarModeXAOD > &obj)
Definition: ObjectId.h:76
mapkey::key
key
Definition: TElectronEfficiencyCorrectionTool.cxx:37