ECCE @ EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
G4Cache.hh
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file G4Cache.hh
1 //
2 // ********************************************************************
3 // * License and Disclaimer *
4 // * *
5 // * The Geant4 software is copyright of the Copyright Holders of *
6 // * the Geant4 Collaboration. It is provided under the terms and *
7 // * conditions of the Geant4 Software License, included in the file *
8 // * LICENSE and available at http://cern.ch/geant4/license . These *
9 // * include a list of copyright holders. *
10 // * *
11 // * Neither the authors of this software system, nor their employing *
12 // * institutes,nor the agencies providing financial support for this *
13 // * work make any representation or warranty, express or implied, *
14 // * regarding this software system or assume any liability for its *
15 // * use. Please see the license in the file LICENSE and URL above *
16 // * for the full disclaimer and the limitation of liability. *
17 // * *
18 // * This code implementation is the result of the scientific and *
19 // * technical work of the GEANT4 collaboration. *
20 // * By using, copying, modifying or distributing the software (or *
21 // * any work based on the software) you agree to acknowledge its *
22 // * use in resulting scientific publications, and indicate your *
23 // * acceptance of all terms of the Geant4 Software license. *
24 // ********************************************************************
25 //
26 //
27 // ---------------------------------------------------------------
28 // GEANT 4 class header file
29 //
30 // Class Description:
31 // Helper classes for Geant4 Multi-Threaded.
32 // The classes defined in this header file provide a thread-private
33 // cache to store a thread-local variable V in a class instance
34 // shared among threads.
35 // These are templated classes on the to-be-stored object.
36 //
37 // Example:
38 // Let's assume an instance myObject of class G4Shared is sharead between
39 // threads. Still a data member of this class needs to be thread-private.
40 // A typical example of this being a "cache" for a local calculation.
41 // The helper defined here can be used to guarantee thread-safe operations
42 // on the thread-private object.
43 // Example:
44 // class G4Shared
45 // {
46 // G4double sharedData;
47 // G4Cache<G4double> threadPrivate;
48 // void foo()
49 // {
50 // G4double priv = threadPrivate.Get();
51 // if ( priv < 10 ) priv += sharedData;
52 // threadPrivate.Put( priv );
53 // }
54 // }
55 //
56 // Two variants of the base G4Cache exist. The first one being
57 // G4VectorCache similar to std::vector.
58 // Example:
59 // G4VectorCache<G4double> aVect;
60 // aVect.Push_back( 3.2 );
61 // aVect.Push_back( 4.1 );
62 // std::cout << aVect[0] << std::endl;
63 // The second one being:
64 // G4MapCache, similar to std::map.
65 // Example:
66 // G4MapCache<G4int, G4double> aMap;
67 // aMap[320]=1.234;
68 //
69 // See classes definition for details.
70 
71 // History:
72 // 21 October 2013: A. Dotti - First implementation
73 // ---------------------------------------------------------------
74 
75 #ifndef G4CACHE_HH
76 #define G4CACHE_HH
77 
78 // Debug this code
79 // #define g4cdebug 1
80 
81 #include <system_error>
82 #include <atomic>
83 #include <map>
84 
85 #include "G4AutoLock.hh"
86 #include "G4CacheDetails.hh" // Thread Local storage details are here
87 
88 // A templated cache to store a thread-private data of type VALTYPE.
89 //
90 template<class VALTYPE>
91 class G4Cache
92 {
93  public:
94 
95  typedef VALTYPE value_type;
96  // The stored type
97 
98  G4Cache();
99  // Default constructor
100 
101  G4Cache(const value_type& v);
102  // Construct cache object with initial value
103 
104  virtual ~G4Cache();
105  // Default destructor
106 
107  inline value_type& Get() const;
108  // Gets reference to cached value of this threads
109 
110  inline void Put( const value_type& val ) const;
111  // Sets this thread cached value to val
112 
113  inline value_type Pop();
114  // Gets copy of cached value
115 
116  G4Cache(const G4Cache& rhs);
117  G4Cache& operator=(const G4Cache& rhs);
118 
119  protected:
120 
121  const G4int& GetId() const { return id; }
122 
123  private:
124 
127  static std::atomic<unsigned int> instancesctr;
128  static std::atomic<unsigned int> dstrctr;
129 
130  inline value_type& GetCache() const
131  {
132  theCache.Initialize(id);
133  return theCache.GetCache(id);
134  }
135 };
136 
137 
138 // A vector version of the cache. Implements vector interface.
139 // Can be used directly as a std::vector would be used.
140 //
141 template<class VALTYPE>
142 class G4VectorCache : public G4Cache< std::vector<VALTYPE> >
143 {
144  public:
145 
146  // Some useful definitions
147  //
148  typedef VALTYPE value_type;
149  typedef typename std::vector<value_type> vector_type;
150  typedef typename vector_type::size_type size_type;
151  typedef typename vector_type::iterator iterator;
152  typedef typename vector_type::const_iterator const_iterator;
153 
154  G4VectorCache();
155  // Default constructor
156 
157  G4VectorCache( G4int nElems );
158  // Creates a vector cache of nElems elements
159 
160  G4VectorCache( G4int nElems , value_type* vals );
161  // Creates a vector cache with elements from an array
162 
163  virtual ~G4VectorCache();
164  // Default destructor
165 
166  // Interface with functionalities of similar name of std::vector
167  //
168  inline void Push_back( const value_type& val );
169  inline value_type Pop_back();
170  inline value_type& operator[](const G4int& idx);
171  inline iterator Begin();
172  inline iterator End();
173  inline void Clear();
174  inline size_type Size() { return G4Cache<vector_type>::Get().size(); }
175  // Needs to be here for a VC9 compilation problem
176 };
177 
178 
179 // a Map version of the cache. Implements std::map interface.
180 // Can be used directly as a std::map would be used.
181 // KEYTYPE being the key type and VALTYPE the value type.
182 //
183 template<class KEYTYPE, class VALTYPE>
184 class G4MapCache : public G4Cache<std::map<KEYTYPE,VALTYPE> >
185 {
186  public:
187 
188  // Some useful definitions
189  //
190  typedef KEYTYPE key_type;
191  typedef VALTYPE value_type;
192  typedef typename std::map<key_type,value_type> map_type;
193  typedef typename map_type::size_type size_type;
194  typedef typename map_type::iterator iterator;
195  typedef typename map_type::const_iterator const_iterator;
196 
197  virtual ~G4MapCache();
198  // Default destructor
199 
200  inline G4bool Has(const key_type& k );
201  // Returns true if map contains element corresponding to key k
202 
203  // Interface with functionalities of similar name of std::map
204  //
205  inline std::pair<iterator,G4bool> Insert( const key_type& k ,
206  const value_type& v );
207  inline iterator Begin();
208  inline iterator End();
209  inline iterator Find(const key_type& k );
210  inline value_type& Get(const key_type& k );
211  inline size_type Erase(const key_type& k );
212  inline value_type& operator[](const key_type& k);
213  inline size_type Size() { return G4Cache<map_type>::Get().size(); }
214  // Needs to be here for a VC9 compilation problem
215 };
216 
217 
218 //========= Implementation: G4Cache<V> ====================================
219 
220 template<class V>
222 {
224  id = instancesctr++;
225 #ifdef g4cdebug
226  std::cout << "G4Cache id: " << id << std::endl;
227 #endif
228 }
229 
230 template<class V>
232 {
233  // Copy is special, we need to copy the content
234  // of the cache, not the cache object
235 
236  if ( this == &rhs ) return;
238  id = instancesctr++;
239 
240  // Force copy of cached data
241  //
242  V aCopy = rhs.GetCache();
243  Put( aCopy );
244 
245 #ifdef g4cdebug
246  std::cout << "Copy constructor with id: " << id << std::endl;
247 #endif
248 }
249 
250 template<class V>
252 {
253  if (this == &rhs) return *this;
254 
255  // Force copy of cached data
256  //
257  V aCopy = rhs.GetCache();
258  Put(aCopy);
259 
260 #ifdef g4cdebug
261  std::cout << "Assignement operator with id: " << id << std::endl;
262 #endif
263  return *this;
264 }
265 
266 template<class V>
267 G4Cache<V>::G4Cache(const V& v)
268 {
270  id = instancesctr++;
271  Put(v);
272 
273 #ifdef g4cdebug
274  std::cout << "G4Cache id: " << id << std::endl;
275 #endif
276 }
277 
278 template<class V>
280 {
281 #ifdef g4cdebug
282  std::cout << "~G4Cache id: " << id << std::endl;
283 #endif
284  // don't automatically lock --> wait until we can catch an error
285  // without scoping the G4AutoLock
286  //
287  G4AutoLock l(G4TypeMutex<G4Cache<V>>(), std::defer_lock);
288 
289  // sometimes the mutex is unavailable in destructors so
290  // try to lock the associated mutex, but catch if it fails
291  try
292  {
293  // a system_error in lock means that the mutex is unavailable
294  // we want to throw the error that comes from locking an unavailable
295  // mutex so that we know there is a memory leak
296  // if the mutex is valid, this will hold until the other thread finishes
297  //
298  l.lock();
299  }
300  catch (std::system_error& e)
301  {
302  // the error that comes from locking an unavailable mutex
303 #ifdef G4VERBOSE
304  G4cout << "Non-critical error: mutex lock failure in ~G4Cache<"
305  << typeid(V).name() << ">. " << G4endl
306  << "If the RunManagerKernel has been deleted, it failed to "
307  << "delete an allocated resource" << G4endl
308  << "and this destructor is being called after the statics "
309  << "were destroyed." << G4endl;
310  G4cout << "Exception: [code: " << e.code() << "] caught: "
311  << e.what() << G4endl;
312 #endif
313  }
314  ++dstrctr;
315  G4bool last = ( dstrctr == instancesctr );
316  theCache.Destroy(id, last);
317  if (last)
318  {
319  instancesctr.store(0);
320  dstrctr.store(0);
321  }
322 }
323 
324 template<class V>
325 V& G4Cache<V>::Get() const
326 { return GetCache(); }
327 
328 template<class V>
329 void G4Cache<V>::Put( const V& val ) const
330 { GetCache() = val; }
331 
332 // Should here remove from cache element?
333 template<class V>
335 { return GetCache(); }
336 
337 template<class V>
338 std::atomic<unsigned int> G4Cache<V>::instancesctr(0);
339 
340 template<class V>
341 std::atomic<unsigned int> G4Cache<V>::dstrctr(0);
342 
343 
344 //========== Implementation: G4VectorCache<V> ===========================
345 
346 template<class V>
348 { }
349 
350 template<class V>
352 {
353 #ifdef g4cdebug
354  std::cout << "~G4VectorCache "
356  << " with size: " << Size() << "->";
357  for ( size_type i = 0 ; i < Size() ; ++i )
358  std::cout << operator[](i) << ",";
359  std::cout << "<-" << std::endl;
360 #endif
361 }
362 
363 template<class V>
365 {
367  cc.resize(nElems);
368 }
369 
370 template<class V>
371 G4VectorCache<V>::G4VectorCache(G4int nElems , V* vals )
372 {
373  vector_type& cc = G4Cache<vector_type>::Get();
374  cc.resize(nElems);
375  for ( G4int idx = 0 ; idx < nElems ; ++idx )
376  cc[idx]=vals[idx];
377 }
378 
379 template<class V>
380 void G4VectorCache<V>::Push_back( const V& val )
381 {
382  G4Cache<vector_type>::Get().push_back( val );
383 }
384 
385 template<class V>
387 {
389  value_type val = cc[cc.size()-1];
390  cc.pop_back();
391  return val;
392 }
393 
394 template<class V>
396 {
398  return cc[idx];
399 }
400 
401 template<class V>
403 {
404  return G4Cache<vector_type>::Get().begin();
405 }
406 
407 template<class V>
409 {
410  return G4Cache<vector_type>::Get().end();
411 }
412 
413 template<class V>
415 {
416  G4Cache<vector_type>::Get().clear();
417 }
418 
419 //template<class V>
420 //typename G4VectorCache<V>::size_type G4VectorCache<V>::Size()
421 //{
422 // return G4Cache<vector_type>::Get().size();
423 //}
424 
425 //======== Implementation: G4MapType<K,V> ===========================
426 
427 template<class K, class V>
429 {
430 #ifdef g4cdebug
431  std::cout << "~G4MacCache " << G4Cache<map_type>::GetId()
432  << " with size: " << Size() << "->";
433  for ( iterator it = Begin() ; it != End() ; ++it )
434  std::cout<<it->first << ":" << it->second << ",";
435  std::cout << "<-" << std::endl;
436 #endif
437 }
438 
439 template<class K, class V>
440 std::pair<typename G4MapCache<K,V>::iterator,G4bool>
441 G4MapCache<K,V>::Insert(const K& k, const V& v)
442 {
443  return G4Cache<map_type>::Get().insert(std::pair<key_type,value_type>(k,v));
444 }
445 
446 //template<class K, class V>
447 //typename G4MapCache<K,V>::size_type G4MapCache<K,V>::Size()
448 //{
449 // return G4Cache<map_type>::Get().size();
450 //}
451 
452 template<class K, class V>
454 {
455  return G4Cache<map_type>::Get().begin();
456 }
457 template<class K, class V>
459 {
460  return G4Cache<map_type>::Get().end();
461 }
462 
463 template<class K, class V>
465 {
466  return G4Cache<map_type>::Get().find(k);
467 }
468 
469 template<class K, class V>
471 {
472  return ( Find(k) != End() );
473 }
474 
475 template<class K, class V>
476 V& G4MapCache<K,V>::Get(const K& k )
477 {
478  return Find(k)->second;
479 }
480 
481 template<class K, class V>
483 {
484  return G4Cache<map_type>::Get().erase(k);
485 }
486 
487 template<class K, class V>
489 {
490  return (G4Cache<map_type>::Get())[k];
491 }
492 
493 #endif