aboutsummaryrefslogtreecommitdiffstats
path: root/chromeos/exception.h
blob: ae6621f12c61f050209e9b1514714f816b72e4bd (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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
// Copyright (c) 2009 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef LIBCHROMEOS_CHROMEOS_EXCEPTION_H_
#define LIBCHROMEOS_CHROMEOS_EXCEPTION_H_

#include <base/logging.h>

#include <algorithm>
#include <exception>
#include <string>
#include <typeinfo>

/******************************************************************************/

namespace chromeos {
using std::swap;

/******************************************************************************/

// \brief AnyException is a runtime polymophic type which can hold any
// std::exception derived exception.
//
// AnyException supports a safe bool cast, return true iff it contains an
// exception (a default constructed AnyException contains no exception.
//
// AnyException is useful for error handling which doesn't use try/catch - but
// may be converted to use try/catch in the future. I can also be used to
// marshal an exception across a non exception safe boundary.
//
// \example
// AnyException error;
// int x = SomeFunction(error);
// if (error) return;
//
// // ...
//
// int SomeFunction(AnyException& error) {
//   // ...
//   if (something_failed) {
//      error = std::logic_error("Something Failed.");
//      return 0;
//   }
//   // ...
// \end_example

class AnyException : public std::exception {
 public:
  AnyException()
      : object_(NULL) {
  }

  template <typename T>  // T is derived from std::exception
  explicit AnyException(const T& x)
      : object_(new Model<T>(x)) {
  }

  AnyException(const AnyException& x)
      : object_(x.object_ ? x.object_->Copy() : NULL) {
  }

  ~AnyException() throw() {
    delete object_;
  }

  AnyException& operator=(AnyException x) {
    swap(*this, x);
  }

  template <typename T>  // T is derived from std::exception
  AnyException& operator=(const T& x) {
    *this = AnyException(x);
  }

  inline friend void swap(AnyException& x, AnyException& y) {
    swap(x.object_, y.object_);
  }

  const char* what() throw() {
    return object_ ? object_->what() : "empty AnyException";
  }

  operator bool() const {
    return object_;
  }

 private:
  operator int() const;  // for safe bool cast.

  class Concept : public std::exception {
   public:
    virtual Concept* Copy() const = 0;
  };

  template <class T>  // T is derived from std::exception
  class Model : public Concept {
   public:
    explicit Model(const T& x)
        : object_(x) {
    }
    Concept* Copy() const {
      return new Model(object_);
    }
    const char* what() throw() {
      return object_.what();
    }

   private:
    T object_;
  };

  Concept* object_;
};

/******************************************************************************/

// \brief BadCast is an std::bad_cast which report the \param from and \param to
// name of types for better error reporting.
//
// \note Consider moving bad cast into a typeinfo.h file.
//
// \example
// template <typaname R,
//           typename T>
// R Cast(const T& x, AnyException& error) {
//   if (!Compatible<T, R>()) {
//     error = BadCast(typeid(T).name(), typeid(R).name());
//     return R();
//   }
//   // ...
// \end_example

class BadCast : public std::bad_cast {
 public:
  BadCast(const char* from, const char* to)
      : what_("BadCast from '") {
    what_ += from;
    what_ += "' to '";
    what_ += to;
    what_ += "'.";
  }

  ~BadCast() throw() {
  }

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

 private:
  std::string what_;
};

/******************************************************************************/

// \brief SquelchError logs a warning noting the x.what().
//
// In a system using exception handling, SquelchError would become a throw.

template <typename T>  // T is derived from std::exception
void SquelchError(const T& x) {
  LOG(WARNING) << "error squelched:" << x.what();
}

/******************************************************************************/

// \brief TerminalError logs a fatal error causing the process to terminate.
//
// x.what() is noted in the log. In a system using exceptino handling,
// TerminalError would become a throw.

template <typename T>  // T is derived from std::exception
void TerminalError(const T& x) {
  LOG(FATAL) << "terminal error:" << x.what();
}

/******************************************************************************/

}  // namespace chromeos

/******************************************************************************/

#endif  // LIBCHROMEOS_CHROMEOS_EXCEPTION_H_