debugstream.hh

Go to the documentation of this file.
00001 // $Id: debugstream.hh 4688 2006-08-10 14:02:26Z oliver $
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 
00134   template <DebugLevel x>
00135   struct notzero {
00136     static const bool value = true;
00137   };
00138 
00139   template < >
00140   struct notzero<0> {
00141     static const bool value = false;
00142   };
00143 
00150   template <DebugLevel current, DebugLevel mask>
00151   struct common_bits {
00152     static const bool value = notzero<current & mask>::value;
00153   };
00154   
00155 
00157   class DebugStreamError : public IOError {};
00158 
00159   class StreamWrap {
00160   public:
00161     StreamWrap(std::ostream& _out) : out(_out) { };
00162     std::ostream& out;
00163     StreamWrap *next;
00164   };
00165 
00167   class DebugStreamState {
00168     // !!! should be protected somehow but that won't be easy
00169   public:
00171     StreamWrap* current;
00172     
00174     bool _active;
00175     
00177     bool _tied;
00178 
00180     unsigned int _tied_streams;
00181   };
00182 
00197   template <DebugLevel thislevel = 1, 
00198             DebugLevel dlevel = 1, 
00199             DebugLevel alevel = 1, 
00200             template<DebugLevel, DebugLevel> class activator = greater_or_equal>
00201   class DebugStream : public DebugStreamState {
00202   public:
00208     DebugStream(std::ostream& out = std::cerr) {
00209       // start a new list of streams
00210       current = new StreamWrap(out);
00211       current->next = 0;
00212       
00213       // check if we are above the default activation level
00214       _active = activator<thislevel,alevel>::value;
00215 
00216       // we're not tied to another DebugStream
00217       _tied = false;
00218 
00219       // no child streams yet
00220       _tied_streams = 0;
00221     };
00222 
00228     DebugStream (DebugStreamState& master, 
00229                 std::ostream& fallback = std::cerr) 
00230     {
00231       // start a new list of streams
00232       current = new StreamWrap(fallback);
00233       current->next = 0;
00234       
00235       // check if we are above the default activation level
00236       _active = activator<thislevel,alevel>::value;
00237       _tied_streams = 0;
00238 
00239       // tie to the provided stream
00240       _tied = true;
00241       tiedstate = &master;
00242       tiedstate->_tied_streams++;
00243     };    
00244 
00251     ~DebugStream() {
00252       // untie
00253       if (_tied)
00254         tiedstate->_tied_streams--;
00255       else {
00256         // check if somebody still ties to us...
00257         if (_tied_streams != 0)
00258           DUNE_THROW(DebugStreamError, 
00259                      "There are streams still tied to this stream!");
00260       };
00261 
00262       // remove ostream-stack
00263       while (current != 0) {
00264         StreamWrap *s = current;
00265         current = current->next;
00266         delete s;
00267       };
00268     };
00269 
00271     template <class T>
00272     DebugStream& operator<<(const T data) {
00273       // remove the following code if stream wasn't compiled active
00274       if (activator<thislevel, dlevel>::value) {
00275         if (! _tied) {
00276           if (_active)
00277             current->out << data;
00278         } else {
00279           if (_active && tiedstate->_active)
00280             tiedstate->current->out << data;        
00281         };
00282       };      
00283 
00284       return *this;
00285     }
00286 
00294     DebugStream& operator<<(const int data) {
00295       // remove the following code if stream wasn't compiled active
00296       if (activator<thislevel, dlevel>::value) {
00297         if (! _tied) {
00298           if (_active)
00299             current->out << data;
00300         } else {
00301           if (_active && tiedstate->_active)
00302             tiedstate->current->out << data;        
00303         };
00304       };      
00305 
00306       return *this;
00307     }
00308     
00310     DebugStream& operator<<(std::ostream& (*f)(std::ostream&)) {
00311       if (activator<thislevel, dlevel>::value) {
00312         if (! _tied) {
00313           if (_active)
00314             f(current->out);
00315         } else {
00316           if (_active && tiedstate->_active)
00317             f(tiedstate->current->out);
00318         };
00319       }
00320 
00321       return *this;
00322     };  
00323     
00325     DebugStream& flush() {
00326       if (activator<thislevel, dlevel>::value) {
00327         if (! _tied) {
00328           if (_active)
00329             current->out.flush();
00330         } else {
00331           if (_active && tiedstate->_active)
00332             tiedstate->current->out.flush();
00333         };
00334       }
00335 
00336       return *this;
00337     };  
00338     
00340     void push(bool b) {
00341       // are we at all active?
00342       if (activator<thislevel,alevel>::value) {
00343         _actstack.push(_active);
00344         _active = b;
00345       } else {
00346         // stay off
00347         _actstack.push(false);
00348       };
00349     };
00350     
00352     void pop() throw(DebugStreamError) {
00353       if (_actstack.empty())
00354         DUNE_THROW(DebugStreamError, "No previous activation setting!");
00355       
00356       _active = _actstack.top();
00357       _actstack.pop();
00358     };
00359 
00366     bool active() const {
00367       return activator<thislevel, dlevel>::value && _active;
00368     };
00369     
00374     void attach(std::ostream& stream) {
00375       if (_tied)
00376         DUNE_THROW(DebugStreamError, "Cannot attach to a tied stream!");
00377 
00378       StreamWrap* newcurr = new StreamWrap(stream);
00379       newcurr->next = current;
00380       current = newcurr;    
00381     };
00382     
00384     void detach() throw(DebugStreamError) {
00385       if (current->next == 0)
00386         DUNE_THROW(DebugStreamError, "Cannot detach initial stream!");
00387       if (_tied)
00388         DUNE_THROW(DebugStreamError, "Cannot detach a tied stream!");
00389       
00390       StreamWrap* old = current;
00391       current = current->next;
00392       delete old;
00393     };
00394 
00395     // \brief Tie a stream to this one.
00396     void tie(DebugStreamState& to) throw(DebugStreamError) {
00397       if (to._tied)
00398         DUNE_THROW(DebugStreamError, "Cannot tie to an already tied stream!");
00399       if (_tied)
00400         DUNE_THROW(DebugStreamError, "Stream already tied: untie first!");
00401 
00402       _tied = true;
00403       tiedstate = &to;
00404       
00405       // tell master class
00406       tiedstate->_tied_streams++;
00407     };
00408     
00410     void untie() throw(DebugStreamError) {
00411       if(! _tied)
00412         DUNE_THROW(DebugStreamError, "Cannot untie, stream is not tied!");
00413 
00414       tiedstate->_tied_streams--;
00415       _tied = false;
00416       tiedstate = 0;
00417     };
00418 
00419   private:
00421     DebugStreamState* tiedstate;
00422 
00427     std::stack<bool> _actstack;
00428   };  
00429 
00431 }
00432 
00433 
00434 #endif

Generated on Thu Apr 2 10:39:53 2009 for dune-common by  doxygen 1.5.6