Skip to content

Commit 25c2369

Browse files
authored
Merge pull request #676 from coatless/feature/improved-exception-messages-v2
Improved exception infrastructure
2 parents 052089b + b022854 commit 25c2369

File tree

6 files changed

+313
-138
lines changed

6 files changed

+313
-138
lines changed

ChangeLog

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
2017-04-17 James J Balamuta <[email protected]>
2+
3+
* inst/include/Rcpp/Rcpp/exceptions/cpp11/exceptions.h: Removed
4+
semicolons from RCPP_ADVANCED_EXCEPTION_CLASS to quiet 'extra ;' -Wpedantic
5+
6+
* inst/include/Rcpp/exceptions.h: Modified exceptions macros to support
7+
a default string and removed generated stop, warning from file.
8+
* inst/include/Rcpp/Rcpp/exceptions/cpp98/exceptions.h: Contains
9+
generated RCPP_ADVANCED_EXCEPTION_CLASS macro, stop & warning.
10+
* inst/include/Rcpp/Rcpp/exceptions/cpp11/exceptions.h: idem but
11+
for variadic versions.
12+
* inst/include/Rcpp/utils/tinyformat.h: Enabled ability to use variadic
13+
tinyformat function if c++11 is detected.
14+
115
2017-04-14 James J Balamuta <[email protected]>
216

317
* inst/include/Rcpp/utils/tinyformat.h: Refreshed tinyformat.h against

