1 // Dear emacs, this is -*- c++ -*-
4 Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
7 * @file AthLinks/ElementLinkBase.icc
8 * @author scott snyder <snyder@bnl.gov>
10 * @brief Base class for ElementLinks to vectors of pointers.
15 * @brief Test the index validity.
16 * @returns True if the index is not valid (in default state).
19 bool ElementLinkBase::isDefaultIndex() const
21 return m_persIndex == INVALID;
26 * @brief Test to see if this link has a cached element pointer.
29 bool ElementLinkBase::hasCachedElement() const
31 return m_element.get() != 0;
36 * @brief Test to see if this link is in the default state.
39 bool ElementLinkBase::isDefault() const
41 return m_proxy.isDefault() && !hasCachedElement() && isDefaultIndex();
46 * @brief Return the index of the link.
49 ElementLinkBase::index_type
50 ElementLinkBase::index() const
52 if (m_persIndex == INVALID)
53 return static_cast<ElementLinkBase::index_type>(-1);
58 * @brief Return the index of the link.
59 * (Deprecated; use @c index() instead.)
62 ElementLinkBase::stored_index_type
63 ElementLinkBase::persIndex() const
70 * @brief Return the SG key that we reference, as a string.
72 * Returns a null string on failure.
75 const ElementLinkBase::ID_type&
76 ElementLinkBase::dataID() const
78 return m_proxy.dataID();
83 * @brief Return the SG key that we reference, as a hash.
85 * Returns 0 on failure.
88 ElementLinkBase::sgkey_t
89 ElementLinkBase::key() const
95 * @brief Return the SG key that we reference, as a hash.
96 * (Deprecated; use @c key instead.)
98 * Returns 0 on failure.
101 ElementLinkBase::sgkey_t
102 ElementLinkBase::persKey() const
109 * @brief Return the data source for this reference.
112 IProxyDict* ElementLinkBase::source() const
114 return m_proxy.source();
119 * @brief Return the SG proxy for the container holding this element.
121 * If this is a null link, we return 0.
122 * If we're directly referencing an object that's not in StoreGate,
123 * either return 0 or throw @c ExcPointerNotInSG, depending
124 * on @c nothrow. Otherwise, return the proxy for the object
128 const SG::DataProxy* ElementLinkBase::proxy() const
130 return m_proxy.proxy(true);
135 * @brief Reset the link to a null state.
138 void ElementLinkBase::reset ()
142 clearCachedElement();
143 m_persIndex = INVALID;
148 * @brief Finish initialization after link has been read.
149 * @param sg Associated store.
151 * This should be called after a link has been read by root
152 * in order to set the proxy pointer.
155 * If @c sg is 0, then we use the global default store.
158 bool ElementLinkBase::toTransient (IProxyDict* sg /*= 0*/)
160 m_proxy.toTransient (m_persKey, sg);
161 clearCachedElement();
167 * @brief Prepare this link for writing.
169 * This method should be called before trying to write the link with root.
170 * It will make sure the persistent fields of the link are valid.
171 * It will also perform remapping if needed.
173 * Will return true on success. Will return false if either the container
174 * or the element index has not been specified. Will throw
175 * @c ExcPointerNotInSG if the link is referencing a container that
179 bool ElementLinkBase::toPersistent()
181 if (isDefault()) return true;
182 if (m_proxy.isDefault() || isDefaultIndex()) return false;
183 if (m_proxy.toPersistent (m_persKey, m_persIndex))
184 clearCachedElement();
190 * @brief Adjust for thinning.
192 * If this link points to a container that has been thinned,
193 * it will be adjusted accordingly.
195 * Returns @c true if the link was changed; @c false otherwise.
198 bool ElementLinkBase::thin()
200 return thin (SG::getThinningCache());
205 * @brief Adjust for thinning.
206 * @param thinningCache Thinning cache for the current stream
209 * If this link points to a container that has been thinned,
210 * it will be adjusted accordingly.
212 * Returns @c true if the link was changed; @c false otherwise.
215 bool ElementLinkBase::thin (const SG::ThinningCache* thinningCache)
217 bool ret1 = toPersistent();
218 size_t index = m_persIndex;
219 bool ret = m_proxy.thin (m_persKey, index, thinningCache);
221 m_persIndex = static_cast<stored_index_type>(index);
227 * @brief Default constructor. Makes a null link.
230 ElementLinkBase::ElementLinkBase()
232 m_persIndex (INVALID)
238 * @brief Construct a link from a string key and an index.
239 * @param dataID Key of the object.
240 * @param link_clid CLID of the link being set.
241 * @param elemID The index of the element within the container.
242 * @param sg Associated store.
244 * If @c sg is 0, we take the global default.
247 ElementLinkBase::ElementLinkBase (const ID_type& dataID,
251 : m_persIndex (static_cast<stored_index_type>(elemID))
253 m_persKey = m_proxy.toIdentifiedObject (dataID, link_clid, sg);
258 * @brief Construct a link from a hashed key and an index.
259 * @param key Hashed key of the object.
260 * @param link_clid CLID of the link being set.
261 * @param elemID The index of the element within the container.
262 * @param sg Associated store.
264 * If @c sg is 0, we take the global default.
267 ElementLinkBase::ElementLinkBase (sgkey_t key,
272 m_persIndex (static_cast<stored_index_type>(elemID))
274 m_proxy.toIdentifiedObject (key, link_clid, sg);
279 * @brief Construct a link from a string key, index, AND pointer to element.
280 * @param dataID Key of the object.
281 * @param link_clid CLID of the link being set.
282 * @param elemID The index of the element within the container.
283 * @param elt Pointer to the element.
284 * @param sg Associated store.
286 * USE CAREFULLY: no coherency checks, we just trust you!
288 * If @c sg is 0, we take the global default.
291 ElementLinkBase::ElementLinkBase (const ID_type& dataID,
296 : m_persIndex (static_cast<stored_index_type>(elemID)),
299 m_persKey = m_proxy.toIdentifiedObject (dataID, link_clid, sg);
304 * @brief Construct a link from a hashed key, index, AND pointer to element.
305 * @param key Hashed key of the object.
306 * @param link_clid CLID of the link being set.
307 * @param elemID The index of the element within the container.
308 * @param elt Pointer to the element.
309 * @param sg Associated store.
311 * USE CAREFULLY: no coherency checks, we just trust you!
313 * If @c sg is 0, we take the global default.
316 ElementLinkBase::ElementLinkBase (sgkey_t key,
322 m_persIndex (static_cast<stored_index_type>(elemID)),
325 m_proxy.toIdentifiedObject (key, link_clid, sg);
330 * @brief Construct a link from an index and pointer to the container.
331 * @param obj Pointer to the container (storable).
332 * @param link_clid CLID of the link being set.
333 * @param elemID The index of the element within the container.
334 * @param sg Associated store.
336 * If @c sg is 0, we take the global default.
339 ElementLinkBase::ElementLinkBase (const_pointer_t obj,
343 : m_persIndex (static_cast<stored_index_type>(elemID))
345 m_persKey = m_proxy.toStorableObject (obj, link_clid, sg);
350 * @brief Construct a link from another link, changing the index.
351 * @param other The source link.
352 * @param elemID The index for the new link.
354 * The index being constructed will reference the same container
355 * as @c other, but it will refer to element @c elemID.
358 ElementLinkBase::ElementLinkBase (const ElementLinkBase& other,
360 : m_persKey (other.m_persKey),
361 m_persIndex (static_cast<stored_index_type>(elemID)),
362 m_proxy (other.m_proxy)
368 * @brief Construct a link from a DataLink and an index.
369 * @param dlink Link to the container.
370 * @param index The index of the element within the container.
373 ElementLinkBase::ElementLinkBase (const DataLinkBase& dlink,
375 : m_persKey (dlink.key()),
376 m_persIndex (dlink.isDefault() ? INVALID : static_cast<stored_index_type>(index)),
377 m_proxy (dlink.m_proxy)
383 * @brief Constructor from a link referencing a different type.
384 * @param other The object from which to copy.
386 * @c FROM_TRAITS is the @c ElementLinkTraits class for @c other;
387 * @c TO_TRAITS is the traits class for this object.
388 * The actual pointer values are not used, just the types are used.
389 * Default conversions for the storable pointer (i.e., derived->base)
392 template <class FROM_TRAITS, class TO_TRAITS>
393 ElementLinkBase::ElementLinkBase (const ElementLinkBase& other,
396 : m_persKey (other.m_persKey),
397 m_persIndex (other.m_persIndex),
398 m_proxy (other.m_proxy,
399 (typename FROM_TRAITS::Storable*)0,
400 (typename TO_TRAITS::Storable*)0)
402 typedef typename FROM_TRAITS::IndexingPolicy FromIndexingPolicy;
403 typedef typename TO_TRAITS::IndexingPolicy ToIndexingPolicy;
404 typedef typename FromIndexingPolicy::ElementType FromElementType;
405 typedef typename ToIndexingPolicy::ElementType ToElementType;
406 FromElementType from_elt = reinterpret_cast<FromElementType>(other.m_element.get());
407 ToElementType to_elt = from_elt;
408 storeCachedElement (to_elt);
413 * @brief Return a pointer to the currently-referenced container object.
414 * @param castfn Function to do the cast from data proxy to object.
415 * If 0, use a dynamic cast.
416 * @param clid The CLID of the desired object.
417 * This is used to determine how the returned pointer
418 * is to be converted.
419 * @param isConst True if the returned object will be treated as const.
420 * @return A pointer to an object of the type given by @a clid,
421 * or null on a failure (or if the reference is null).
424 void* ElementLinkBase::storableBase (castfn_t* castfn,
428 return m_proxy.storableBase (castfn, clid, isConst);
433 * @brief Set the container referenced by the link to @c data.
434 * @param data Pointer to the new container.
435 * @param link_clid CLID of the link being set.
436 * @param replace True if we can change an existing link.
437 * @param sg Associated store.
438 * @returns True if the link was changed.
440 * If the link is already set, this will return false and leave the
441 * link unchanged unless @c replace is set. The @c replace argument
442 * should be set if the element is now in a new storable container;
443 * e.g. element ptr has been put in a new view container.
445 * If @c sg is 0, then we take the store from whatever the link's currently
446 * set to. If the link has no current store, then we take the global
450 bool ElementLinkBase::setStorableObject (const_pointer_t data,
455 if (!m_proxy.isDefault()) {
456 if (!replace) return false;
457 m_persIndex = INVALID;
460 m_persKey = m_proxy.toStorableObject (data, link_clid, sg);
466 * @brief Set the link to an element given by index and pointer to container.
467 * @param obj Pointer to the container (storable).
468 * @param link_clid CLID of the link being set.
469 * @param elemID The index of the element within the container.
470 * @param sg Associated store.
471 * @returns True if the link was changed.
473 * If the link is already set, this will return false and leave the
476 * If @c sg is 0, then we take the store from whatever the link's currently
477 * set to. If the link has no current store, then we take the global
481 bool ElementLinkBase::toIndexedElement (const_pointer_t obj,
486 if (m_proxy.isDefault() && isDefaultIndex() && !hasCachedElement()) {
487 m_persKey = m_proxy.toStorableObject (obj, link_clid, sg);
488 m_persIndex = static_cast<stored_index_type>(elemID);
489 //clearCachedElement(); // Redundant --- must be 0 due to above test.
497 * @brief Set the link to an element given by string key and index.
498 * @param dataID Key of the object.
499 * @param link_clid CLID of the link being set.
500 * @param elemID The index of the element within the container.
501 * @param sg Associated store.
503 * If @c sg is 0, then we take the store from whatever the link's currently
504 * set to. If the link has no current store, then we take the global
508 void ElementLinkBase::resetWithKeyAndIndex (const ID_type& dataID,
513 m_persKey = m_proxy.toIdentifiedObject (dataID, link_clid, sg);
514 m_persIndex = static_cast<stored_index_type>(elemID);
515 clearCachedElement();
520 * @brief Set the link to an element given by string key and index.
521 * @param key Hashed key of the object.
522 * @param link_clid CLID of the link being set.
523 * @param elemID The index of the element within the container.
524 * @param sg Associated store.
526 * If @c sg is 0, then we take the store from whatever the link's currently
527 * set to. If the link has no current store, then we take the global
531 void ElementLinkBase::resetWithKeyAndIndex (sgkey_t key,
537 m_proxy.toIdentifiedObject (key, link_clid, sg);
538 m_persIndex = static_cast<stored_index_type>(elemID);
539 clearCachedElement();
544 * @brief Set the index part of the link.
545 * @param index New index value.
548 void ElementLinkBase::setIndex (index_type index)
550 m_persIndex = static_cast<stored_index_type>(index);
555 * @brief Return the stored representation of the link index.
558 const ElementLinkBase::stored_index_type&
559 ElementLinkBase::storedIndex() const
566 * @brief Clear the currently-cached element.
569 void ElementLinkBase::clearCachedElement()
571 storeCachedElement (nullptr);
576 * @brief Set the cached element stored in the link,
577 * assuming the cached element is null.
578 * @param elt New value for the cached element.
581 void ElementLinkBase::setCachedElement (ElementType elt) const
588 * @brief Set the cached element stored in the link.
589 * @param elt New value for the cached element.
592 void ElementLinkBase::storeCachedElement (ElementType elt)
594 m_element.store (elt);
599 * @brief Retrieve the cached element from the link.
600 * @param elt[out] The cached element.
601 * @returns True if an element was cached; false otherwise.
603 * @c elt is left unmodified if there is no cached element.
607 bool ElementLinkBase::getCachedElement (const T* & elt) const
609 if (m_element.get()) {
610 elt = reinterpret_cast<const T*> (m_element.ptr());
618 * @brief Return the internal proxy holder object.
621 const SG::DataProxyHolder& ElementLinkBase::proxyHolder() const