Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-02-21 10:00:28

0001 /***********************************************************************************\
0002 * (c) Copyright 1998-2019 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 #if __cplusplus >= 201703L
0086       auto accumulate( Mapper f, std::invoke_result_t<Mapper, const T*> init ) const -> decltype( init ) {
0087 #else
0088       auto accumulate( Mapper f, std::result_of_t<Mapper( const T* )> init ) const -> decltype( init ) {
0089 #endif
0090         return accumulate( f, init, std::plus<>() );
0091       }
0092 
0093       /// Taking a function f that from a T* produces a value, return the
0094       /// accumulated  result, through the operation 'op', of all the values
0095       /// corresponding to the contained pointers using init as first value.
0096       template <class Mapper, class BinaryOperation>
0097 #if __cplusplus >= 201703L
0098       auto accumulate( Mapper f, std::invoke_result_t<Mapper, const T*> init, BinaryOperation op ) const
0099 #else
0100       auto accumulate( Mapper f, std::result_of_t<Mapper( const T* )> init, BinaryOperation op ) const
0101 #endif
0102           -> decltype( init ) {
0103         auto lock = std::scoped_lock{ m_ptrs_lock };
0104         return std::accumulate( m_ptrs.begin(), m_ptrs.end(), init, [&f, &op]( const auto& partial, const auto& p ) {
0105           return op( partial, f( p.second ) );
0106         } );
0107       }
0108 
0109       /// Call a function on each contained pointer.
0110       template <class F>
0111       void for_each( F f ) const {
0112         auto lock = std::scoped_lock{ m_ptrs_lock };
0113         for ( auto& i : m_ptrs ) f( i.second );
0114       }
0115 
0116       /// Call a function on each contained pointer. (non-const version)
0117       template <class F>
0118       void for_each( F f ) {
0119         auto lock = std::scoped_lock{ m_ptrs_lock };
0120         for ( auto& i : m_ptrs ) f( i.second );
0121       }
0122 
0123       /// Call a function on each element, passing slot# as well
0124       template <class F>
0125       void for_all( F f ) const {
0126         auto lock = std::scoped_lock{ m_ptrs_lock };
0127         for ( auto& i : m_ptrs ) f( i.first, i.second );
0128       }
0129       template <class F>
0130       void for_all( F f ) {
0131         auto lock = std::scoped_lock{ m_ptrs_lock };
0132         for ( auto& i : m_ptrs ) f( i.first, i.second );
0133       }
0134 
0135       void deleteAll() {
0136         for_each( []( T*& p ) {
0137           delete p;
0138           p = nullptr;
0139         } );
0140       }
0141 
0142     private:
0143       /// Internal storage for the different internal pointers.
0144       mutable StorageType m_ptrs;
0145       /// Mutex for the m_ptrs container.
0146       mutable std::mutex m_ptrs_lock;
0147     };
0148 
0149     /**
0150      *  Implementation of a context specific storage accessible as a sort of
0151      *  smart reference class.
0152      *
0153      *  New values are created from the prototype passed to the constructor.
0154      */
0155     template <typename T>
0156     class ContextSpecificData {
0157     public:
0158       /// Constructor with prototype value.
0159       ContextSpecificData( T proto = {} ) : m_proto( std::move( proto ) ) {}
0160 
0161       /// Destructor.
0162       ~ContextSpecificData() { m_ptr.deleteAll(); }
0163 
0164       operator T&() {
0165         if ( !m_ptr ) m_ptr = new T( m_proto );
0166         return *m_ptr;
0167       }
0168 
0169       operator T&() const {
0170         if ( !m_ptr ) m_ptr = new T( m_proto );
0171         return *m_ptr;
0172       }
0173 
0174       /// Assignment operator.
0175       T& operator=( const T& other ) { return (T&)( *this ) = other; }
0176 
0177       /// Return the sum of all the contained values using init as first value.
0178       T accumulate( T init ) const { return accumulate( init, std::plus<>() ); }
0179 
0180       /// Return the accumulated result, through the operation 'op', of all the
0181       /// contained values using init as first value.
0182       template <class T1, class BinaryOperation>
0183       T1 accumulate( T1 init, BinaryOperation op ) const {
0184         return m_ptr.accumulate( []( const T* p ) { return *p; }, init, op );
0185       }
0186 
0187       /// Call a function on each contained value.
0188       template <class F>
0189       void for_each( F f ) const {
0190         m_ptr.for_each( [&f]( const T* p ) { f( *p ); } );
0191       }
0192 
0193       /// Call a function on each contained value. (non-const version)
0194       template <class F>
0195       void for_each( F f ) {
0196         m_ptr.for_each( [&f]( T* p ) { f( *p ); } );
0197       }
0198 
0199       /// Call a function on each element, passing slot# as well
0200       template <class F>
0201       void for_all( F f ) const {
0202         m_ptr.for_all( [&f]( size_t s, const T* p ) { f( s, *p ); } );
0203       }
0204       template <class F>
0205       void for_all( F f ) {
0206         m_ptr.for_all( [&f]( size_t s, T* p ) { f( s, *p ); } );
0207       }
0208 
0209     private:
0210       // FIXME: implement a proper copy constructor
0211       ContextSpecificData( const ContextSpecificData& ) = delete;
0212 
0213       /// Prototype value.
0214       T m_proto = {};
0215       /// Internal implementation.
0216       mutable ContextSpecificPtr<T> m_ptr;
0217     };
0218   } // namespace Hive
0219 } // namespace Gaudi
0220 
0221 #endif // _GAUDI_CONTEXTSPECIFICPTR_H_