debugstream.hh
Go to the documentation of this file.00001
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
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
00210 current = new StreamWrap(out);
00211 current->next = 0;
00212
00213
00214 _active = activator<thislevel,alevel>::value;
00215
00216
00217 _tied = false;
00218
00219
00220 _tied_streams = 0;
00221 };
00222
00228 DebugStream (DebugStreamState& master,
00229 std::ostream& fallback = std::cerr)
00230 {
00231
00232 current = new StreamWrap(fallback);
00233 current->next = 0;
00234
00235
00236 _active = activator<thislevel,alevel>::value;
00237 _tied_streams = 0;
00238
00239
00240 _tied = true;
00241 tiedstate = &master;
00242 tiedstate->_tied_streams++;
00243 };
00244
00251 ~DebugStream() {
00252
00253 if (_tied)
00254 tiedstate->_tied_streams--;
00255 else {
00256
00257 if (_tied_streams != 0)
00258 DUNE_THROW(DebugStreamError,
00259 "There are streams still tied to this stream!");
00260 };
00261
00262
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
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
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
00342 if (activator<thislevel,alevel>::value) {
00343 _actstack.push(_active);
00344 _active = b;
00345 } else {
00346
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
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
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