00001
00002
00003
00004 #ifndef DUNE_DEBUGSTREAM_HH
00005 #define DUNE_DEBUGSTREAM_HH
00006
00011 #include <iostream>
00012 #include <stack>
00013
00014 #include <dune/common/exceptions.hh>
00015
00016 namespace Dune {
00017
00116 typedef unsigned int DebugLevel;
00117
00127 template <DebugLevel current, DebugLevel threshold>
00128 struct greater_or_equal {
00129 static const bool value = (current >= threshold);
00130 };
00131
00132
00139 template <DebugLevel current, DebugLevel mask>
00140 struct common_bits {
00141 enum {value = ((current & mask)!=0) };
00142 };
00143
00144
00146 class DebugStreamError : public IOError {};
00147
00148 class StreamWrap {
00149 public:
00150 StreamWrap(std::ostream& _out) : out(_out) { }
00151 std::ostream& out;
00152 StreamWrap *next;
00153 };
00154
00156 class DebugStreamState {
00157
00158 public:
00160 StreamWrap* current;
00161
00163 bool _active;
00164
00166 bool _tied;
00167
00169 unsigned int _tied_streams;
00170 };
00171
00186 template <DebugLevel thislevel = 1,
00187 DebugLevel dlevel = 1,
00188 DebugLevel alevel = 1,
00189 template<DebugLevel, DebugLevel> class activator = greater_or_equal>
00190 class DebugStream : public DebugStreamState {
00191 public:
00197 DebugStream(std::ostream& out = std::cerr) {
00198
00199 current = new StreamWrap(out);
00200 current->next = 0;
00201
00202
00203 _active = activator<thislevel,alevel>::value;
00204
00205
00206 _tied = false;
00207
00208
00209 _tied_streams = 0;
00210 }
00211
00217 DebugStream (DebugStreamState& master,
00218 std::ostream& fallback = std::cerr)
00219 {
00220
00221 current = new StreamWrap(fallback);
00222 current->next = 0;
00223
00224
00225 _active = activator<thislevel,alevel>::value;
00226 _tied_streams = 0;
00227
00228
00229 _tied = true;
00230 tiedstate = &master;
00231 tiedstate->_tied_streams++;
00232 }
00233
00240 ~DebugStream() noexcept(false)
00241 {
00242
00243 if (_tied)
00244 tiedstate->_tied_streams--;
00245 else {
00246
00247 if (_tied_streams != 0)
00248 DUNE_THROW(DebugStreamError,
00249 "There are streams still tied to this stream!");
00250 }
00251
00252
00253 while (current != 0) {
00254 StreamWrap *s = current;
00255 current = current->next;
00256 delete s;
00257 }
00258 }
00259
00261 template <class T>
00262 DebugStream& operator<<(const T data) {
00263
00264 if (activator<thislevel, dlevel>::value) {
00265 if (! _tied) {
00266 if (_active)
00267 current->out << data;
00268 } else {
00269 if (_active && tiedstate->_active)
00270 tiedstate->current->out << data;
00271 }
00272 }
00273
00274 return *this;
00275 }
00276
00284 DebugStream& operator<<(const int data) {
00285
00286 if (activator<thislevel, dlevel>::value) {
00287 if (! _tied) {
00288 if (_active)
00289 current->out << data;
00290 } else {
00291 if (_active && tiedstate->_active)
00292 tiedstate->current->out << data;
00293 }
00294 }
00295
00296 return *this;
00297 }
00298
00300 DebugStream& operator<<(std::ostream& (*f)(std::ostream&)) {
00301 if (activator<thislevel, dlevel>::value) {
00302 if (! _tied) {
00303 if (_active)
00304 f(current->out);
00305 } else {
00306 if (_active && tiedstate->_active)
00307 f(tiedstate->current->out);
00308 }
00309 }
00310
00311 return *this;
00312 }
00313
00315 DebugStream& flush() {
00316 if (activator<thislevel, dlevel>::value) {
00317 if (! _tied) {
00318 if (_active)
00319 current->out.flush();
00320 } else {
00321 if (_active && tiedstate->_active)
00322 tiedstate->current->out.flush();
00323 }
00324 }
00325
00326 return *this;
00327 }
00328
00330 void push(bool b) {
00331
00332 if (activator<thislevel,alevel>::value) {
00333 _actstack.push(_active);
00334 _active = b;
00335 } else {
00336
00337 _actstack.push(false);
00338 }
00339 }
00340
00342 void pop() throw(DebugStreamError) {
00343 if (_actstack.empty())
00344 DUNE_THROW(DebugStreamError, "No previous activation setting!");
00345
00346 _active = _actstack.top();
00347 _actstack.pop();
00348 }
00349
00356 bool active() const {
00357 return activator<thislevel, dlevel>::value && _active;
00358 }
00359
00364 void attach(std::ostream& stream) {
00365 if (_tied)
00366 DUNE_THROW(DebugStreamError, "Cannot attach to a tied stream!");
00367
00368 StreamWrap* newcurr = new StreamWrap(stream);
00369 newcurr->next = current;
00370 current = newcurr;
00371 }
00372
00374 void detach() throw(DebugStreamError) {
00375 if (current->next == 0)
00376 DUNE_THROW(DebugStreamError, "Cannot detach initial stream!");
00377 if (_tied)
00378 DUNE_THROW(DebugStreamError, "Cannot detach a tied stream!");
00379
00380 StreamWrap* old = current;
00381 current = current->next;
00382 delete old;
00383 }
00384
00385
00386 void tie(DebugStreamState& to) throw(DebugStreamError) {
00387 if (to._tied)
00388 DUNE_THROW(DebugStreamError, "Cannot tie to an already tied stream!");
00389 if (_tied)
00390 DUNE_THROW(DebugStreamError, "Stream already tied: untie first!");
00391
00392 _tied = true;
00393 tiedstate = &to;
00394
00395
00396 tiedstate->_tied_streams++;
00397 }
00398
00400 void untie() throw(DebugStreamError) {
00401 if(! _tied)
00402 DUNE_THROW(DebugStreamError, "Cannot untie, stream is not tied!");
00403
00404 tiedstate->_tied_streams--;
00405 _tied = false;
00406 tiedstate = 0;
00407 }
00408
00409 private:
00411 DebugStreamState* tiedstate;
00412
00417 std::stack<bool> _actstack;
00418 };
00419
00421 }
00422
00423
00424 #endif