RCFProto
 All Classes Functions Typedefs
Throw.hpp
1 
2 //******************************************************************************
3 // RCF - Remote Call Framework
4 //
5 // Copyright (c) 2005 - 2013, Delta V Software. All rights reserved.
6 // http://www.deltavsoft.com
7 //
8 // RCF is distributed under dual licenses - closed source or GPL.
9 // Consult your particular license for conditions of use.
10 //
11 // If you have not purchased a commercial license, you are using RCF
12 // under GPL terms.
13 //
14 // Version: 2.0
15 // Contact: support <at> deltavsoft.com
16 //
17 //******************************************************************************
18 
19 #ifndef INCLUDE_UTIL_THROW_HPP
20 #define INCLUDE_UTIL_THROW_HPP
21 
22 #include <exception>
23 #include <memory>
24 
25 #include <boost/current_function.hpp>
26 
27 #include "VariableArgMacro.hpp"
28 
29 namespace RCF {
30 
31  namespace detail {
32 
33  class I_InvokeThrow
34  {
35  public:
36  virtual ~I_InvokeThrow() {}
37  virtual void invoke(const std::string &context, const std::string & args, int logName, int logLevel, const char * file, int line, const char * func) = 0;
38  };
39 
40  template<typename E>
41  class InvokeThrow : public I_InvokeThrow
42  {
43  public:
44  InvokeThrow(const E &e) : mE(e)
45  {}
46 
47  void invoke(const std::string &context, const std::string & args, int logName, int logLevel, const char * file, int line, const char * func)
48  {
49  const_cast<E &>(mE).setContext(context);
50 
51  if (RCF::LogManager::instance().isEnabled(logName, logLevel))
52  {
53  RCF::LogEntry entry(logName, logLevel, file, line, func);
54 
55  entry
56  << "Exception thrown. "
57  << mE;
58 
59  if (!args.empty())
60  {
61  entry
62  << " Values: "
63  << args;
64  }
65  }
66 
67  throw mE;
68  }
69 
70  private:
71  const E &mE;
72  };
73 
74  template<>
75  class InvokeThrow<std::runtime_error> : public I_InvokeThrow
76  {
77  public:
78  InvokeThrow(const std::runtime_error &e) : mE(e)
79  {}
80 
81  void invoke(const std::string &context, const std::string & args, int logName, int logLevel, const char * file, int line, const char * func)
82  {
83  if (RCF::LogManager::instance().isEnabled(logName, logLevel))
84  {
85  RCF::LogEntry entry(logName, logLevel, file, line, func);
86 
87  entry
88  << "Exception thrown. "
89  << mE;
90 
91  if (!args.empty())
92  {
93  entry
94  << " Values: "
95  << args;
96  }
97  }
98 
99  throw std::runtime_error( std::string(mE.what()) + ": " + context);
100  }
101 
102  private:
103  const std::runtime_error &mE;
104  };
105 
106  template<typename T>
107  const char *getTypeName(const T &t)
108  {
109  return typeid(t).name();
110  }
111 
112  }
113 
114  class ThrowFunctor : public VariableArgMacroFunctor
115  {
116  public:
117  ThrowFunctor() : mThrown(false), mLogName(0), mLogLevel(0)
118  {}
119 
120  template<typename E>
121  ThrowFunctor(const E &e, int logName, int logLevel) :
122  VariableArgMacroFunctor(),
123  mInvokeThrow(new detail::InvokeThrow<E>(e)),
124  mThrown(false),
125  mLogName(logName),
126  mLogLevel(logLevel)
127  {}
128 
129  ~ThrowFunctor()
130  {
131  // dtor gets called repeatedly by borland, believe it or not
132  if (!mThrown)
133  {
134  mThrown = true;
135 
136  std::string args(mArgs->str(), static_cast<std::size_t>(mArgs->tellp()));
137 
138  std::string context = mHeader->str();
139  context += args;
140 
141  if (!std::uncaught_exception())
142  {
143  mInvokeThrow->invoke(context, args, mLogName, mLogLevel, mFile, mLine, mFunc);
144  }
145  }
146  }
147 
148  private:
149  std::auto_ptr<detail::I_InvokeThrow> mInvokeThrow;
150  bool mThrown;
151 
152  int mLogName;
153  int mLogLevel;
154  };
155 
156 
157 #ifdef _MSC_VER
158 #pragma warning( push )
159 #pragma warning( disable : 4355 ) // warning C4355: 'this' : used in base member initializer list
160 #endif
161 
162 #if defined(__GNUC__) && (__GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ < 4))
163 #define UTIL_THROW_GCC_33_HACK (const RCF::VariableArgMacro<RCF::ThrowFunctor> &)
164 #else
165 #define UTIL_THROW_GCC_33_HACK
166 #endif
167 
168 DECLARE_VARIABLE_ARG_MACRO( UTIL_THROW, ThrowFunctor );
169 #define UTIL_THROW(e, logName, logLevel) \
170  while (true) \
171  UTIL_THROW_GCC_33_HACK \
172  RCF::VariableArgMacro<RCF::ThrowFunctor>(e, logName, logLevel) \
173  .init( \
174  "", \
175  "", \
176  __FILE__, \
177  __LINE__, \
178  BOOST_CURRENT_FUNCTION) \
179  .cast( (RCF::VariableArgMacro<RCF::ThrowFunctor> *) NULL) \
180  .UTIL_THROW_A
181 
182 
183 
184 #define UTIL_THROW_A(x) UTIL_THROW_OP(x, B)
185 #define UTIL_THROW_B(x) UTIL_THROW_OP(x, A)
186 #define UTIL_THROW_OP(x, next) UTIL_THROW_A.notify_((x), #x).UTIL_THROW_ ## next
187 
188 #ifdef _MSC_VER
189 #pragma warning( pop )
190 #endif
191 
192 #define UTIL_VERIFY(cond, e, logName, logLevel) if (cond); else UTIL_THROW(e, logName, logLevel)
193 
194 } // namespace RCF
195 
196 #endif // ! INCLUDE_UTIL_THROW_HPP