2 * Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration.
5 * @file GeneratorObjects/HepMcParticleLink.icc
6 * @author scott snyder <snyder@bnl.gov>
8 * @brief a link optimized in size for a GenParticle in a McEventCollection
12 //**************************************************************************
17 HepMcParticleLink::ExtendedBarCode::ExtendedBarCode()
24 * @param uid Unique ID of target particle.
25 * @param eventIndex Identifies the target GenEvent in a McEventCollection,
26 * as either the event number if @c isIndexEventPosition is IS_EVENTNUM,
27 * or the position in the container
28 * if isIndexEventPosition is IS_POSITION.
29 * 0 always means the first event in the collection.
30 * @param isIndexEventPosition: See @c eventIndex.
33 HepMcParticleLink::ExtendedBarCode::ExtendedBarCode
35 index_type eventIndex,
36 PositionFlag isIndexEventPosition /*=IS_EVENTNUM*/,
37 UniqueIDFlag isUniqueIDBarcode /*= IS_ID*/)
39 setIndex (eventIndex, isIndexEventPosition);
40 setUniqueID (uid, isUniqueIDBarcode);
45 * @brief Copy constructor. (Can't be defaulted due to the atomic member.)
48 HepMcParticleLink::ExtendedBarCode::ExtendedBarCode (const ExtendedBarCode& rhs)
49 : m_BC (static_cast<barcode_type> (rhs.m_BC)),
50 m_evtIndex (static_cast<index_type> (rhs.m_evtIndex))
56 * @brief Move constructor. (Can't be defaulted due to the atomic member.)
59 HepMcParticleLink::ExtendedBarCode::ExtendedBarCode (ExtendedBarCode&& rhs) noexcept
60 : m_BC (rhs.m_BC.load()), // no move constructor for atomics
61 m_evtIndex (rhs.m_evtIndex.load()) // no move constructor for atomics
66 * @brief Assignment. (Can't be defaulted due to the atomic member.)
69 HepMcParticleLink::ExtendedBarCode&
70 HepMcParticleLink::ExtendedBarCode::operator= (const ExtendedBarCode& rhs)
73 m_BC = static_cast<barcode_type> (rhs.m_BC);
74 m_evtIndex = static_cast<index_type> (rhs.m_evtIndex);
80 * @brief Assignment. (Can't be defaulted due to the atomic member.)
83 HepMcParticleLink::ExtendedBarCode&
84 HepMcParticleLink::ExtendedBarCode::operator= (ExtendedBarCode&& rhs) noexcept
87 m_BC = static_cast<barcode_type> (rhs.m_BC.load());
88 m_evtIndex = static_cast<index_type>(rhs.m_evtIndex.load());
95 * @brief Unique ID of target variable (0 for a null link).
98 HepMcParticleLink::barcode_type
99 HepMcParticleLink::ExtendedBarCode::uid() const
106 * @brief Return the event index/position.
107 * @param index[out] Event index (number), or @c UNDEFINED.
108 * @param position[out] Event position, or @c UNDEFINED.
110 * The GenEvent within the McEventCollection is identified either by
111 * the GenEvent number or by the position within the collection.
112 * This method will return this by setting either @c index or @c position;
113 * the other one is set to @c UNDEFINED.
116 void HepMcParticleLink::ExtendedBarCode::eventIndex (index_type& index,
117 index_type& position) const
119 index_type idx = m_evtIndex;
120 if (idx & POSITION_MASK) {
122 position = idx & ~POSITION_MASK;
126 position = UNDEFINED;
132 * @brief Return the GenParticle id/barcode.
133 * @param id[out] GenParticle::id, or @c UNDEFINEDBC.
134 * @param barcode[out] barcode (deprecated), or @c UNDEFINEDBC.
136 * The GenParticle within the GenEvent is identified either by
137 * the GenParticle::id or the barcode.
138 * This method will return this by setting either @c id or @c barcode;
139 * the other one is set to @c UNDEFINEDBC.
142 void HepMcParticleLink::ExtendedBarCode::uniqueID (barcode_type& id,
143 barcode_type& barcode) const
145 barcode_type uid = m_BC;
146 if (uid == 0) // special case for delta-rays
151 else if (uid & BARCODE_MASK) {
153 barcode = uid & ~BARCODE_MASK;
157 barcode = UNDEFINEDBC;
163 * @brief Equality test.
165 * Be aware: if one EBC holds the target GenEvent by number and the
166 * other by position, then this will always return false, even if they
167 * reference the same GenEvent.
168 * To avoid this, use HepMcParticleLink::operator=.
172 HepMcParticleLink::ExtendedBarCode::operator==(const ExtendedBarCode& rhs) const
174 return (this->m_BC == rhs.m_BC &&
175 this->m_evtIndex == rhs.m_evtIndex);
180 * @brief Inequality test.
182 * Be aware: if one EBC holds the target GenEvent by number and the
183 * other by position, then this will always return true, even if they
184 * reference the same GenEvent.
185 * To avoid this, use HepMcParticleLink::operator=.
189 HepMcParticleLink::ExtendedBarCode::operator!= (const ExtendedBarCode& rhs) const
191 return !(operator==(rhs));
196 * @brief Ordering test.
198 * Be aware: if one EBC holds the target GenEvent by number and the
199 * other by position, then this will not work as expected.
200 * To avoid this, use HepMcParticleLink::operator=.
204 HepMcParticleLink::ExtendedBarCode::operator< (const ExtendedBarCode& rhs) const
207 (m_evtIndex < rhs.m_evtIndex) ||
208 (m_evtIndex == rhs.m_evtIndex && m_BC < rhs.m_BC) ) ;
213 * @brief Compare the event index part of two links.
214 * @param lhs First link to compare.
215 * @param rhs Second link to compare.
216 * @returns -1, 0, or 1, depending on the result of the comparison.
218 * The event index part of the link can be represented as either
219 * an event number or the position within the container.
220 * If necessary, the links will be normalized so that they
221 * both refer to an event number.
225 HepMcParticleLink::ExtendedBarCode::compareIndex (const HepMcParticleLink& lhs,
226 const HepMcParticleLink& rhs)
228 // Get the stored indices. The high bit will be set of they
229 // represent a position. Do a quick test for equality.
230 index_type idx1 = lhs.m_extBarcode.m_evtIndex;
231 index_type idx2 = rhs.m_extBarcode.m_evtIndex;
232 if (idx1 == idx2) return 0;
234 // Normalize the values so that they both refer to event number;
235 // this happens as a side-effect of calling cptr().
236 if (idx1 & POSITION_MASK) {
238 idx1 = lhs.m_extBarcode.m_evtIndex;
240 if (idx2 & POSITION_MASK) {
242 idx2 = rhs.m_extBarcode.m_evtIndex;
249 else if (idx1 < idx2) {
260 * @brief Compare the unique ID part of two links.
261 * @param lhs First link to compare.
262 * @param rhs Second link to compare.
263 * @returns -1, 0, or 1, depending on the result of the comparison.
265 * The unique ID part of the link can be represented as either
266 * a barcode or the id.
267 * If necessary, the links will be normalized so that they
268 * both refer to an id.
272 HepMcParticleLink::ExtendedBarCode::compareUniqueID (const HepMcParticleLink& lhs,
273 const HepMcParticleLink& rhs)
275 // Get the stored indices. The high bit will be set of they
276 // represent a position. Do a quick test for equality.
277 barcode_type uid1 = lhs.m_extBarcode.m_BC;
278 barcode_type uid2 = rhs.m_extBarcode.m_BC;
279 if (uid1 == uid2) return 0;
281 // Normalize the values so that they both refer to the id;
282 // this happens as a side-effect of calling cptr().
283 if (uid1 & BARCODE_MASK) {
285 uid1 = lhs.m_extBarcode.m_BC;
287 if (uid2 & BARCODE_MASK) {
289 uid2 = rhs.m_extBarcode.m_BC;
295 else if (uid1 < uid2) {
305 * @brief Change m_BC from barcode to ID.
306 * @param ID GenParticle::id value to set.
307 * @param barcode existing barcode value.
309 * If the link is currently referencing a GenParticle with @c barcode,
310 * update it so that it instead references the GenParticle
311 * with id value @c ID.
313 * This may be called concurrently, as long as all such concurrent
314 * calls have the same arguments.
317 void HepMcParticleLink::ExtendedBarCode::makeID (barcode_type ID,
318 barcode_type barcode) const
320 assert ((ID & BARCODE_MASK) == 0);
321 barcode_type old = barcode | BARCODE_MASK;
322 m_BC.compare_exchange_strong (old, ID);
323 assert (old == (barcode|BARCODE_MASK) || old == ID);
328 * @brief Change index from position to number.
329 * @param index Event number to set.
330 * @param position Existing event position.
332 * If the link is currently referencing the GenEvent at @c position,
333 * update it so that it instead references the GenEvent
334 * with number @c index.
336 * This may be called concurrently, as long as all such concurrent
337 * calls have the same arguments.
340 void HepMcParticleLink::ExtendedBarCode::makeIndex (index_type index,
341 index_type position) const
343 assert ((index & POSITION_MASK) == 0);
344 index_type old = position | POSITION_MASK;
345 m_evtIndex.compare_exchange_strong (old, index);
346 assert (old == (position|POSITION_MASK) || old == index || (position==UNDEFINED && old==0));
351 * @brief Initialize the unique identifier part of the link.
352 * @param uid The id or barcode.
353 * @param barcodeFlag If IS_BARCODE, @c uid represents a GenParticle barcode (deprecated);
354 * otherwise, it represents a GenParticle::id().
358 HepMcParticleLink::ExtendedBarCode::setUniqueID (barcode_type uid,
359 UniqueIDFlag barcodeFlag)
361 assert ((uid & BARCODE_MASK) == 0);
362 // For delta-rays barcode=id=0
363 if (uid != 0 && barcodeFlag == IS_BARCODE) {
371 * @brief Initialize the event index part of the link.
372 * @param idx The index or position.
373 * @param positionFlag If IS_POSITION, @c idx represents a position
374 * in the collection; otherwise, it represents an event number.
378 HepMcParticleLink::ExtendedBarCode::setIndex (index_type idx,
379 PositionFlag positionFlag)
381 assert ((idx & POSITION_MASK) == 0);
382 if (positionFlag == IS_POSITION) {
383 idx |= POSITION_MASK;
388 inline bool HepMcParticleLink::ExtendedBarCode::linkIsNull() const
390 barcode_type particle_id, particle_barcode;
391 uniqueID (particle_id, particle_barcode);
393 (particle_id == 0 && particle_barcode == 0) || // delta rays
394 (particle_id == 0 && particle_barcode == ExtendedBarCode::UNDEFINEDBC) ||
395 (particle_id == ExtendedBarCode::UNDEFINEDBC && particle_barcode == 0)
400 //**************************************************************************
406 * @brief Default constructor. Makes a null link.
407 * @param sg Optional specification of a specific store to reference.
410 HepMcParticleLink::HepMcParticleLink (IProxyDict* sg /*= nullptr*/)
417 * @brief Default constructor. Makes a null link.
418 * @param ctx Context of the store to reference.
421 HepMcParticleLink::HepMcParticleLink (const EventContext& ctx)
422 : HepMcParticleLink (Atlas::getExtendedEventContext(ctx).proxy())
427 * @brief Constructor.
428 * @param uid Unique ID of the target particle. 0 means a null link.
429 * @param eventIndex Identifies the target GenEvent in a McEventCollection,
430 * as either the event number if @c isIndexEventPosition is IS_EVENTNUM,
431 * or the position in the container
432 * if isIndexEventPosition is IS_POSITION.
433 * 0 always means the first event in the collection.
434 * @param positionFlag: See @c eventIndex.
435 * @param sg Optional specification of a specific store to reference.
438 HepMcParticleLink::HepMcParticleLink (barcode_type uid,
439 uint32_t eventIndex /*= 0*/,
440 PositionFlag positionFlag /*= IS_EVENTNUM*/,
441 UniqueIDFlag uniqueIDFlag /*= IS_ID*/,
442 IProxyDict* sg /*= SG::CurrentEventStore::store()*/)
444 m_extBarcode (uid, eventIndex, positionFlag, uniqueIDFlag)
450 * @brief Constructor.
451 * @param uid Unique ID of the target particle. 0 means a null link.
452 * @param eventIndex Identifies the target GenEvent in a McEventCollection,
453 * as either the event number if @c isIndexEventPosition is IS_EVENTNUM,
454 * or the position in the container
455 * if isIndexEventPosition is IS_POSITION.
456 * 0 always means the first event in the collection.
457 * @param positionFlag: See @c eventIndex.
458 * @param ctx Context of the store to reference.
461 HepMcParticleLink::HepMcParticleLink (barcode_type uid,
463 PositionFlag positionFlag,
464 UniqueIDFlag uniqueIDFlag,
465 const EventContext& ctx)
466 : HepMcParticleLink (uid, eventIndex, positionFlag, uniqueIDFlag,
467 Atlas::getExtendedEventContext(ctx).proxy())
473 * @brief Constructor.
474 * @param p Particle to reference.
475 * @param eventIndex Identifies the target GenEvent in a McEventCollection,
476 * as either the event number if @c isIndexEventPosition is IS_EVENTNUM,
477 * or the position in the container
478 * if isIndexEventPosition is IS_POSITION.
479 * 0 always means the first event in the collection.
480 * @param positionFlag: See @c eventIndex.
481 * @param ctx Context of the store to reference.
484 HepMcParticleLink::HepMcParticleLink (const HepMC::ConstGenParticlePtr& part,
486 PositionFlag positionFlag,
487 const EventContext& ctx)
488 : HepMcParticleLink (part, eventIndex, positionFlag,
489 Atlas::getExtendedEventContext(ctx).proxy())
494 * @brief Dereference.
497 const HepMC::GenParticle& HepMcParticleLink::operator* () const
504 * @brief Dereference.
507 HepMC::ConstGenParticlePtr HepMcParticleLink::operator->() const
514 * @brief Dereference.
517 HepMcParticleLink::operator HepMC::ConstGenParticlePtr() const
524 * @brief Validity check. Dereference and check for null.
527 bool HepMcParticleLink::isValid() const
529 return (nullptr != cptr());
534 * @brief Validity check. Dereference and check for null.
537 bool HepMcParticleLink::operator!() const
544 * @brief Validity check. Dereference and check for null.
547 HepMcParticleLink::operator bool() const
554 * @brief Equality comparison.
557 bool HepMcParticleLink::operator== (const HepMcParticleLink& rhs) const
559 return (ExtendedBarCode::compareUniqueID(*this, rhs) == 0 &&
560 ExtendedBarCode::compareIndex (*this, rhs) == 0);
565 * @brief Inequality comparison.
568 bool HepMcParticleLink::operator!= (const HepMcParticleLink& rhs) const
570 return !(operator==(rhs));
575 * @brief Ordering comparison.
578 bool HepMcParticleLink::operator< (const HepMcParticleLink& rhs) const
580 int cmpIndex = ExtendedBarCode::compareIndex (*this, rhs);
581 if (cmpIndex < 0) return true;
583 if (ExtendedBarCode::compareUniqueID(*this, rhs) < 0) return true;
590 * @brief Hash the 32-bit barcode and 16-bit eventindex into a 32bit int.
593 HepMcParticleLink::barcode_type HepMcParticleLink::compress() const
595 return ( ((m_extBarcode.uid()&0xFFFF) << 16) |
601 * @brief Comparison with ConstGenParticlePtr.
602 * Needed with c++20 to break an ambiguity.
605 bool operator== (HepMC::ConstGenParticlePtr a,
606 const HepMcParticleLink& b)
608 return a == b.cptr();