dune-common  2.2.0
debugstream.hh
Go to the documentation of this file.
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