Geant4 Cross Reference |
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 // 69 template <class VALTYPE> 70 class G4CacheReference 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 // 97 template <class VALTYPE> 98 class 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 // 115 template <> 116 class G4CacheReference<G4double> 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 133 template <class V> 134 void G4CacheReference<V>::Initialize(unsigned int id) 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 154 template <class V> 155 void 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 { 165 G4ExceptionDescription msg; 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 194 template <class V> 195 V& G4CacheReference<V>::GetCache(unsigned int id) const 196 { 197 return *(cache()->operator[](id)); 198 } 199 200 template <class V> 201 typename 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 210 template <class V> 211 void 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*>(nullptr)); 223 } 224 } 225 226 template <class V> 227 inline 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 { 237 G4ExceptionDescription msg; 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 267 template <class V> 268 V*& G4CacheReference<V*>::GetCache(unsigned int id) const 269 { 270 return (cache()->operator[](id)); 271 } 272 273 template <class V> 274 typename 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 283 void G4CacheReference<G4double>::Initialize(unsigned int id) 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 298 void 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 311 G4double& G4CacheReference<G4double>::GetCache(unsigned int id) const 312 { 313 return cache()->operator[](id); 314 } 315 316 #endif 317