Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-15 08:57:58

0001 /***********************************************************************************\
0002 * (c) Copyright 1998-2025 CERN for the benefit of the LHCb and ATLAS collaborations *
0003 *                                                                                   *
0004 * This software is distributed under the terms of the Apache version 2 licence,     *
0005 * copied verbatim in the file "LICENSE".                                            *
0006 *                                                                                   *
0007 * In applying this licence, CERN does not waive the privileges and immunities       *
0008 * granted to it by virtue of its status as an Intergovernmental Organization        *
0009 * or submit itself to any jurisdiction.                                             *
0010 \***********************************************************************************/
0011 #ifndef _GAUDI_CONTEXTSPECIFICPTR_H_
0012 #define _GAUDI_CONTEXTSPECIFICPTR_H_
0013 
0014 #include <functional>
0015 #include <mutex>
0016 #include <numeric>
0017 #include <type_traits>
0018 #include <unordered_map>
0019 
0020 // For the definition of GAUDI_API
0021 #include <GaudiKernel/Kernel.h>
0022 #include <GaudiKernel/ThreadLocalContext.h>
0023 
0024 class EventContext;
0025 
0026 namespace Gaudi {
0027   namespace Hive {
0028     /**
0029      *  Simple implementation of a smart pointer with different values for
0030      *  different event contexts (slots).
0031      *
0032      *  When the copy for a new context is requested, the returned pointer is
0033      *  null.
0034      *
0035      *  The interface is meant to allow for a drop-in replacement for regular
0036      *  pointers. It's still responsibility of the user to delete the memory
0037      *  associated to the pointers.
0038      */
0039     template <typename T>
0040     class ContextSpecificPtr {
0041     private:
0042       /// Type used for the internal storage.
0043       typedef std::unordered_map<ContextIdType, T*> StorageType;
0044 
0045     public:
0046       /// Return the pointer for the current context (null for a new context).
0047       T* get() const {
0048         auto lock = std::scoped_lock{ m_ptrs_lock };
0049         return m_ptrs[currentContextId()];
0050       }
0051       /// Set the pointer for the current context.
0052       T*& set( T* ptr ) {
0053         auto lock                         = std::scoped_lock{ m_ptrs_lock };
0054         return m_ptrs[currentContextId()] = ptr;
0055       }
0056 
0057       /// Assignment operator (@see set).
0058       T*& operator=( T* ptr ) { return set( ptr ); }
0059 
0060       /// Return true if the pointer is not null.
0061       bool isValid() const { return get(); }
0062 
0063       /// Conversion to boolean (@see isValid).
0064       operator bool() const { return isValid(); }
0065 
0066       /// Comparison with another pointer.
0067       bool operator==( T* rhs ) const { return get() == rhs; }
0068 
0069       /// @{ Dereference operators.
0070       T&       operator*() { return *get(); }
0071       const T& operator*() const { return *get(); }
0072       T*       operator->() { return get(); }
0073       const T* operator->() const { return get(); }
0074       /// @}
0075 
0076       /// @{Non thread-safe methods.
0077 
0078       /// Set to null all the used pointers.
0079       void clear() { m_ptrs.clear(); }
0080 
0081       /// Taking a function f that from a T* produces a value, return the sum of
0082       /// all the values corresponding to the contained pointers using init as
0083       /// first value.
0084       template <class Mapper>
0085       auto accumulate( Mapper f, std::invoke_result_t<Mapper, const T*> init ) const -> decltype( init ) {
0086         return accumulate( f, init, std::plus<>() );
0087       }
0088 
0089       /// Taking a function f that from a T* produces a value, return the
0090       /// accumulated  result, through the operation 'op', of all the values
0091       /// corresponding to the contained pointers using init as first value.
0092       template <class Mapper, class BinaryOperation>
0093       auto accumulate( Mapper f, std::invoke_result_t<Mapper, const T*> init, BinaryOperation op ) const
0094           -> decltype( init ) {
0095         auto lock = std::scoped_lock{ m_ptrs_lock };
0096         return std::accumulate( m_ptrs.begin(), m_ptrs.end(), init, [&f, &op]( const auto& partial, const auto& p ) {
0097           return op( partial, f( p.second ) );
0098         } );
0099       }
0100 
0101       /// Call a function on each contained pointer.
0102       template <class F>
0103       void for_each( F f ) const {
0104         auto lock = std::scoped_lock{ m_ptrs_lock };
0105         for ( auto& i : m_ptrs ) f( i.second );
0106       }
0107 
0108       /// Call a function on each contained pointer. (non-const version)
0109       template <class F>
0110       void for_each( F f ) {
0111         auto lock = std::scoped_lock{ m_ptrs_lock };
0112         for ( auto& i : m_ptrs ) f( i.second );
0113       }
0114 
0115       /// Call a function on each element, passing slot# as well
0116       template <class F>
0117       void for_all( F f ) const {
0118         auto lock = std::scoped_lock{ m_ptrs_lock };
0119         for ( auto& i : m_ptrs ) f( i.first, i.second );
0120       }
0121       template <class F>
0122       void for_all( F f ) {
0123         auto lock = std::scoped_lock{ m_ptrs_lock };
0124         for ( auto& i : m_ptrs ) f( i.first, i.second );
0125       }
0126 
0127       void deleteAll() {
0128         for_each( []( T*& p ) {
0129           delete p;
0130           p = nullptr;
0131         } );
0132       }
0133 
0134     private:
0135       /// Internal storage for the different internal pointers.
0136       mutable StorageType m_ptrs;
0137       /// Mutex for the m_ptrs container.
0138       mutable std::mutex m_ptrs_lock;
0139     };
0140 
0141     /**
0142      *  Implementation of a context specific storage accessible as a sort of
0143      *  smart reference class.
0144      *
0145      *  New values are created from the prototype passed to the constructor.
0146      */
0147     template <typename T>
0148     class ContextSpecificData {
0149     public:
0150       /// Constructor with prototype value.
0151       ContextSpecificData( T proto = {} ) : m_proto( std::move( proto ) ) {}
0152 
0153       /// Destructor.
0154       ~ContextSpecificData() { m_ptr.deleteAll(); }
0155 
0156       operator T&() {
0157         if ( !m_ptr ) m_ptr = new T( m_proto );
0158         return *m_ptr;
0159       }
0160 
0161       operator T&() const {
0162         if ( !m_ptr ) m_ptr = new T( m_proto );
0163         return *m_ptr;
0164       }
0165 
0166       /// Assignment operator.
0167       T& operator=( const T& other ) { return (T&)( *this ) = other; }
0168 
0169       /// Return the sum of all the contained values using init as first value.
0170       T accumulate( T init ) const { return accumulate( init, std::plus<>() ); }
0171 
0172       /// Return the accumulated result, through the operation 'op', of all the
0173       /// contained values using init as first value.
0174       template <class T1, class BinaryOperation>
0175       T1 accumulate( T1 init, BinaryOperation op ) const {
0176         return m_ptr.accumulate( []( const T* p ) { return *p; }, init, op );
0177       }
0178 
0179       /// Call a function on each contained value.
0180       template <class F>
0181       void for_each( F f ) const {
0182         m_ptr.for_each( [&f]( const T* p ) { f( *p ); } );
0183       }
0184 
0185       /// Call a function on each contained value. (non-const version)
0186       template <class F>
0187       void for_each( F f ) {
0188         m_ptr.for_each( [&f]( T* p ) { f( *p ); } );
0189       }
0190 
0191       /// Call a function on each element, passing slot# as well
0192       template <class F>
0193       void for_all( F f ) const {
0194         m_ptr.for_all( [&f]( size_t s, const T* p ) { f( s, *p ); } );
0195       }
0196       template <class F>
0197       void for_all( F f ) {
0198         m_ptr.for_all( [&f]( size_t s, T* p ) { f( s, *p ); } );
0199       }
0200 
0201     private:
0202       // FIXME: implement a proper copy constructor
0203       ContextSpecificData( const ContextSpecificData& ) = delete;
0204 
0205       /// Prototype value.
0206       T m_proto = {};
0207       /// Internal implementation.
0208       mutable ContextSpecificPtr<T> m_ptr;
0209     };
0210   } // namespace Hive
0211 } // namespace Gaudi
0212 
0213 #endif // _GAUDI_CONTEXTSPECIFICPTR_H_