Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:57:59

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 // G4Cache
0027 //
0028 // Class Description:
0029 //
0030 //      Helper classes for Geant4 Multi-Threaded.
0031 //      The classes defined in this header file provide a thread-private
0032 //      cache to store a thread-local variable V in a class instance
0033 //      shared among threads.
0034 //      These are templated classes on the to-be-stored object.
0035 //
0036 // Example:
0037 //      Let's assume an instance myObject of class G4Shared is sharead between
0038 //      threads. Still a data member of this class needs to be thread-private.
0039 //      A typical example of this being a "cache" for a local calculation.
0040 //      The helper defined here can be used to guarantee thread-safe operations
0041 //      on the thread-private object.
0042 //      Example:
0043 //         class G4Shared
0044 //         {
0045 //           G4double sharedData;
0046 //           G4Cache<G4double> threadPrivate;
0047 //           void foo()
0048 //           {
0049 //             G4double priv = threadPrivate.Get();
0050 //             if ( priv < 10 ) priv += sharedData;
0051 //             threadPrivate.Put( priv );
0052 //           }
0053 //         }
0054 //
0055 //      Two variants of the base G4Cache exist. The first one being
0056 //      G4VectorCache similar to std::vector.
0057 //      Example:
0058 //         G4VectorCache<G4double> aVect;
0059 //         aVect.Push_back( 3.2 );
0060 //         aVect.Push_back( 4.1 );
0061 //         std::cout << aVect[0] << std::endl;
0062 //      The second one being:
0063 //      G4MapCache, similar to std::map.
0064 //      Example:
0065 //         G4MapCache<G4int, G4double> aMap;
0066 //         aMap[320]=1.234;
0067 //
0068 //      See classes definition for details.
0069 
0070 // Author: A.Dotti, 21 October 2013 - First implementation
0071 // --------------------------------------------------------------------
0072 #ifndef G4CACHE_HH
0073 #define G4CACHE_HH
0074 
0075 // Debug this code
0076 // #define g4cdebug 1
0077 
0078 #include <atomic>
0079 #include <map>
0080 #include <system_error>
0081 
0082 #include "G4AutoLock.hh"
0083 #include "G4CacheDetails.hh"  // Thread Local storage details are here
0084 
0085 // A templated cache to store a thread-private data of type VALTYPE.
0086 //
0087 template <class VALTYPE>
0088 class G4Cache
0089 {
0090  public:
0091   using value_type = VALTYPE;
0092   // The stored type
0093 
0094   G4Cache();
0095   // Default constructor
0096 
0097   G4Cache(const value_type& v);
0098   // Construct cache object with initial value
0099 
0100   virtual ~G4Cache();
0101   // Default destructor
0102 
0103   inline value_type& Get() const;
0104   // Gets reference to cached value of this threads
0105 
0106   inline void Put(const value_type& val) const;
0107   // Sets this thread cached value to val
0108 
0109   inline value_type Pop();
0110   // Gets copy of cached value
0111 
0112   G4Cache(const G4Cache& rhs);
0113   G4Cache& operator=(const G4Cache& rhs);
0114 
0115  protected:
0116   const G4int& GetId() const { return id; }
0117 
0118  private:
0119   G4int id;
0120   mutable G4CacheReference<value_type> theCache;
0121   static std::atomic<unsigned int> instancesctr;
0122   static std::atomic<unsigned int> dstrctr;
0123 
0124   inline value_type& GetCache() const
0125   {
0126     theCache.Initialize(id);
0127     return theCache.GetCache(id);
0128   }
0129 };
0130 
0131 // A vector version of the cache. Implements vector interface.
0132 // Can be used directly as a std::vector would be used.
0133 //
0134 template <class VALTYPE>
0135 class G4VectorCache : public G4Cache<std::vector<VALTYPE>>
0136 {
0137  public:
0138   // Some useful definitions
0139   //
0140   using value_type = VALTYPE;
0141   using vector_type = typename std::vector<value_type>;
0142   using size_type = typename vector_type::size_type;
0143   using iterator = typename vector_type::iterator;
0144   using const_iterator = typename vector_type::const_iterator;
0145 
0146   G4VectorCache();
0147   // Default constructor
0148 
0149   G4VectorCache(G4int nElems);
0150   // Creates a vector cache of nElems elements
0151 
0152   G4VectorCache(G4int nElems, value_type* vals);
0153   // Creates a vector cache with elements from an array
0154 
0155   virtual ~G4VectorCache();
0156   // Default destructor
0157 
0158   // Interface with functionalities of similar name of std::vector
0159   //
0160   inline void Push_back(const value_type& val);
0161   inline value_type Pop_back();
0162   inline value_type& operator[](const G4int& idx);
0163   inline iterator Begin();
0164   inline iterator End();
0165   inline void Clear();
0166   inline size_type Size() { return G4Cache<vector_type>::Get().size(); }
0167   //  Needs to be here for a VC9 compilation problem
0168 };
0169 
0170 // a Map version of the cache. Implements std::map interface.
0171 // Can be used directly as a std::map would be used.
0172 // KEYTYPE being the key type and VALTYPE the value type.
0173 //
0174 template <class KEYTYPE, class VALTYPE>
0175 class G4MapCache : public G4Cache<std::map<KEYTYPE, VALTYPE>>
0176 {
0177  public:
0178   // Some useful definitions
0179   //
0180   using key_type = KEYTYPE;
0181   using value_type = VALTYPE;
0182   using map_type = typename std::map<key_type, value_type>;
0183   using size_type = typename map_type::size_type;
0184   using iterator = typename map_type::iterator;
0185   using const_iterator = typename map_type::const_iterator;
0186 
0187   virtual ~G4MapCache();
0188   // Default destructor
0189 
0190   inline G4bool Has(const key_type& k);
0191   // Returns true if map contains element corresponding to key k
0192 
0193   // Interface with functionalities of similar name of std::map
0194   //
0195   inline std::pair<iterator, G4bool> Insert(const key_type& k,
0196                                             const value_type& v);
0197   inline iterator Begin();
0198   inline iterator End();
0199   inline iterator Find(const key_type& k);
0200   inline value_type& Get(const key_type& k);
0201   inline size_type Erase(const key_type& k);
0202   inline value_type& operator[](const key_type& k);
0203   inline size_type Size() { return G4Cache<map_type>::Get().size(); }
0204   //  Needs to be here for a VC9 compilation problem
0205 };
0206 
0207 //========= Implementation: G4Cache<V> ====================================
0208 
0209 template <class V>
0210 G4Cache<V>::G4Cache()
0211 {
0212   G4AutoLock l(G4TypeMutex<G4Cache<V>>());
0213   id = instancesctr++;
0214 #ifdef g4cdebug
0215   std::cout << "G4Cache id: " << id << std::endl;
0216 #endif
0217 }
0218 
0219 template <class V>
0220 G4Cache<V>::G4Cache(const G4Cache<V>& rhs)
0221 {
0222   // Copy is special, we need to copy the content
0223   // of the cache, not the cache object
0224 
0225   if(this == &rhs)
0226     return;
0227   G4AutoLock l(G4TypeMutex<G4Cache<V>>());
0228   id = instancesctr++;
0229 
0230   // Force copy of cached data
0231   //
0232   V aCopy = rhs.GetCache();
0233   Put(aCopy);
0234 
0235 #ifdef g4cdebug
0236   std::cout << "Copy constructor with id: " << id << std::endl;
0237 #endif
0238 }
0239 
0240 template <class V>
0241 G4Cache<V>& G4Cache<V>::operator=(const G4Cache<V>& rhs)
0242 {
0243   if(this == &rhs)
0244     return *this;
0245 
0246   // Force copy of cached data
0247   //
0248   V aCopy = rhs.GetCache();
0249   Put(aCopy);
0250 
0251 #ifdef g4cdebug
0252   std::cout << "Assignement operator with id: " << id << std::endl;
0253 #endif
0254   return *this;
0255 }
0256 
0257 template <class V>
0258 G4Cache<V>::G4Cache(const V& v)
0259 {
0260   G4AutoLock l(G4TypeMutex<G4Cache<V>>());
0261   id = instancesctr++;
0262   Put(v);
0263 
0264 #ifdef g4cdebug
0265   std::cout << "G4Cache id: " << id << std::endl;
0266 #endif
0267 }
0268 
0269 template <class V>
0270 G4Cache<V>::~G4Cache()
0271 {
0272 #ifdef g4cdebug
0273   std::cout << "~G4Cache id: " << id << std::endl;
0274 #endif
0275   // don't automatically lock --> wait until we can catch an error
0276   // without scoping the G4AutoLock
0277   //
0278   G4AutoLock l(G4TypeMutex<G4Cache<V>>(), std::defer_lock);
0279 
0280   // sometimes the mutex is unavailable in destructors so
0281   // try to lock the associated mutex, but catch if it fails
0282   try
0283   {
0284     // a system_error in lock means that the mutex is unavailable
0285     // we want to throw the error that comes from locking an unavailable
0286     // mutex so that we know there is a memory leak
0287     // if the mutex is valid, this will hold until the other thread finishes
0288     //
0289     l.lock();
0290   } catch(std::system_error& e)
0291   {
0292     // the error that comes from locking an unavailable mutex
0293 #ifdef G4VERBOSE
0294     G4cout << "Non-critical error: mutex lock failure in ~G4Cache<"
0295            << typeid(V).name() << ">. " << G4endl
0296            << "If the RunManagerKernel has been deleted, it failed to "
0297            << "delete an allocated resource" << G4endl
0298            << "and this destructor is being called after the statics "
0299            << "were destroyed." << G4endl;
0300     G4cout << "Exception: [code: " << e.code() << "] caught: " << e.what()
0301            << G4endl;
0302 #endif
0303   }
0304   ++dstrctr;
0305   G4bool last = (dstrctr == instancesctr);
0306   theCache.Destroy(id, last);
0307   if(last)
0308   {
0309     instancesctr.store(0);
0310     dstrctr.store(0);
0311   }
0312 }
0313 
0314 template <class V>
0315 V& G4Cache<V>::Get() const
0316 {
0317   return GetCache();
0318 }
0319 
0320 template <class V>
0321 void G4Cache<V>::Put(const V& val) const
0322 {
0323   GetCache() = val;
0324 }
0325 
0326 // Should here remove from cache element?
0327 template <class V>
0328 V G4Cache<V>::Pop()
0329 {
0330   return GetCache();
0331 }
0332 
0333 template <class V>
0334 std::atomic<unsigned int> G4Cache<V>::instancesctr(0);
0335 
0336 template <class V>
0337 std::atomic<unsigned int> G4Cache<V>::dstrctr(0);
0338 
0339 //========== Implementation: G4VectorCache<V> ===========================
0340 
0341 template <class V>
0342 G4VectorCache<V>::G4VectorCache() = default;
0343 
0344 template <class V>
0345 G4VectorCache<V>::~G4VectorCache()
0346 {
0347 #ifdef g4cdebug
0348   std::cout << "~G4VectorCache "
0349             << G4Cache<G4VectorCache<V>::vector_type>::GetId()
0350             << " with size: " << Size() << "->";
0351   for(size_type i = 0; i < Size(); ++i)
0352     std::cout << operator[](i) << ",";
0353   std::cout << "<-" << std::endl;
0354 #endif
0355 }
0356 
0357 template <class V>
0358 G4VectorCache<V>::G4VectorCache(G4int nElems)
0359 {
0360   vector_type& cc = G4Cache<vector_type>::Get();
0361   cc.resize(nElems);
0362 }
0363 
0364 template <class V>
0365 G4VectorCache<V>::G4VectorCache(G4int nElems, V* vals)
0366 {
0367   vector_type& cc = G4Cache<vector_type>::Get();
0368   cc.resize(nElems);
0369   for(G4int idx = 0; idx < nElems; ++idx)
0370     cc[idx] = vals[idx];
0371 }
0372 
0373 template <class V>
0374 void G4VectorCache<V>::Push_back(const V& val)
0375 {
0376   G4Cache<vector_type>::Get().push_back(val);
0377 }
0378 
0379 template <class V>
0380 V G4VectorCache<V>::Pop_back()
0381 {
0382   vector_type& cc = G4Cache<vector_type>::Get();
0383   value_type val  = cc[cc.size() - 1];
0384   cc.pop_back();
0385   return val;
0386 }
0387 
0388 template <class V>
0389 V& G4VectorCache<V>::operator[](const G4int& idx)
0390 {
0391   vector_type& cc = G4Cache<vector_type>::Get();
0392   return cc[idx];
0393 }
0394 
0395 template <class V>
0396 typename G4VectorCache<V>::iterator G4VectorCache<V>::Begin()
0397 {
0398   return G4Cache<vector_type>::Get().begin();
0399 }
0400 
0401 template <class V>
0402 typename G4VectorCache<V>::iterator G4VectorCache<V>::End()
0403 {
0404   return G4Cache<vector_type>::Get().end();
0405 }
0406 
0407 template <class V>
0408 void G4VectorCache<V>::Clear()
0409 {
0410   G4Cache<vector_type>::Get().clear();
0411 }
0412 
0413 // template<class V>
0414 // typename G4VectorCache<V>::size_type G4VectorCache<V>::Size()
0415 //{
0416 //    return G4Cache<vector_type>::Get().size();
0417 //}
0418 
0419 //======== Implementation: G4MapType<K,V> ===========================
0420 
0421 template <class K, class V>
0422 G4MapCache<K, V>::~G4MapCache()
0423 {
0424 #ifdef g4cdebug
0425   std::cout << "~G4MacCache " << G4Cache<map_type>::GetId()
0426             << " with size: " << Size() << "->";
0427   for(iterator it = Begin(); it != End(); ++it)
0428     std::cout << it->first << ":" << it->second << ",";
0429   std::cout << "<-" << std::endl;
0430 #endif
0431 }
0432 
0433 template <class K, class V>
0434 std::pair<typename G4MapCache<K, V>::iterator, G4bool> G4MapCache<K, V>::Insert(
0435   const K& k, const V& v)
0436 {
0437   return G4Cache<map_type>::Get().insert(std::pair<key_type, value_type>(k, v));
0438 }
0439 
0440 // template<class K, class V>
0441 // typename G4MapCache<K,V>::size_type G4MapCache<K,V>::Size()
0442 //{
0443 //    return G4Cache<map_type>::Get().size();
0444 //}
0445 
0446 template <class K, class V>
0447 typename G4MapCache<K, V>::iterator G4MapCache<K, V>::Begin()
0448 {
0449   return G4Cache<map_type>::Get().begin();
0450 }
0451 template <class K, class V>
0452 typename G4MapCache<K, V>::iterator G4MapCache<K, V>::End()
0453 {
0454   return G4Cache<map_type>::Get().end();
0455 }
0456 
0457 template <class K, class V>
0458 typename G4MapCache<K, V>::iterator G4MapCache<K, V>::Find(const K& k)
0459 {
0460   return G4Cache<map_type>::Get().find(k);
0461 }
0462 
0463 template <class K, class V>
0464 G4bool G4MapCache<K, V>::Has(const K& k)
0465 {
0466   return (Find(k) != End());
0467 }
0468 
0469 template <class K, class V>
0470 V& G4MapCache<K, V>::Get(const K& k)
0471 {
0472   return Find(k)->second;
0473 }
0474 
0475 template <class K, class V>
0476 typename G4MapCache<K, V>::size_type G4MapCache<K, V>::Erase(const K& k)
0477 {
0478   return G4Cache<map_type>::Get().erase(k);
0479 }
0480 
0481 template <class K, class V>
0482 V& G4MapCache<K, V>::operator[](const K& k)
0483 {
0484   return (G4Cache<map_type>::Get())[k];
0485 }
0486 
0487 #endif