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 util {
30 
31  namespace detail {
32 
33  inline bool uncaught_exception()
34  {
35  return std::uncaught_exception();
36  }
37 
38  class I_InvokeThrow
39  {
40  public:
41  virtual ~I_InvokeThrow() {}
42  virtual void invoke(const std::string &context, const std::string & args, int logName, int logLevel, const char * file, int line, const char * func) = 0;
43  };
44 
45  template<typename E>
46  class InvokeThrow : public I_InvokeThrow
47  {
48  public:
49  InvokeThrow(const E &e) : mE(e)
50  {}
51 
52  void invoke(const std::string &context, const std::string & args, int logName, int logLevel, const char * file, int line, const char * func)
53  {
54  const_cast<E &>(mE).setContext(context);
55 
56  if (RCF::LogManager::instance().isEnabled(logName, logLevel))
57  {
58  RCF::LogEntry entry(logName, logLevel, file, line, func);
59 
60  entry
61  << "Exception thrown. "
62  << mE;
63 
64  if (!args.empty())
65  {
66  entry
67  << " Values: "
68  << args;
69  }
70  }
71 
72  throw mE;
73  }
74 
75  private:
76  const E &mE;
77  };
78 
79  template<>
80  class InvokeThrow<std::runtime_error> : public I_InvokeThrow
81  {
82  public:
83  InvokeThrow(const std::runtime_error &e) : mE(e)
84  {}
85 
86  void invoke(const std::string &context, const std::string & args, int logName, int logLevel, const char * file, int line, const char * func)
87  {
88  if (RCF::LogManager::instance().isEnabled(logName, logLevel))
89  {
90  RCF::LogEntry entry(logName, logLevel, file, line, func);
91 
92  entry
93  << "Exception thrown. "
94  << mE;
95 
96  if (!args.empty())
97  {
98  entry
99  << " Values: "
100  << args;
101  }
102  }
103 
104  throw std::runtime_error( std::string(mE.what()) + ": " + context);
105  }
106 
107  private:
108  const std::runtime_error &mE;
109  };
110 
111  template<typename T>
112  const char *getTypeName(const T &t)
113  {
114  return typeid(t).name();
115  }
116 
117  }
118 
119  class ThrowFunctor : public VariableArgMacroFunctor
120  {
121  public:
122  ThrowFunctor() : mThrown(false), mLogName(0), mLogLevel(0)
123  {}
124 
125  template<typename E>
126  ThrowFunctor(const E &e, int logName, int logLevel) :
127  VariableArgMacroFunctor(),
128  mInvokeThrow(new detail::InvokeThrow<E>(e)),
129  mThrown(false),
130  mLogName(logName),
131  mLogLevel(logLevel)
132  {}
133 
134  ~ThrowFunctor()
135  {
136  // dtor gets called repeatedly by borland, believe it or not
137  if (!mThrown)
138  {
139  mThrown = true;
140 
141  std::string args(mArgs->str(), static_cast<std::size_t>(mArgs->tellp()));
142 
143  std::string context = mHeader->str();
144  context += args;
145 
146  if (!util::detail::uncaught_exception())
147  {
148  mInvokeThrow->invoke(context, args, mLogName, mLogLevel, mFile, mLine, mFunc);
149  }
150  }
151  }
152 
153  private:
154  std::auto_ptr<detail::I_InvokeThrow> mInvokeThrow;
155  bool mThrown;
156 
157  int mLogName;
158  int mLogLevel;
159  };
160 
161 
162 #ifdef _MSC_VER
163 #pragma warning( push )
164 #pragma warning( disable : 4355 ) // warning C4355: 'this' : used in base member initializer list
165 #endif
166 
167 #if defined(__GNUC__) && (__GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ < 4))
168 #define UTIL_THROW_GCC_33_HACK (const util::VariableArgMacro<util::ThrowFunctor> &)
169 #else
170 #define UTIL_THROW_GCC_33_HACK
171 #endif
172 
173 DECLARE_VARIABLE_ARG_MACRO( UTIL_THROW, ThrowFunctor );
174 #define UTIL_THROW(e, logName, logLevel) \
175  while (true) \
176  UTIL_THROW_GCC_33_HACK \
177  util::VariableArgMacro<util::ThrowFunctor>(e, logName, logLevel) \
178  .init( \
179  "", \
180  "", \
181  __FILE__, \
182  __LINE__, \
183  BOOST_CURRENT_FUNCTION) \
184  .cast( (util::VariableArgMacro<util::ThrowFunctor> *) NULL) \
185  .UTIL_THROW_A
186 
187 
188 
189 #define UTIL_THROW_A(x) UTIL_THROW_OP(x, B)
190 #define UTIL_THROW_B(x) UTIL_THROW_OP(x, A)
191 #define UTIL_THROW_OP(x, next) UTIL_THROW_A.notify_((x), #x).UTIL_THROW_ ## next
192 
193 #ifdef _MSC_VER
194 #pragma warning( pop )
195 #endif
196 
197 #define UTIL_VERIFY(cond, e, logName, logLevel) if (cond); else UTIL_THROW(e, logName, logLevel)
198 
199 } // namespace util
200 
201 #endif // ! INCLUDE_UTIL_THROW_HPP