ECCE @ EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
G4CacheDetails.hh
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file G4CacheDetails.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 //
32 // The classes contained in this header files are used by
33 // G4Cache to store a TLS instance of the cached object.
34 // These classes should not be used by client code, but
35 // are used by one of the G4Cache classes.
36 //
37 // G4Cache is a container of the cached value.
38 // Not memory efficient, but CPU efficient (constant time access).
39 // A different version with a map instead of a vector should be
40 // memory efficient and less CPU efficient (log-time access).
41 // If really a lot of these objects are used
42 // we may want to consider the map version to save some memory.
43 //
44 // These are simplified "split-classes" without any
45 // copy-from-master logic. Each cached object is associated
46 // a unique identified (an integer), that references an instance
47 // of the cached value (of template type VALTYPE) in a
48 // static TLS data structure.
49 //
50 // In case the cache is used for a cached object the object class
51 // has to provide a default constructor. Alternatively pointers to
52 // objects can be stored in the cache and this limitation is removed
53 // but explicit handling of memory (new/delete) of cached object becomes
54 // client responsibility.
55 
56 // History:
57 // 21 Oct 2013: A. Dotti - First implementation
58 //
59 // Todos: - Understand if map based class can be more efficent than
60 // vector one.
61 // - Evaluate use of specialized allocator for TLS "new".
62 // ------------------------------------------------------------
63 
64 #ifndef G4CacheDetails_hh
65 #define G4CacheDetails_hh
66 
67 #include <vector>
68 #include "G4Threading.hh"
69 #include "globals.hh"
70 
71 // A TLS storage for a cache of type VALTYPE
72 //
73 template<class VALTYPE> class G4CacheReference
74 {
75  public:
76 
77  inline void Initialize( unsigned int id );
78  // Initliaze TLS storage
79 
80  inline void Destroy( unsigned int id , G4bool last);
81  // Cleanup TLS storage for instance id. If last==true
82  // destroy and cleanup object container
83 
84  inline VALTYPE& GetCache(unsigned int id) const;
85  // Returns cached value for instance id
86 
87  private:
88 
89  typedef std::vector<VALTYPE*> cache_container;
90  // Implementation detail: the cached object is stored as a
91  // pointer. Object is stored as a pointer to avoid too large
92  // std::vector in case of stored objects and allow use of
93  // specialized allocators
94 
95  static cache_container*& cache();
96 };
97 
98 // Template specialization for pointers
99 // Note: Objects are not owned by cache, for this version of the cache
100 // the explicit new/delete of the cached object
101 //
102 template<class VALTYPE> class G4CacheReference<VALTYPE*>
103 {
104  public:
105  inline void Initialize( unsigned int id );
106 
107  inline void Destroy( unsigned int id , G4bool last);
108 
109  inline VALTYPE*& GetCache(unsigned int id) const;
110 
111  private:
112  typedef std::vector<VALTYPE*> cache_container;
113  static cache_container*& cache();
114 };
115 
116 // Template specialization for probably the most used case: double
117 // Be more efficient avoiding unnecessary "new/delete"
118 //
119 template<> class G4CacheReference<G4double>
120 {
121  public:
122 
123  inline void Initialize( unsigned int id );
124 
125  inline void Destroy( unsigned int id , G4bool last);
126 
127  inline G4double& GetCache(unsigned int id) const;
128 
129  private:
130 
131  typedef std::vector<G4double> cache_container;
132  static G4GLOB_DLL cache_container*& cache();
133 };
134 
135 
136 //======= Implementation: G4CacheReference<V>
137 //===========================================
138 
139 template<class V>
140 void G4CacheReference<V>::Initialize( unsigned int id )
141 {
142  // Create cache container
143  if ( cache() == 0 )
144  {
145 #ifdef g4cdebug
146  std::cout << "Generic template container..." << std::endl;
147 #endif
148  cache() = new cache_container;
149  }
150  if ( cache()->size() <= id )
151  {
152  cache()->resize(id+1,static_cast<V*>(0));
153  }
154  if ( (*cache())[id] == 0 )
155  {
156  (*cache())[id]=new V;
157  }
158 }
159 
160 template<class V>
161 void G4CacheReference<V>::Destroy( unsigned int id, G4bool last )
162 {
163  if ( cache() )
164  {
165 #ifdef g4cdebug
166  std::cout << "V: Destroying element "<< id
167  << " is last? " << last << std::endl;
168 #endif
169  if ( cache()->size() < id )
170  {
172  msg << "Internal fatal error. Invalid G4Cache size (requested id: "
173  << id << " but cache has size: "<< cache()->size();
174  msg << " Possibly client created G4Cache object in a thread and"
175  << " tried to delete it from another thread!";
176  G4Exception("G4CacheReference<V>::Destroy", "Cache001",
177  FatalException, msg);
178  return;
179  }
180  if ( cache()->size() > id && (*cache())[id] )
181  {
182 #ifdef g4cdebug
183  std::cout << "V: Destroying element " << id
184  << " size: " << cache()->size() << std::endl;
185 #endif
186  delete (*cache())[id];
187  (*cache())[id]=0;
188  }
189  if (last)
190  {
191 #ifdef g4cdebug
192  std::cout << "V: Destroying LAST element!" << std::endl;
193 #endif
194  delete cache();
195  cache() = 0;
196  }
197  }
198 }
199 
200 template<class V>
201 V& G4CacheReference<V>::GetCache( unsigned int id ) const
202 {
203  return *(cache()->operator[](id));
204 }
205 
206 template<class V>
209 {
210  G4ThreadLocalStatic cache_container* _instance = nullptr;
211  return _instance;
212 }
213 
214 //======= Implementation: G4CacheReference<V*>
215 //============================================
216 
217 template<class V>
218 void G4CacheReference<V*>::Initialize( unsigned int id )
219 {
220  if ( cache() == 0 )
221  {
222 #ifdef g4cdebug
223  std::cout << "Pointer template container..." << std::endl;
224 #endif
225  cache() = new cache_container;
226  }
227  if ( cache()->size() <= id )
228  {
229  cache()->resize(id+1,static_cast<V*>(0));
230  }
231 }
232 
233 template<class V>
234 inline void G4CacheReference<V*>::Destroy( unsigned int id , G4bool last )
235 {
236  if ( cache() )
237  {
238 #ifdef g4cdebug
239  std::cout << "V*: Destroying element " << id << " is last? " << last
240  << std::endl;
241 #endif
242  if ( cache()->size() < id )
243  {
245  msg << "Internal fatal error. Invalid G4Cache size (requested id: "
246  << id << " but cache has size: " << cache()->size();
247  msg << " Possibly client created G4Cache object in a thread and"
248  << " tried to delete it from another thread!";
249  G4Exception("G4CacheReference<V*>::Destroy", "Cache001",
250  FatalException, msg);
251  return;
252  }
253  if ( cache()->size() > id && (*cache())[id] )
254  {
255  // Ownership is for client
256  // delete (*cache())[id];
257 #ifdef g4cdebug
258  std::cout << "V*: Resetting element " << id
259  << " size: " << cache()->size() << std::endl;
260 #endif
261  (*cache())[id]=0;
262  }
263  if (last )
264  {
265 #ifdef g4cdebug
266  std::cout << "V*: Deleting LAST element!" << std::endl;
267 #endif
268  delete cache();
269  cache() = 0;
270  }
271  }
272 }
273 
274 template<class V>
275 V*& G4CacheReference<V*>::GetCache(unsigned int id) const
276 {
277  return (cache()->operator[](id));
278 }
279 
280 template<class V>
283 {
284  G4ThreadLocalStatic cache_container* _instance = nullptr;
285  return _instance;
286 }
287 
288 //======= Implementation: G4CacheReference<double>
289 //============================================
290 
292 {
293  if ( cache() == 0 )
294  {
295 #ifdef g4cdebug
296  std::cout << "Specialized template for G4double container..." << std::endl;
297 #endif
298  cache() = new cache_container;
299  }
300  if ( cache()->size() <= id )
301  {
302  cache()->resize(id+1,static_cast<G4double>(0));
303  }
304 }
305 
306 void G4CacheReference<G4double>::Destroy( unsigned int /*id*/ , G4bool last)
307 {
308  if ( cache() && last )
309  {
310 #ifdef g4cdebug
311  std::cout << "DB: Destroying LAST element! Is it last? " << last
312  << std::endl;
313 #endif
314  delete cache();
315  cache() = 0;
316  }
317 }
318 
320 {
321  return cache()->operator[](id);
322 }
323 
324 #endif