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