summaryrefslogtreecommitdiff
path: root/klm/util/exception.hh
blob: 124689cf52401228c18f3f9700400e5661301da5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#ifndef UTIL_EXCEPTION__
#define UTIL_EXCEPTION__

#include "util/string_piece.hh"

#include <exception>
#include <sstream>
#include <string>

namespace util {

class Exception : public std::exception {
  public:
    Exception() throw();
    virtual ~Exception() throw();

    const char *what() const throw() { return what_.c_str(); }

    // This helps restrict operator<< defined below.  
    template <class T> struct ExceptionTag {
      typedef T Identity;
    };

    std::string &Str() {
      return what_;
    }

  protected:
    std::string what_;
};

/* This implements the normal operator<< for Exception and all its children. 
 * SNIFAE means it only applies to Exception.  Think of this as an ersatz
 * boost::enable_if.  
 */
template <class Except, class Data> typename Except::template ExceptionTag<Except&>::Identity operator<<(Except &e, const Data &data) {
  // Argh I had a stringstream in the exception, but the only way to get the string is by calling str().  But that's a temporary string, so virtual const char *what() const can't actually return it.  
  std::stringstream stream;
  stream << data;
  e.Str() += stream.str();
  return e;
}
template <class Except> typename Except::template ExceptionTag<Except&>::Identity operator<<(Except &e, const char *data) {
  e.Str() += data;
  return e;
}
template <class Except> typename Except::template ExceptionTag<Except&>::Identity operator<<(Except &e, const std::string &data) {
  e.Str() += data;
  return e;
}
template <class Except> typename Except::template ExceptionTag<Except&>::Identity operator<<(Except &e, const StringPiece &str) {
  e.Str().append(str.data(), str.length());
  return e;
}

#define UTIL_THROW(Exception, Modify) { Exception UTIL_e; {UTIL_e << Modify;} throw UTIL_e; }

class ErrnoException : public Exception {
  public:
    ErrnoException() throw();

    virtual ~ErrnoException() throw();

    int Error() { return errno_; }

  private:
    int errno_;
};

} // namespace util

#endif // UTIL_EXCEPTION__