forked from Abc-Arbitrage/Disruptor-cpp
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathExceptionBase.h
More file actions
204 lines (169 loc) · 6.46 KB
/
ExceptionBase.h
File metadata and controls
204 lines (169 loc) · 6.46 KB
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
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
#pragma once
#include <exception>
#include <sstream>
#include <type_traits>
#include "Disruptor/Pragmas.h"
#define DISRUPTOR_THROW(DisruptorExceptionType, disruptorMessage) \
DISRUPTOR_PRAGMA_PUSH \
DISRUPTOR_PRAGMA_IGNORE_CONDITIONAL_EXPRESSION_IS_CONSTANT \
do \
{ \
std::stringstream disruptorStream; \
disruptorStream << disruptorMessage; \
throw DisruptorExceptionType(disruptorStream.str(), __FUNCTION__, __FILE__, __LINE__); \
} while (0); \
DISRUPTOR_PRAGMA_POP
#define DISRUPTOR_DECLARE_EXCEPTION(DisruptorExceptionType) \
class DisruptorExceptionType : public ::Disruptor::ExceptionBase< DisruptorExceptionType > \
{ \
public: \
explicit DisruptorExceptionType(std::string message = std::string(), \
std::string function = std::string(), \
std::string file = std::string(), \
int line = -1) \
: ExceptionBase< DisruptorExceptionType >(std::move(message), std::move(function), std::move(file), line) \
{ \
} \
\
explicit DisruptorExceptionType(std::string message, \
const std::exception& innerException, \
std::string function = std::string(), \
std::string file = std::string(), \
int line = -1) \
: ExceptionBase< DisruptorExceptionType >(std::move(message), innerException, std::move(function), std::move(file), line) \
{ \
} \
\
explicit DisruptorExceptionType(const std::exception& innerException, \
std::string function = std::string(), \
std::string file = std::string(), \
int line = -1) \
: ExceptionBase< DisruptorExceptionType >(innerException, std::move(function), std::move(file), line) \
{ \
} \
}
namespace Disruptor
{
template <class TException>
class ExceptionBase : public std::exception
{
public:
explicit ExceptionBase(std::string message = std::string(),
std::string function = std::string(),
std::string file = std::string(),
int line = -1)
: m_message(std::move(message))
, m_innerException(emptyException())
, m_function(std::move(function))
, m_file(std::move(file))
, m_line(line)
, m_wholeMessage()
{
}
explicit ExceptionBase(const std::exception& innerException,
std::string function = std::string(),
std::string file = std::string(),
int line = -1)
: m_message()
, m_innerException(innerException)
, m_function(std::move(function))
, m_file(std::move(file))
, m_line(line)
, m_wholeMessage()
{
}
explicit ExceptionBase(std::string message,
const std::exception& innerException,
std::string function = std::string(),
std::string file = std::string(),
int line = -1)
: m_message(std::move(message))
, m_innerException(innerException)
, m_function(std::move(function))
, m_file(std::move(file))
, m_line(line)
, m_wholeMessage()
{
}
// theoricaly not necessary but g++ complains
virtual ~ExceptionBase() throw() {}
const char* what() const throw() override
{
if (m_wholeMessage.empty())
formatWholeMessage();
return m_wholeMessage.c_str();
}
const std::string& message() const { return m_message; }
const std::string& function() const { return m_function; }
const std::string& file() const { return m_file; }
int line() const { return m_line; }
const std::exception& innerException() const { return m_innerException; }
// this stuff provides cool writing such as `throw Exception() << "Holy shit! what's wrong with id: " << id`;
template <class T>
TException& operator<<(const T& rhs)
{
std::stringstream stream;
stream << rhs;
m_message += stream.str();
return static_cast< TException& >(*this);
}
protected:
bool hasThrowLocationInformation() const
{
return m_line != -1;
}
void formatWholeMessage() const
{
std::stringstream stream;
stream << m_message;
if (hasThrowLocationInformation())
{
stream << " - ";
appendThrowLocationInformation(stream);
}
auto&& derivedMessage = getDerivedExceptionMessage();
if (derivedMessage.size())
stream << " - " << derivedMessage;
m_wholeMessage = stream.str();
}
// let a chance for a derived exception to provide additional information, such as an api error string.
virtual std::string getDerivedExceptionMessage() const
{
return std::string();
}
void appendThrowLocationInformation(std::stringstream& stream) const
{
stream << "Throw location: " << m_function << " in " << m_file << "(" << m_line << ")";
}
static const std::exception& emptyException()
{
static std::exception result;
return result;
}
private:
std::string m_message;
const std::exception& m_innerException;
std::string m_function;
std::string m_file;
int m_line;
mutable std::string m_wholeMessage;
};
template <class TException>
inline std::string toString(const ExceptionBase< TException >& ex)
{
std::stringstream stream;
stream << ex;
return stream.str();
}
} // namespace Disruptor
#include <ostream>
namespace std
{
template <class TException>
inline ostream& operator<<(ostream& os, const Disruptor::ExceptionBase< TException >& ex)
{
return os
<< ex.message()
<< ", InnerException: " << ex.innerException().what();
}
} // namespace std