Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:58:00

0001 //
0002 // ********************************************************************
0003 // * License and Disclaimer                                           *
0004 // *                                                                  *
0005 // * The  Geant4 software  is  copyright of the Copyright Holders  of *
0006 // * the Geant4 Collaboration.  It is provided  under  the terms  and *
0007 // * conditions of the Geant4 Software License,  included in the file *
0008 // * LICENSE and available at  http://cern.ch/geant4/license .  These *
0009 // * include a list of copyright holders.                             *
0010 // *                                                                  *
0011 // * Neither the authors of this software system, nor their employing *
0012 // * institutes,nor the agencies providing financial support for this *
0013 // * work  make  any representation or  warranty, express or implied, *
0014 // * regarding  this  software system or assume any liability for its *
0015 // * use.  Please see the license in the file  LICENSE  and URL above *
0016 // * for the full disclaimer and the limitation of liability.         *
0017 // *                                                                  *
0018 // * This  code  implementation is the result of  the  scientific and *
0019 // * technical work of the GEANT4 collaboration.                      *
0020 // * By using,  copying,  modifying or  distributing the software (or *
0021 // * any work based  on the software)  you  agree  to acknowledge its *
0022 // * use  in  resulting  scientific  publications,  and indicate your *
0023 // * acceptance of all terms of the Geant4 Software license.          *
0024 // ********************************************************************
0025 //
0026 // G4CacheDetails
0027 //
0028 // Class description:
0029 //
0030 //    The classes contained in this header files are used by
0031 //    G4Cache to store a TLS instance of the cached object.
0032 //    These classes should not be used by client code, but
0033 //    are used by one of the G4Cache classes.
0034 //
0035 //    G4Cache is a container of the cached value.
0036 //    Not memory efficient, but CPU efficient (constant time access).
0037 //    A different version with a map instead of a vector should be
0038 //    memory efficient and less CPU efficient (log-time access).
0039 //    If really a lot of these objects are used
0040 //    we may want to consider the map version to save some memory.
0041 //
0042 //    These are simplified "split-classes" without any
0043 //    copy-from-master logic. Each cached object is associated
0044 //    a unique identified (an integer), that references an instance
0045 //    of the cached value (of template type VALTYPE) in a
0046 //    static TLS data structure.
0047 //
0048 //    In case the cache is used for a cached object the object class
0049 //    has to provide a default constructor. Alternatively pointers to
0050 //    objects can be stored in the cache and this limitation is removed
0051 //    but explicit handling of memory (new/delete) of cached object becomes
0052 //    client responsibility.
0053 //
0054 // Todos: - Understand if map based class can be more efficent than
0055 //          vector one.
0056 //        - Evaluate use of specialized allocator for TLS "new".
0057 
0058 // Author: A.Dotti, 21 October 2013 - First implementation
0059 // --------------------------------------------------------------------
0060 #ifndef G4CacheDetails_hh
0061 #define G4CacheDetails_hh
0062 
0063 #include "G4Threading.hh"
0064 #include "globals.hh"
0065 #include <vector>
0066 
0067 // A TLS storage for a cache of type VALTYPE
0068 //
0069 template <class VALTYPE>
0070 class G4CacheReference
0071 {
0072  public:
0073   inline void Initialize(unsigned int id);
0074   // Initliaze TLS storage
0075 
0076   inline void Destroy(unsigned int id, G4bool last);
0077   // Cleanup TLS storage for instance id. If last==true
0078   // destroy and cleanup object container
0079 
0080   inline VALTYPE& GetCache(unsigned int id) const;
0081   // Returns cached value for instance id
0082 
0083  private:
0084   using cache_container = std::vector<VALTYPE*>;
0085   // Implementation detail: the cached object is stored as a
0086   // pointer. Object is stored as a pointer to avoid too large
0087   // std::vector in case of stored objects and allow use of
0088   // specialized allocators
0089 
0090   static cache_container*& cache();
0091 };
0092 
0093 // Template specialization for pointers
0094 // Note: Objects are not owned by cache, for this version of the cache
0095 //       the explicit new/delete of the cached object
0096 //
0097 template <class VALTYPE>
0098 class G4CacheReference<VALTYPE*>
0099 {
0100  public:
0101   inline void Initialize(unsigned int id);
0102 
0103   inline void Destroy(unsigned int id, G4bool last);
0104 
0105   inline VALTYPE*& GetCache(unsigned int id) const;
0106 
0107  private:
0108   using cache_container = std::vector<VALTYPE*>;
0109   static cache_container*& cache();
0110 };
0111 
0112 // Template specialization for probably the most used case: double
0113 // Be more efficient avoiding unnecessary "new/delete"
0114 //
0115 template <>
0116 class G4CacheReference<G4double>
0117 {
0118  public:
0119   inline void Initialize(unsigned int id);
0120 
0121   inline void Destroy(unsigned int id, G4bool last);
0122 
0123   inline G4double& GetCache(unsigned int id) const;
0124 
0125  private:
0126   using cache_container = std::vector<G4double>;
0127   static G4GLOB_DLL cache_container*& cache();
0128 };
0129 
0130 //======= Implementation: G4CacheReference<V>
0131 //===========================================
0132 
0133 template <class V>
0134 void G4CacheReference<V>::Initialize(unsigned int id)
0135 {
0136   // Create cache container
0137   if(cache() == nullptr)
0138   {
0139 #ifdef g4cdebug
0140     std::cout << "Generic template container..." << std::endl;
0141 #endif
0142     cache() = new cache_container;
0143   }
0144   if(cache()->size() <= id)
0145   {
0146     cache()->resize(id + 1, static_cast<V*>(0));
0147   }
0148   if((*cache())[id] == 0)
0149   {
0150     (*cache())[id] = new V;
0151   }
0152 }
0153 
0154 template <class V>
0155 void G4CacheReference<V>::Destroy(unsigned int id, G4bool last)
0156 {
0157   if(cache() != nullptr)
0158   {
0159 #ifdef g4cdebug
0160     std::cout << "V: Destroying element " << id << " is last? " << last
0161               << std::endl;
0162 #endif
0163     if(cache()->size() < id)
0164     {
0165       G4ExceptionDescription msg;
0166       msg << "Internal fatal error. Invalid G4Cache size (requested id: " << id
0167           << " but cache has size: " << cache()->size();
0168       msg << " Possibly client created G4Cache object in a thread and"
0169           << " tried to delete it from another thread!";
0170       G4Exception("G4CacheReference<V>::Destroy", "Cache001", FatalException,
0171                   msg);
0172       return;
0173     }
0174     if(cache()->size() > id && (*cache())[id] != nullptr)
0175     {
0176 #ifdef g4cdebug
0177       std::cout << "V: Destroying element " << id
0178                 << " size: " << cache()->size() << std::endl;
0179 #endif
0180       delete(*cache())[id];
0181       (*cache())[id] = nullptr;
0182     }
0183     if(last)
0184     {
0185 #ifdef g4cdebug
0186       std::cout << "V: Destroying LAST element!" << std::endl;
0187 #endif
0188       delete cache();
0189       cache() = nullptr;
0190     }
0191   }
0192 }
0193 
0194 template <class V>
0195 V& G4CacheReference<V>::GetCache(unsigned int id) const
0196 {
0197   return *(cache()->operator[](id));
0198 }
0199 
0200 template <class V>
0201 typename G4CacheReference<V>::cache_container*& G4CacheReference<V>::cache()
0202 {
0203   G4ThreadLocalStatic cache_container* _instance = nullptr;
0204   return _instance;
0205 }
0206 
0207 //======= Implementation: G4CacheReference<V*>
0208 //============================================
0209 
0210 template <class V>
0211 void G4CacheReference<V*>::Initialize(unsigned int id)
0212 {
0213   if(cache() == nullptr)
0214   {
0215 #ifdef g4cdebug
0216     std::cout << "Pointer template container..." << std::endl;
0217 #endif
0218     cache() = new cache_container;
0219   }
0220   if(cache()->size() <= id)
0221   {
0222     cache()->resize(id + 1, static_cast<V*>(nullptr));
0223   }
0224 }
0225 
0226 template <class V>
0227 inline void G4CacheReference<V*>::Destroy(unsigned int id, G4bool last)
0228 {
0229   if(cache() != nullptr)
0230   {
0231 #ifdef g4cdebug
0232     std::cout << "V*: Destroying element " << id << " is last? " << last
0233               << std::endl;
0234 #endif
0235     if(cache()->size() < id)
0236     {
0237       G4ExceptionDescription msg;
0238       msg << "Internal fatal error. Invalid G4Cache size (requested id: " << id
0239           << " but cache has size: " << cache()->size();
0240       msg << " Possibly client created G4Cache object in a thread and"
0241           << " tried to delete it from another thread!";
0242       G4Exception("G4CacheReference<V*>::Destroy", "Cache001", FatalException,
0243                   msg);
0244       return;
0245     }
0246     if(cache()->size() > id && (*cache())[id] != nullptr)
0247     {
0248       // Ownership is for client
0249       // delete (*cache())[id];
0250 #ifdef g4cdebug
0251       std::cout << "V*: Resetting element " << id
0252                 << " size: " << cache()->size() << std::endl;
0253 #endif
0254       (*cache())[id] = nullptr;
0255     }
0256     if(last)
0257     {
0258 #ifdef g4cdebug
0259       std::cout << "V*: Deleting LAST element!" << std::endl;
0260 #endif
0261       delete cache();
0262       cache() = nullptr;
0263     }
0264   }
0265 }
0266 
0267 template <class V>
0268 V*& G4CacheReference<V*>::GetCache(unsigned int id) const
0269 {
0270   return (cache()->operator[](id));
0271 }
0272 
0273 template <class V>
0274 typename G4CacheReference<V*>::cache_container*& G4CacheReference<V*>::cache()
0275 {
0276   G4ThreadLocalStatic cache_container* _instance = nullptr;
0277   return _instance;
0278 }
0279 
0280 //======= Implementation: G4CacheReference<double>
0281 //============================================
0282 
0283 void G4CacheReference<G4double>::Initialize(unsigned int id)
0284 {
0285   if(cache() == nullptr)
0286   {
0287 #ifdef g4cdebug
0288     std::cout << "Specialized template for G4double container..." << std::endl;
0289 #endif
0290     cache() = new cache_container;
0291   }
0292   if(cache()->size() <= id)
0293   {
0294     cache()->resize(id + 1, static_cast<G4double>(0));
0295   }
0296 }
0297 
0298 void G4CacheReference<G4double>::Destroy(unsigned int /*id*/, G4bool last)
0299 {
0300   if(cache() != nullptr && last)
0301   {
0302 #ifdef g4cdebug
0303     std::cout << "DB: Destroying LAST element! Is it last? " << last
0304               << std::endl;
0305 #endif
0306     delete cache();
0307     cache() = nullptr;
0308   }
0309 }
0310 
0311 G4double& G4CacheReference<G4double>::GetCache(unsigned int id) const
0312 {
0313   return cache()->operator[](id);
0314 }
0315 
0316 #endif