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 // G4ios implementation 27 // 28 // Authors: H.Yoshida, M.Nagamatu - November 1998 29 // -------------------------------------------------------------------- 30 31 #include "G4ios.hh" 32 33 #include "G4coutDestination.hh" 34 35 #include <iostream> 36 37 namespace 38 { 39 // Concrete streambuf redirecting output to G4coutDestination via G4cout etc 40 // Templated on two policy types to determine: 41 // - DestinationPolicy: which member member function of G4coutDestination to redirect to 42 // - DefaultPolicy: what to do if G4coutDestination is default (nullptr) 43 template <typename DestinationPolicy, typename DefaultPolicy> 44 class G4strstreambuf : public std::basic_streambuf<char> 45 { 46 public: 47 G4strstreambuf() 48 { 49 size = 4095; 50 buffer = new char[size + 1]; 51 } 52 53 ~G4strstreambuf() override 54 { 55 delete[] buffer; 56 } 57 58 G4strstreambuf(const G4strstreambuf&) = delete; 59 G4strstreambuf& operator=(const G4strstreambuf&) = delete; 60 61 G4int overflow(G4int c = EOF) override 62 { 63 G4int result = 0; 64 if (count >= size) result = sync(); 65 66 buffer[count] = (char)c; 67 count++; 68 69 return result; 70 } 71 72 G4int sync() override 73 { 74 buffer[count] = '\0'; 75 count = 0; 76 return ReceiveString(); 77 } 78 79 #ifdef WIN32 80 virtual G4int underflow() { return 0; } 81 #endif 82 83 void SetDestination(G4coutDestination* dest) { destination = dest; } 84 85 inline G4int ReceiveString() 86 { 87 G4String stringToSend(buffer); 88 if (destination != nullptr) { 89 return DestinationPolicy::PostMessage(destination, stringToSend); 90 } 91 return DefaultPolicy::PostMessage(stringToSend); 92 } 93 94 private: 95 char* buffer = nullptr; 96 G4int count = 0; 97 G4int size = 0; 98 G4coutDestination* destination = nullptr; 99 }; 100 101 // Policies 102 struct PostToG4debug 103 { 104 static inline G4int PostMessage(G4coutDestination* d, const G4String& s) 105 { 106 return d->ReceiveG4debug_(s); 107 } 108 }; 109 110 struct PostToG4cout 111 { 112 static inline G4int PostMessage(G4coutDestination* d, const G4String& s) 113 { 114 return d->ReceiveG4cout_(s); 115 } 116 }; 117 118 struct PostToG4cerr 119 { 120 static inline G4int PostMessage(G4coutDestination* d, const G4String& s) 121 { 122 return d->ReceiveG4cerr_(s); 123 } 124 }; 125 126 struct DefaultToCout 127 { 128 static inline G4int PostMessage(const G4String& s) 129 { 130 std::cout << s << std::flush; 131 return 0; 132 } 133 }; 134 135 struct DefaultToCerr 136 { 137 static inline G4int PostMessage(const G4String& s) 138 { 139 std::cerr << s << std::flush; 140 return 0; 141 } 142 }; 143 144 using G4debugstreambuf = G4strstreambuf<PostToG4debug, DefaultToCout>; 145 using G4coutstreambuf = G4strstreambuf<PostToG4cout, DefaultToCout>; 146 using G4cerrstreambuf = G4strstreambuf<PostToG4cerr, DefaultToCerr>; 147 } // namespace 148 149 #ifdef G4MULTITHREADED 150 // --- StreamBuffers 151 G4debugstreambuf*& _G4debugbuf_p() 152 { 153 G4ThreadLocalStatic auto* _instance = new G4debugstreambuf; 154 return _instance; 155 } 156 157 G4coutstreambuf*& _G4coutbuf_p() 158 { 159 G4ThreadLocalStatic auto* _instance = new G4coutstreambuf; 160 return _instance; 161 } 162 163 G4cerrstreambuf*& _G4cerrbuf_p() 164 { 165 G4ThreadLocalStatic auto* _instance = new G4cerrstreambuf; 166 return _instance; 167 } 168 169 // --- Streams 170 std::ostream*& _G4debug_p() 171 { 172 G4ThreadLocalStatic auto* _instance = new std::ostream(_G4debugbuf_p()); 173 return _instance; 174 } 175 176 std::ostream*& _G4cout_p() 177 { 178 G4ThreadLocalStatic auto* _instance = new std::ostream(_G4coutbuf_p()); 179 return _instance; 180 } 181 182 std::ostream*& _G4cerr_p() 183 { 184 G4ThreadLocalStatic auto* _instance = new std::ostream(_G4cerrbuf_p()); 185 return _instance; 186 } 187 188 void G4iosInitialization() 189 { 190 // --- Stream Buffers 191 if (_G4debugbuf_p() == nullptr) { 192 _G4debugbuf_p() = new G4debugstreambuf; 193 } 194 if (_G4coutbuf_p() == nullptr) { 195 _G4coutbuf_p() = new G4coutstreambuf; 196 } 197 if (_G4cerrbuf_p() == nullptr) { 198 _G4cerrbuf_p() = new G4cerrstreambuf; 199 } 200 201 // --- Streams 202 if (_G4debug_p() == &std::cout || _G4debug_p() == nullptr) { 203 _G4debug_p() = new std::ostream(_G4debugbuf_p()); 204 } 205 if (_G4cout_p() == &std::cout || _G4cout_p() == nullptr) { 206 _G4cout_p() = new std::ostream(_G4coutbuf_p()); 207 } 208 if (_G4cerr_p() == &std::cerr || _G4cerr_p() == nullptr) { 209 _G4cerr_p() = new std::ostream(_G4cerrbuf_p()); 210 } 211 } 212 213 void G4iosFinalization() 214 { 215 // Reverse order 216 // --- Flush 217 _G4debug_p()->flush(); 218 _G4cout_p()->flush(); 219 _G4cerr_p()->flush(); 220 221 // --- Streams 222 delete _G4debug_p(); 223 _G4debug_p() = &std::cout; 224 delete _G4cout_p(); 225 _G4cout_p() = &std::cout; 226 delete _G4cerr_p(); 227 _G4cerr_p() = &std::cerr; 228 229 // --- Stream Buffers 230 delete _G4debugbuf_p(); 231 _G4debugbuf_p() = nullptr; 232 delete _G4coutbuf_p(); 233 _G4coutbuf_p() = nullptr; 234 delete _G4cerrbuf_p(); 235 _G4cerrbuf_p() = nullptr; 236 } 237 238 # define G4debugbuf (*_G4debugbuf_p()) 239 # define G4coutbuf (*_G4coutbuf_p()) 240 # define G4cerrbuf (*_G4cerrbuf_p()) 241 242 // We want to trigger initialization at load time and 243 // finalization at unloading time. Directly manipulating 244 // the `.init/.fini` section using the `__attribute__((constructor))` 245 // (beside that it does not work on Windows) does not work 246 // where Geant4 is built with static libraries but a downstream 247 // package is built with shared library and has also executable 248 // that are linking against those shared library and directly 249 // to the Geant4 static libraries (for example if the executable 250 // code calls Geant4 directly in addition to indirectly through 251 // the shared library). 252 // In this example, the explicit `.init/.fini` manipulations are 253 // added twice (because the linker is asked to link with this .o 254 // file twice and each time needs to add the init and finalization) 255 // This issue appear also for the initialization on an file static 256 // including those declared as function static in anonymous namespace. 257 // To get the behavior we need (where the G4iosFinalization 258 // and G4iosFinalization are called exactly once), we need to 259 // associate the initialization with a symbol and/or mechanism that 260 // the linker is told to de-duplicate even in the example described 261 // above. So we use an extern object that is guaranteed to be only 262 // initialized once. 263 namespace 264 { 265 struct RAII_G4iosSystem { 266 RAII_G4iosSystem() { 267 G4iosInitialization(); 268 } 269 ~RAII_G4iosSystem() { 270 G4iosFinalization(); 271 } 272 }; 273 } // namespace 274 // Extern but not user reachable (anonymous type) 275 // We want the linker to only create one of those. 276 extern "C" RAII_G4iosSystem RAII_G4iosSystemObj; 277 278 #else // Sequential 279 280 G4debugstreambuf G4debugbuf; 281 G4coutstreambuf G4coutbuf; 282 G4cerrstreambuf G4cerrbuf; 283 284 std::ostream G4debug(&G4debugbuf); 285 std::ostream G4cout(&G4coutbuf); 286 std::ostream G4cerr(&G4cerrbuf); 287 288 void G4iosInitialization() {} 289 void G4iosFinalization() { 290 G4debug.flush(); 291 G4cout.flush(); 292 G4cerr.flush(); 293 } 294 295 #endif 296 297 void G4iosSetDestination(G4coutDestination* sink) 298 { 299 G4debugbuf.SetDestination(sink); 300 G4coutbuf.SetDestination(sink); 301 G4cerrbuf.SetDestination(sink); 302 } 303