debugstream.hh

Go to the documentation of this file.
00001 // $Id$
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

Generated on Fri Apr 29 2011 with Doxygen (ver 1.7.1) [doxygen-log,error-log].