dune-common  2.2.1
debugstream.hh
Go to the documentation of this file.
1 // $Id: debugstream.hh 6785 2012-05-31 22:07:47Z sander $
2 
3 #ifndef DUNE_DEBUGSTREAM_HH
4 #define DUNE_DEBUGSTREAM_HH
5 
10 #include <iostream>
11 #include <stack>
12 
14 
15 namespace Dune {
16 
115  typedef unsigned int DebugLevel;
116 
126  template <DebugLevel current, DebugLevel threshold>
128  static const bool value = (current >= threshold);
129  };
130 
131 
138  template <DebugLevel current, DebugLevel mask>
139  struct common_bits {
140  enum {value = ((current & mask)!=0) };
141  };
142 
143 
145  class DebugStreamError : public IOError {};
146 
147  class StreamWrap {
148  public:
149  StreamWrap(std::ostream& _out) : out(_out) { };
150  std::ostream& out;
152  };
153 
156  // !!! should be protected somehow but that won't be easy
157  public:
160 
162  bool _active;
163 
165  bool _tied;
166 
168  unsigned int _tied_streams;
169  };
170 
185  template <DebugLevel thislevel = 1,
186  DebugLevel dlevel = 1,
187  DebugLevel alevel = 1,
188  template<DebugLevel, DebugLevel> class activator = greater_or_equal>
189  class DebugStream : public DebugStreamState {
190  public:
196  DebugStream(std::ostream& out = std::cerr) {
197  // start a new list of streams
198  current = new StreamWrap(out);
199  current->next = 0;
200 
201  // check if we are above the default activation level
202  _active = activator<thislevel,alevel>::value;
203 
204  // we're not tied to another DebugStream
205  _tied = false;
206 
207  // no child streams yet
208  _tied_streams = 0;
209  };
210 
217  std::ostream& fallback = std::cerr)
218  {
219  // start a new list of streams
220  current = new StreamWrap(fallback);
221  current->next = 0;
222 
223  // check if we are above the default activation level
224  _active = activator<thislevel,alevel>::value;
225  _tied_streams = 0;
226 
227  // tie to the provided stream
228  _tied = true;
229  tiedstate = &master;
230  tiedstate->_tied_streams++;
231  };
232 
240  // untie
241  if (_tied)
242  tiedstate->_tied_streams--;
243  else {
244  // check if somebody still ties to us...
245  if (_tied_streams != 0)
247  "There are streams still tied to this stream!");
248  };
249 
250  // remove ostream-stack
251  while (current != 0) {
252  StreamWrap *s = current;
253  current = current->next;
254  delete s;
255  };
256  };
257 
259  template <class T>
260  DebugStream& operator<<(const T data) {
261  // remove the following code if stream wasn't compiled active
262  if (activator<thislevel, dlevel>::value) {
263  if (! _tied) {
264  if (_active)
265  current->out << data;
266  } else {
267  if (_active && tiedstate->_active)
268  tiedstate->current->out << data;
269  };
270  };
271 
272  return *this;
273  }
274 
282  DebugStream& operator<<(const int data) {
283  // remove the following code if stream wasn't compiled active
284  if (activator<thislevel, dlevel>::value) {
285  if (! _tied) {
286  if (_active)
287  current->out << data;
288  } else {
289  if (_active && tiedstate->_active)
290  tiedstate->current->out << data;
291  };
292  };
293 
294  return *this;
295  }
296 
298  DebugStream& operator<<(std::ostream& (*f)(std::ostream&)) {
299  if (activator<thislevel, dlevel>::value) {
300  if (! _tied) {
301  if (_active)
302  f(current->out);
303  } else {
304  if (_active && tiedstate->_active)
305  f(tiedstate->current->out);
306  };
307  }
308 
309  return *this;
310  };
311 
314  if (activator<thislevel, dlevel>::value) {
315  if (! _tied) {
316  if (_active)
317  current->out.flush();
318  } else {
319  if (_active && tiedstate->_active)
320  tiedstate->current->out.flush();
321  };
322  }
323 
324  return *this;
325  };
326 
328  void push(bool b) {
329  // are we at all active?
330  if (activator<thislevel,alevel>::value) {
331  _actstack.push(_active);
332  _active = b;
333  } else {
334  // stay off
335  _actstack.push(false);
336  };
337  };
338 
340  void pop() throw(DebugStreamError) {
341  if (_actstack.empty())
342  DUNE_THROW(DebugStreamError, "No previous activation setting!");
343 
344  _active = _actstack.top();
345  _actstack.pop();
346  };
347 
354  bool active() const {
355  return activator<thislevel, dlevel>::value && _active;
356  };
357 
362  void attach(std::ostream& stream) {
363  if (_tied)
364  DUNE_THROW(DebugStreamError, "Cannot attach to a tied stream!");
365 
366  StreamWrap* newcurr = new StreamWrap(stream);
367  newcurr->next = current;
368  current = newcurr;
369  };
370 
372  void detach() throw(DebugStreamError) {
373  if (current->next == 0)
374  DUNE_THROW(DebugStreamError, "Cannot detach initial stream!");
375  if (_tied)
376  DUNE_THROW(DebugStreamError, "Cannot detach a tied stream!");
377 
378  StreamWrap* old = current;
379  current = current->next;
380  delete old;
381  };
382 
383  // \brief Tie a stream to this one.
385  if (to._tied)
386  DUNE_THROW(DebugStreamError, "Cannot tie to an already tied stream!");
387  if (_tied)
388  DUNE_THROW(DebugStreamError, "Stream already tied: untie first!");
389 
390  _tied = true;
391  tiedstate = &to;
392 
393  // tell master class
394  tiedstate->_tied_streams++;
395  };
396 
398  void untie() throw(DebugStreamError) {
399  if(! _tied)
400  DUNE_THROW(DebugStreamError, "Cannot untie, stream is not tied!");
401 
402  tiedstate->_tied_streams--;
403  _tied = false;
404  tiedstate = 0;
405  };
406 
407  private:
409  DebugStreamState* tiedstate;
410 
415  std::stack<bool> _actstack;
416  };
417 
419 }
420 
421 
422 #endif