inst/NEWS.Rd

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@
1313
now suppressed (Kirill Mueller in \ghpr{670}, \ghpr{671} and \ghpr{672}).
1414
\item Refreshed the included \code{tinyformat} template library
1515
(James Balamuta in \ghpr{674} addressing \ghit{673}).
16+
\item Added \code{printf}-like syntax support for exception classes and
17+
variadic templating for \code{Rcpp::stop} and \code{Rcpp::warning}
18+
(James Balamuta in \ghpr{676}).
19+
\item Exception messages have been rewritten to provide additional
20+
information. (James Balamuta in \ghpr{676}, ?? addressing \ghit{184}).
1621
}
1722
\item Changes in Rcpp Documentation:
1823
\itemize{

inst/include/Rcpp/exceptions.h

Lines changed: 56 additions & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,37 @@ namespace Rcpp {
9797
file_io_error("file already exists", file) {} // #nocov end
9898
};
9999

100+
// Variadic / code generated version of the warning and stop functions
101+
// can be found within the respective C++11 or C++98 exceptions.h
102+
// included below
103+
inline void warning(const std::string& message) { // #nocov start
104+
Rf_warning(message.c_str());
105+
} // #nocov end
106+
107+
inline void NORET stop(const std::string& message) { // #nocov start
108+
throw Rcpp::exception(message.c_str());
109+
} // #nocov end
110+
111+
} // namespace Rcpp
112+
113+
114+
// Determine whether to use variadic templated RCPP_ADVANCED_EXCEPTION_CLASS,
115+
// warning, and stop exception functions or to use the generated argument macro
116+
// based on whether the compiler supports c++11 or not.
117+
#if __cplusplus >= 201103L
118+
# include <Rcpp/exceptions/cpp11/exceptions.h>
119+
#else
120+
# include <Rcpp/exceptions/cpp98/exceptions.h>
121+
#endif
122+
123+
namespace Rcpp {
124+
100125
#define RCPP_EXCEPTION_CLASS(__CLASS__,__WHAT__) \
101126
class __CLASS__ : public std::exception{ \
102127
public: \
103-
__CLASS__( const std::string& message ) throw() : message( __WHAT__ ){} ; \
128+
__CLASS__( ) throw() : message( std::string(__WHAT__) + "." ){} ; \
129+
__CLASS__( const std::string& message ) throw() : \
130+
message( std::string(__WHAT__) + ": " + message + "." ){} ; \
104131
virtual ~__CLASS__() throw(){} ; \
105132
virtual const char* what() const throw() { return message.c_str() ; } \
106133
private: \
@@ -115,30 +142,35 @@ namespace Rcpp {
115142
virtual const char* what() const throw() { return __MESSAGE__ ; } \
116143
} ;
117144

118-
RCPP_SIMPLE_EXCEPTION_CLASS(not_a_matrix, "not a matrix")
119-
RCPP_SIMPLE_EXCEPTION_CLASS(index_out_of_bounds, "index out of bounds")
120-
RCPP_SIMPLE_EXCEPTION_CLASS(parse_error, "parse error")
121-
RCPP_SIMPLE_EXCEPTION_CLASS(not_s4, "not an S4 object") // #nocov start
122-
RCPP_SIMPLE_EXCEPTION_CLASS(not_reference, "not an S4 object of a reference class")
123-
RCPP_SIMPLE_EXCEPTION_CLASS(not_initialized, "C++ object not initialized (missing default constructor?)")
124-
RCPP_SIMPLE_EXCEPTION_CLASS(no_such_slot, "no such slot")
125-
RCPP_SIMPLE_EXCEPTION_CLASS(no_such_field, "no such field")
126-
RCPP_SIMPLE_EXCEPTION_CLASS(not_a_closure, "not a closure")
127-
RCPP_SIMPLE_EXCEPTION_CLASS(no_such_function, "no such function")
128-
RCPP_SIMPLE_EXCEPTION_CLASS(unevaluated_promise, "promise not yet evaluated")
129-
130-
RCPP_EXCEPTION_CLASS(not_compatible, message )
131-
RCPP_EXCEPTION_CLASS(S4_creation_error, std::string("error creating object of S4 class : ") + message )
132-
RCPP_EXCEPTION_CLASS(reference_creation_error, std::string("error creating object of reference class : ") + message )
133-
RCPP_EXCEPTION_CLASS(no_such_binding, std::string("no such binding : '") + message + "'" )
134-
RCPP_EXCEPTION_CLASS(binding_not_found, std::string("binding not found: '") + message + "'" )
135-
RCPP_EXCEPTION_CLASS(binding_is_locked, std::string("binding is locked: '") + message + "'" )
136-
RCPP_EXCEPTION_CLASS(no_such_namespace, std::string("no such namespace: '") + message + "'" )
137-
RCPP_EXCEPTION_CLASS(function_not_exported, std::string("function not exported: ") + message)
138-
RCPP_EXCEPTION_CLASS(eval_error, message ) // #nocov end
145+
RCPP_SIMPLE_EXCEPTION_CLASS(not_a_matrix, "Not a matrix.") // #nocov start
146+
RCPP_SIMPLE_EXCEPTION_CLASS(parse_error, "Parse error.")
147+
RCPP_SIMPLE_EXCEPTION_CLASS(not_s4, "Not an S4 object.")
148+
RCPP_SIMPLE_EXCEPTION_CLASS(not_reference, "Not an S4 object of a reference class.")
149+
RCPP_SIMPLE_EXCEPTION_CLASS(not_initialized, "C++ object not initialized. (Missing default constructor?)")
150+
RCPP_SIMPLE_EXCEPTION_CLASS(no_such_field, "No such field.") // not used internally
151+
RCPP_SIMPLE_EXCEPTION_CLASS(no_such_function, "No such function.")
152+
RCPP_SIMPLE_EXCEPTION_CLASS(unevaluated_promise, "Promise not yet evaluated.")
153+
154+
// Promoted
155+
RCPP_EXCEPTION_CLASS(no_such_slot, "No such slot")
156+
RCPP_EXCEPTION_CLASS(not_a_closure, "Not a closure")
157+
158+
RCPP_EXCEPTION_CLASS(S4_creation_error, "Error creating object of S4 class")
159+
RCPP_EXCEPTION_CLASS(reference_creation_error, "Error creating object of reference class") // not used internally
160+
RCPP_EXCEPTION_CLASS(no_such_binding, "No such binding")
161+
RCPP_EXCEPTION_CLASS(binding_not_found, "Binding not found")
162+
RCPP_EXCEPTION_CLASS(binding_is_locked, "Binding is locked")
163+
RCPP_EXCEPTION_CLASS(no_such_namespace, "No such namespace")
164+
RCPP_EXCEPTION_CLASS(function_not_exported, "Function not exported")
165+
RCPP_EXCEPTION_CLASS(eval_error, "Evaluation error") // #nocov end
166+
167+
// Promoted
168+
RCPP_ADVANCED_EXCEPTION_CLASS(not_compatible, "Not compatible" )
169+
RCPP_ADVANCED_EXCEPTION_CLASS(index_out_of_bounds, "Index is out of bounds")
139170

140-
#undef RCPP_EXCEPTION_CLASS
141171
#undef RCPP_SIMPLE_EXCEPTION_CLASS
172+
#undef RCPP_EXCEPTION_CLASS
173+
#undef RCPP_ADVANCED_EXCEPTION_CLASS
142174

143175

144176
namespace internal {
@@ -166,7 +198,7 @@ namespace internal {
166198
nth(expr, 2) == identity_fun &&
167199
nth(expr, 3) == identity_fun;
168200
}
169-
}
201+
} // namespace internal
170202

171203
} // namespace Rcpp
172204

