dune-common 2.1.1
|
00001 // $Id: debugstream.hh 6145 2010-09-12 22:01:43Z graeser $ 00002 00003 #ifndef DUNE_DEBUGSTREAM_HH 00004 #define DUNE_DEBUGSTREAM_HH 00005 00006 #include <iostream> 00007 #include <stack> 00008 00009 #include <dune/common/exceptions.hh> 00010 00011 namespace Dune { 00012 00111 typedef unsigned int DebugLevel; 00112 00122 template <DebugLevel current, DebugLevel threshold> 00123 struct greater_or_equal { 00124 static const bool value = (current >= threshold); 00125 }; 00126 00127 00134 template <DebugLevel current, DebugLevel mask> 00135 struct common_bits { 00136 enum {value = ((current & mask)!=0) }; 00137 }; 00138 00139 00141 class DebugStreamError : public IOError {}; 00142 00143 class StreamWrap { 00144 public: 00145 StreamWrap(std::ostream& _out) : out(_out) { }; 00146 std::ostream& out; 00147 StreamWrap *next; 00148 }; 00149 00151 class DebugStreamState { 00152 // !!! should be protected somehow but that won't be easy 00153 public: 00155 StreamWrap* current; 00156 00158 bool _active; 00159 00161 bool _tied; 00162 00164 unsigned int _tied_streams; 00165 }; 00166 00181 template <DebugLevel thislevel = 1, 00182 DebugLevel dlevel = 1, 00183 DebugLevel alevel = 1, 00184 template<DebugLevel, DebugLevel> class activator = greater_or_equal> 00185 class DebugStream : public DebugStreamState { 00186 public: 00192 DebugStream(std::ostream& out = std::cerr) { 00193 // start a new list of streams 00194 current = new StreamWrap(out); 00195 current->next = 0; 00196 00197 // check if we are above the default activation level 00198 _active = activator<thislevel,alevel>::value; 00199 00200 // we're not tied to another DebugStream 00201 _tied = false; 00202 00203 // no child streams yet 00204 _tied_streams = 0; 00205 }; 00206 00212 DebugStream (DebugStreamState& master, 00213 std::ostream& fallback = std::cerr) 00214 { 00215 // start a new list of streams 00216 current = new StreamWrap(fallback); 00217 current->next = 0; 00218 00219 // check if we are above the default activation level 00220 _active = activator<thislevel,alevel>::value; 00221 _tied_streams = 0; 00222 00223 // tie to the provided stream 00224 _tied = true; 00225 tiedstate = &master; 00226 tiedstate->_tied_streams++; 00227 }; 00228 00235 ~DebugStream() { 00236 // untie 00237 if (_tied) 00238 tiedstate->_tied_streams--; 00239 else { 00240 // check if somebody still ties to us... 00241 if (_tied_streams != 0) 00242 DUNE_THROW(DebugStreamError, 00243 "There are streams still tied to this stream!"); 00244 }; 00245 00246 // remove ostream-stack 00247 while (current != 0) { 00248 StreamWrap *s = current; 00249 current = current->next; 00250 delete s; 00251 }; 00252 }; 00253 00255 template <class T> 00256 DebugStream& operator<<(const T data) { 00257 // remove the following code if stream wasn't compiled active 00258 if (activator<thislevel, dlevel>::value) { 00259 if (! _tied) { 00260 if (_active) 00261 current->out << data; 00262 } else { 00263 if (_active && tiedstate->_active) 00264 tiedstate->current->out << data; 00265 }; 00266 }; 00267 00268 return *this; 00269 } 00270 00278 DebugStream& operator<<(const int data) { 00279 // remove the following code if stream wasn't compiled active 00280 if (activator<thislevel, dlevel>::value) { 00281 if (! _tied) { 00282 if (_active) 00283 current->out << data; 00284 } else { 00285 if (_active && tiedstate->_active) 00286 tiedstate->current->out << data; 00287 }; 00288 }; 00289 00290 return *this; 00291 } 00292 00294 DebugStream& operator<<(std::ostream& (*f)(std::ostream&)) { 00295 if (activator<thislevel, dlevel>::value) { 00296 if (! _tied) { 00297 if (_active) 00298 f(current->out); 00299 } else { 00300 if (_active && tiedstate->_active) 00301 f(tiedstate->current->out); 00302 }; 00303 } 00304 00305 return *this; 00306 }; 00307 00309 DebugStream& flush() { 00310 if (activator<thislevel, dlevel>::value) { 00311 if (! _tied) { 00312 if (_active) 00313 current->out.flush(); 00314 } else { 00315 if (_active && tiedstate->_active) 00316 tiedstate->current->out.flush(); 00317 }; 00318 } 00319 00320 return *this; 00321 }; 00322 00324 void push(bool b) { 00325 // are we at all active? 00326 if (activator<thislevel,alevel>::value) { 00327 _actstack.push(_active); 00328 _active = b; 00329 } else { 00330 // stay off 00331 _actstack.push(false); 00332 }; 00333 }; 00334 00336 void pop() throw(DebugStreamError) { 00337 if (_actstack.empty()) 00338 DUNE_THROW(DebugStreamError, "No previous activation setting!"); 00339 00340 _active = _actstack.top(); 00341 _actstack.pop(); 00342 }; 00343 00350 bool active() const { 00351 return activator<thislevel, dlevel>::value && _active; 00352 }; 00353 00358 void attach(std::ostream& stream) { 00359 if (_tied) 00360 DUNE_THROW(DebugStreamError, "Cannot attach to a tied stream!"); 00361 00362 StreamWrap* newcurr = new StreamWrap(stream); 00363 newcurr->next = current; 00364 current = newcurr; 00365 }; 00366 00368 void detach() throw(DebugStreamError) { 00369 if (current->next == 0) 00370 DUNE_THROW(DebugStreamError, "Cannot detach initial stream!"); 00371 if (_tied) 00372 DUNE_THROW(DebugStreamError, "Cannot detach a tied stream!"); 00373 00374 StreamWrap* old = current; 00375 current = current->next; 00376 delete old; 00377 }; 00378 00379 // \brief Tie a stream to this one. 00380 void tie(DebugStreamState& to) throw(DebugStreamError) { 00381 if (to._tied) 00382 DUNE_THROW(DebugStreamError, "Cannot tie to an already tied stream!"); 00383 if (_tied) 00384 DUNE_THROW(DebugStreamError, "Stream already tied: untie first!"); 00385 00386 _tied = true; 00387 tiedstate = &to; 00388 00389 // tell master class 00390 tiedstate->_tied_streams++; 00391 }; 00392 00394 void untie() throw(DebugStreamError) { 00395 if(! _tied) 00396 DUNE_THROW(DebugStreamError, "Cannot untie, stream is not tied!"); 00397 00398 tiedstate->_tied_streams--; 00399 _tied = false; 00400 tiedstate = 0; 00401 }; 00402 00403 private: 00405 DebugStreamState* tiedstate; 00406 00411 std::stack<bool> _actstack; 00412 }; 00413 00415 } 00416 00417 00418 #endif