dune-common
2.2.0
|
00001 // $Id: debugstream.hh 6785 2012-05-31 22:07:47Z sander $ 00002 00003 #ifndef DUNE_DEBUGSTREAM_HH 00004 #define DUNE_DEBUGSTREAM_HH 00005 00010 #include <iostream> 00011 #include <stack> 00012 00013 #include <dune/common/exceptions.hh> 00014 00015 namespace Dune { 00016 00115 typedef unsigned int DebugLevel; 00116 00126 template <DebugLevel current, DebugLevel threshold> 00127 struct greater_or_equal { 00128 static const bool value = (current >= threshold); 00129 }; 00130 00131 00138 template <DebugLevel current, DebugLevel mask> 00139 struct common_bits { 00140 enum {value = ((current & mask)!=0) }; 00141 }; 00142 00143 00145 class DebugStreamError : public IOError {}; 00146 00147 class StreamWrap { 00148 public: 00149 StreamWrap(std::ostream& _out) : out(_out) { }; 00150 std::ostream& out; 00151 StreamWrap *next; 00152 }; 00153 00155 class DebugStreamState { 00156 // !!! should be protected somehow but that won't be easy 00157 public: 00159 StreamWrap* current; 00160 00162 bool _active; 00163 00165 bool _tied; 00166 00168 unsigned int _tied_streams; 00169 }; 00170 00185 template <DebugLevel thislevel = 1, 00186 DebugLevel dlevel = 1, 00187 DebugLevel alevel = 1, 00188 template<DebugLevel, DebugLevel> class activator = greater_or_equal> 00189 class DebugStream : public DebugStreamState { 00190 public: 00196 DebugStream(std::ostream& out = std::cerr) { 00197 // start a new list of streams 00198 current = new StreamWrap(out); 00199 current->next = 0; 00200 00201 // check if we are above the default activation level 00202 _active = activator<thislevel,alevel>::value; 00203 00204 // we're not tied to another DebugStream 00205 _tied = false; 00206 00207 // no child streams yet 00208 _tied_streams = 0; 00209 }; 00210 00216 DebugStream (DebugStreamState& master, 00217 std::ostream& fallback = std::cerr) 00218 { 00219 // start a new list of streams 00220 current = new StreamWrap(fallback); 00221 current->next = 0; 00222 00223 // check if we are above the default activation level 00224 _active = activator<thislevel,alevel>::value; 00225 _tied_streams = 0; 00226 00227 // tie to the provided stream 00228 _tied = true; 00229 tiedstate = &master; 00230 tiedstate->_tied_streams++; 00231 }; 00232 00239 ~DebugStream() { 00240 // untie 00241 if (_tied) 00242 tiedstate->_tied_streams--; 00243 else { 00244 // check if somebody still ties to us... 00245 if (_tied_streams != 0) 00246 DUNE_THROW(DebugStreamError, 00247 "There are streams still tied to this stream!"); 00248 }; 00249 00250 // remove ostream-stack 00251 while (current != 0) { 00252 StreamWrap *s = current; 00253 current = current->next; 00254 delete s; 00255 }; 00256 }; 00257 00259 template <class T> 00260 DebugStream& operator<<(const T data) { 00261 // remove the following code if stream wasn't compiled active 00262 if (activator<thislevel, dlevel>::value) { 00263 if (! _tied) { 00264 if (_active) 00265 current->out << data; 00266 } else { 00267 if (_active && tiedstate->_active) 00268 tiedstate->current->out << data; 00269 }; 00270 }; 00271 00272 return *this; 00273 } 00274 00282 DebugStream& operator<<(const int data) { 00283 // remove the following code if stream wasn't compiled active 00284 if (activator<thislevel, dlevel>::value) { 00285 if (! _tied) { 00286 if (_active) 00287 current->out << data; 00288 } else { 00289 if (_active && tiedstate->_active) 00290 tiedstate->current->out << data; 00291 }; 00292 }; 00293 00294 return *this; 00295 } 00296 00298 DebugStream& operator<<(std::ostream& (*f)(std::ostream&)) { 00299 if (activator<thislevel, dlevel>::value) { 00300 if (! _tied) { 00301 if (_active) 00302 f(current->out); 00303 } else { 00304 if (_active && tiedstate->_active) 00305 f(tiedstate->current->out); 00306 }; 00307 } 00308 00309 return *this; 00310 }; 00311 00313 DebugStream& flush() { 00314 if (activator<thislevel, dlevel>::value) { 00315 if (! _tied) { 00316 if (_active) 00317 current->out.flush(); 00318 } else { 00319 if (_active && tiedstate->_active) 00320 tiedstate->current->out.flush(); 00321 }; 00322 } 00323 00324 return *this; 00325 }; 00326 00328 void push(bool b) { 00329 // are we at all active? 00330 if (activator<thislevel,alevel>::value) { 00331 _actstack.push(_active); 00332 _active = b; 00333 } else { 00334 // stay off 00335 _actstack.push(false); 00336 }; 00337 }; 00338 00340 void pop() throw(DebugStreamError) { 00341 if (_actstack.empty()) 00342 DUNE_THROW(DebugStreamError, "No previous activation setting!"); 00343 00344 _active = _actstack.top(); 00345 _actstack.pop(); 00346 }; 00347 00354 bool active() const { 00355 return activator<thislevel, dlevel>::value && _active; 00356 }; 00357 00362 void attach(std::ostream& stream) { 00363 if (_tied) 00364 DUNE_THROW(DebugStreamError, "Cannot attach to a tied stream!"); 00365 00366 StreamWrap* newcurr = new StreamWrap(stream); 00367 newcurr->next = current; 00368 current = newcurr; 00369 }; 00370 00372 void detach() throw(DebugStreamError) { 00373 if (current->next == 0) 00374 DUNE_THROW(DebugStreamError, "Cannot detach initial stream!"); 00375 if (_tied) 00376 DUNE_THROW(DebugStreamError, "Cannot detach a tied stream!"); 00377 00378 StreamWrap* old = current; 00379 current = current->next; 00380 delete old; 00381 }; 00382 00383 // \brief Tie a stream to this one. 00384 void tie(DebugStreamState& to) throw(DebugStreamError) { 00385 if (to._tied) 00386 DUNE_THROW(DebugStreamError, "Cannot tie to an already tied stream!"); 00387 if (_tied) 00388 DUNE_THROW(DebugStreamError, "Stream already tied: untie first!"); 00389 00390 _tied = true; 00391 tiedstate = &to; 00392 00393 // tell master class 00394 tiedstate->_tied_streams++; 00395 }; 00396 00398 void untie() throw(DebugStreamError) { 00399 if(! _tied) 00400 DUNE_THROW(DebugStreamError, "Cannot untie, stream is not tied!"); 00401 00402 tiedstate->_tied_streams--; 00403 _tied = false; 00404 tiedstate = 0; 00405 }; 00406 00407 private: 00409 DebugStreamState* tiedstate; 00410 00415 std::stack<bool> _actstack; 00416 }; 00417 00419 } 00420 00421 00422 #endif