@@ -281,117 +313,6 @@ inline SEXP exception_to_try_error( const std::exception& ex){
281313
std::string demangle( const std::string& name) ;
282314
#define DEMANGLE(__TYPE__) demangle( typeid(__TYPE__).name() ).c_str()
283315

284-
namespace Rcpp{
285-
286-
inline void warning(const std::string& message) {
287-
Rf_warning(message.c_str());
288-
}
289-
290-
template <typename T1>
291-
inline void warning(const char* fmt, const T1& arg1) {
292-
Rf_warning( tfm::format(fmt, arg1 ).c_str() );
293-
}
294-
295-
template <typename T1, typename T2>
296-
inline void warning(const char* fmt, const T1& arg1, const T2& arg2) {
297-
Rf_warning( tfm::format(fmt, arg1, arg2 ).c_str() );
298-
}
299-
300-
template <typename T1, typename T2, typename T3>
301-
inline void warning(const char* fmt, const T1& arg1, const T2& arg2, const T3& arg3) {
302-
Rf_warning( tfm::format(fmt, arg1, arg2, arg3).c_str() );
303-
}
304-
305-
template <typename T1, typename T2, typename T3, typename T4>
306-
inline void warning(const char* fmt, const T1& arg1, const T2& arg2, const T3& arg3, const T4& arg4) {
307-
Rf_warning( tfm::format(fmt, arg1, arg2, arg3, arg4).c_str() );
308-
}
309-
310-
template <typename T1, typename T2, typename T3, typename T4, typename T5>
311-
inline void warning(const char* fmt, const T1& arg1, const T2& arg2, const T3& arg3, const T4& arg4, const T5& arg5) {
312-
Rf_warning( tfm::format(fmt, arg1, arg2, arg3, arg4, arg5).c_str() );
313-
}
314-
315-
template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
316-
inline void warning(const char* fmt, const T1& arg1, const T2& arg2, const T3& arg3, const T4& arg4, const T5& arg5, const T6& arg6) {
317-
Rf_warning( tfm::format(fmt, arg1, arg2, arg3, arg4, arg5, arg6).c_str() );
318-
}
319-
320-
template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
321-
inline void warning(const char* fmt, const T1& arg1, const T2& arg2, const T3& arg3, const T4& arg4, const T5& arg5, const T6& arg6, const T7& arg7) {
322-
Rf_warning( tfm::format(fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7).c_str() );
323-
}
324-
325-
template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8>
326-
inline void warning(const char* fmt, const T1& arg1, const T2& arg2, const T3& arg3, const T4& arg4, const T5& arg5, const T6& arg6, const T7& arg7, const T8& arg8) {
327-
Rf_warning( tfm::format(fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8).c_str() );
328-
}
329-
330-
template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9>
331-
inline void warning(const char* fmt, const T1& arg1, const T2& arg2, const T3& arg3, const T4& arg4, const T5& arg5, const T6& arg6, const T7& arg7, const T8& arg8, const T9& arg9) {
332-
Rf_warning( tfm::format(fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9).c_str() );
333-
}
334-
335-
template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10>
336-
inline void warning(const char* fmt, const T1& arg1, const T2& arg2, const T3& arg3, const T4& arg4, const T5& arg5, const T6& arg6, const T7& arg7, const T8& arg8, const T9& arg9, const T10& arg10) {
337-
Rf_warning( tfm::format(fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10).c_str() );
338-
}
339-
340-
inline void NORET stop(const std::string& message) { // #nocov start
341-
throw Rcpp::exception(message.c_str());
342-
} // #nocov end
343-
344-
template <typename T1>
345-
inline void NORET stop(const char* fmt, const T1& arg1) {
346-
throw Rcpp::exception( tfm::format(fmt, arg1 ).c_str() );
347-
}
348-
349-
template <typename T1, typename T2>
350-
inline void NORET stop(const char* fmt, const T1& arg1, const T2& arg2) {
351-
throw Rcpp::exception( tfm::format(fmt, arg1, arg2 ).c_str() );
352-
}
353-
354-
template <typename T1, typename T2, typename T3>
355-
inline void NORET stop(const char* fmt, const T1& arg1, const T2& arg2, const T3& arg3) {
356-
throw Rcpp::exception( tfm::format(fmt, arg1, arg2, arg3).c_str() );
357-
}
358-
359-
template <typename T1, typename T2, typename T3, typename T4>
360-
inline void NORET stop(const char* fmt, const T1& arg1, const T2& arg2, const T3& arg3, const T4& arg4) {
361-
throw Rcpp::exception( tfm::format(fmt, arg1, arg2, arg3, arg4).c_str() );
362-
}
363-
364-
template <typename T1, typename T2, typename T3, typename T4, typename T5>
365-
inline void NORET stop(const char* fmt, const T1& arg1, const T2& arg2, const T3& arg3, const T4& arg4, const T5& arg5) {
366-
throw Rcpp::exception( tfm::format(fmt, arg1, arg2, arg3, arg4, arg5).c_str() );
367-
}
368-
369-
template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
370-
inline void NORET stop(const char* fmt, const T1& arg1, const T2& arg2, const T3& arg3, const T4& arg4, const T5& arg5, const T6& arg6) {
371-
throw Rcpp::exception( tfm::format(fmt, arg1, arg2, arg3, arg4, arg5, arg6).c_str() );
372-
}
373-
374-
template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
375-
inline void NORET stop(const char* fmt, const T1& arg1, const T2& arg2, const T3& arg3, const T4& arg4, const T5& arg5, const T6& arg6, const T7& arg7) {
376-
throw Rcpp::exception( tfm::format(fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7).c_str() );
377-
}
378-
379-
template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8>
380-
inline void NORET stop(const char* fmt, const T1& arg1, const T2& arg2, const T3& arg3, const T4& arg4, const T5& arg5, const T6& arg6, const T7& arg7, const T8& arg8) {
381-
throw Rcpp::exception( tfm::format(fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8).c_str() );
382-
}
383-
384-
template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9>
385-
inline void NORET stop(const char* fmt, const T1& arg1, const T2& arg2, const T3& arg3, const T4& arg4, const T5& arg5, const T6& arg6, const T7& arg7, const T8& arg8, const T9& arg9) {
386-
throw Rcpp::exception( tfm::format(fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9).c_str() );
387-
}
388-
389-
template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10>
390-
inline void NORET stop(const char* fmt, const T1& arg1, const T2& arg2, const T3& arg3, const T4& arg4, const T5& arg5, const T6& arg6, const T7& arg7, const T8& arg8, const T9& arg9, const T10& arg10) {
391-
throw Rcpp::exception( tfm::format(fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10).c_str() );
392-
}
393-
}
394-
395316
inline void forward_exception_to_r(const std::exception& ex){
396317
SEXP stop_sym = Rf_install( "stop" ) ;
397318
Rcpp::Shield<SEXP> condition( exception_to_r_condition(ex) );
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// -*- mode: C++; c-indent-level: 4; c-basic-offset: 4; indent-tabs-mode: nil; -*-
2+
//
3+
// exceptions.h: Rcpp R/C++ interface class library -- exceptions
4+
//
5+
// Copyright (C) 2017 James J Balamuta
6+
//
7+
// This file is part of Rcpp.
8+
//
9+
// Rcpp is free software: you can redistribute it and/or modify it
10+
// under the terms of the GNU General Public License as published by
11+
// the Free Software Foundation, either version 2 of the License, or
12+
// (at your option) any later version.
13+
//
14+
// Rcpp is distributed in the hope that it will be useful, but
15+
// WITHOUT ANY WARRANTY; without even the implied warranty of
16+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17+
// GNU General Public License for more details.
18+
//
19+
// You should have received a copy of the GNU General Public License
20+
// along with Rcpp. If not, see <http://www.gnu.org/licenses/>.
21+
22+
#ifndef Rcpp__exceptionscpp11__h
23+
#define Rcpp__exceptionscpp11__h
24+
25+
// Required for std::forward
26+
#include <utility>
27+
28+
namespace Rcpp {
29+
30+
#define RCPP_ADVANCED_EXCEPTION_CLASS(__CLASS__, __WHAT__) \
31+
class __CLASS__ : public std::exception { \
32+
public: \
33+
__CLASS__( ) throw() : message( std::string(__WHAT__) + "." ){} \
34+
__CLASS__( const std::string& message ) throw() : \
35+
message( std::string(__WHAT__) + ": " + message + "."){} \
36+
template <typename... Args> \
37+
__CLASS__( const char* fmt, Args&&... args ) throw() : \
38+
message( tfm::format(fmt, std::forward<Args>(args)... ) ){} \
39+
virtual ~__CLASS__() throw(){} \
40+
virtual const char* what() const throw() { return message.c_str(); } \
41+
private: \
42+
std::string message; \
43+
};
44+
45+
template <typename... Args>
46+
inline void warning(const char* fmt, Args&&... args ) {
47+
Rf_warning( tfm::format(fmt, std::forward<Args>(args)... ).c_str() );
48+
}
49+
50+
template <typename... Args>
51+
inline void NORET stop(const char* fmt, Args&&... args) {
52+
throw Rcpp::exception( tfm::format(fmt, std::forward<Args>(args)... ).c_str() );
53+
}
54+
55+
} // namespace Rcpp
56+
#endif

0 commit comments

Comments
 (0)