55#include < stan/math/prim/fun/get.hpp>
66#include < stan/math/prim/fun/size.hpp>
77#include < stan/math/prim/fun/value_of_rec.hpp>
8+ #include < stan/math/prim/meta/is_vector.hpp>
89#include < string>
910#include < sstream>
1011#include < vector>
@@ -13,80 +14,148 @@ namespace stan {
1314namespace math {
1415namespace internal {
1516
16- template <typename T_is_good, typename T_exception>
17- struct Checker {
18- const T_is_good& is_good;
17+ /* * Apply an error check to a container, signal failure by throwing.
18+ * Apply a predicate like is_positive to the double underlying every scalar in a
19+ * container, throw an exception if the predicate fails for any double.
20+ * @tparam F type of predicate
21+ * @tparam E type of exception thrown
22+ */
23+ template <typename F, typename E>
24+ class Checker {
25+ const F& is_good;
1926 const char * function;
2027 const char * name;
2128 const char * suffix;
2229
23- void raise_error_impl (std::stringstream& ss) { throw T_exception{ss.str ()}; }
24-
25- template <typename ... M>
26- void raise_error_impl (std::stringstream& ss, const char * message,
27- const M&... messages) {
30+ public:
31+ /* *
32+ * @param is_good predicate to check, must accept doubles and produce bools
33+ * @param function function name (for error messages)
34+ * @param name variable name (for error messages)
35+ * @param suffix message to print at end of error message
36+ */
37+ Checker (const F& is_good, const char * function, const char * name,
38+ const char * suffix)
39+ : is_good(is_good), function(function), name(name), suffix(suffix) {}
40+
41+ /* *
42+ * Throw an exception of type `E`.
43+ * The error message is the string inside the provided stringstream.
44+ * @param ss stringstream containing error message
45+ * @throws `E`
46+ */
47+ void raise_error_ss (std::stringstream& ss) { throw E{ss.str ()}; }
48+
49+ /* *
50+ * Throw an exception of type `E`.
51+ * The error message is the concatenation of the string inside the provided
52+ * stringstream with all the provided messages.
53+ * @tparam M types of first message
54+ * @tparam Ms types of other messages
55+ * @param ss stringstream to accumulate error message in.
56+ * @param message a message to append to `ss`
57+ * @param messages more messages to append
58+ * @throws `E`
59+ */
60+ template <typename M, typename ... Ms>
61+ void raise_error_ss (std::stringstream& ss, const M& message,
62+ const Ms&... messages) {
2863 ss << message;
29- raise_error_impl (ss, messages...);
30- }
31-
32- template <typename ... M>
33- void raise_error_impl (std::stringstream& ss, double value_of_x,
34- const M&... messages) {
35- ss << value_of_x;
36- raise_error_impl (ss, messages...);
64+ raise_error_ss (ss, messages...);
3765 }
3866
39- template < typename ... M>
40- void raise_error_impl (std::stringstream& ss, size_t index,
41- const M&... messages) {
42- ss << index + 1 ;
43- raise_error_impl (ss, messages...);
44- }
45-
46- template <typename ... M >
47- void raise_error (const M &... messages) {
67+ /* *
68+ * Throw an exception of type `E`.
69+ * The error message is the concatenation of the provided messages.
70+ * @tparam Ms types of messages
71+ * @param messages a list of messages
72+ * @throws `E`
73+ */
74+ template <typename ... Ms >
75+ void raise_error (const Ms &... messages) {
4876 std::stringstream ss{};
49- raise_error_impl (ss, messages...);
77+ raise_error_ss (ss, messages...);
5078 }
5179
52- template <typename T, typename = require_stan_scalar_t <T>,
53- typename ... T_indices>
54- void check (const T& x, T_indices... indices) {
80+ /* *
81+ * Check the scalar.
82+ * @tparam T type of scalar
83+ * @tparam Ms types of messages
84+ * @param x scalar
85+ * @param messages a list of messages to append to the error message
86+ * @throws `E` if the scalar fails the error check
87+ */
88+ template <typename T, typename = require_stan_scalar_t <T>, typename ... Ms>
89+ void check (const T& x, Ms... messages) {
5590 double xd = value_of_rec (x);
5691 if (!is_good (xd))
57- raise_error (function, " : " , name, indices ..., " is " , xd, suffix);
92+ raise_error (function, " : " , name, messages ..., " is " , xd, suffix);
5893 }
5994
60- template <typename T, typename = require_eigen_vector_t <T>, typename = void ,
61- typename ... T_indices>
62- void check (const T& x, T_indices... indices) {
95+ /* *
96+ * Check all the scalars inside the vector.
97+ * @tparam T type of vector
98+ * @tparam Ms types of messages
99+ * @param x vector
100+ * @param messages a list of messages to append to the error message
101+ * @throws `E` if any of the scalars fail the error check
102+ */
103+ template <typename T, typename = require_vector_t <T>, typename = void ,
104+ typename ... Ms>
105+ void check (const T& x, Ms... messages) {
63106 for (size_t i = 0 ; i < stan::math::size (x); ++i)
64- check (x (i), indices ..., " [" , i, " ]" );
107+ check (x[i], messages ..., " [" , i + 1 , " ]" );
65108 }
66109
67- template <typename T, typename ... T_indices>
68- void check (const std::vector<T>& x, T_indices... indices) {
69- for (size_t i = 0 ; i < stan::math::size (x); ++i)
70- check (x[i], indices..., " [" , i, " ]" );
71- }
72-
73- template <typename T, typename ... T_indices>
74- void check (const Eigen::DenseBase<T>& x, T_indices... indices) {
110+ /* *
111+ * Check all the scalars inside the matrix.
112+ * @tparam Derived type of matrix
113+ * @tparam Ms types of messages
114+ * @param x matrix
115+ * @param messages a list of messages to append to the error message
116+ * @throws `E` if any of the scalars fail the error check
117+ */
118+ template <typename Derived, typename ... Ms>
119+ void check (const Eigen::DenseBase<Derived>& x, Ms... messages) {
75120 for (size_t n = 0 ; n < x.cols (); ++n)
76121 for (size_t m = 0 ; m < x.rows (); ++m)
77- check (x (m, n), indices ..., " [row=" , m, " , col=" , n, " ]" );
122+ check (x (m, n), messages ..., " [row=" , m + 1 , " , col=" , n + 1 , " ]" );
78123 }
79- };
80-
81- template <typename T_is_good>
82- struct Iser {
83- const T_is_good& is_good;
124+ }; // namespace internal
84125
126+ /* * Apply an error check to a container, signal failure with `false`.
127+ * Apply a predicate like is_positive to the double underlying every scalar in a
128+ * container, producing true if the predicate holds everywhere and `false` if it
129+ * fails anywhere.
130+ * @tparam F type of predicate
131+ */
132+ template <typename F>
133+ class Iser {
134+ const F& is_good;
135+
136+ public:
137+ /* *
138+ * @param is_good predicate to check, must accept doubles and produce bools
139+ */
140+ explicit Iser (const F& is_good) : is_good(is_good) {}
141+
142+ /* *
143+ * Check the scalar.
144+ * @tparam T type of scalar
145+ * @param x scalar
146+ * @return `false` if the scalar fails the error check
147+ */
85148 template <typename T, typename = require_stan_scalar_t <T>>
86149 bool is (const T& x) {
87150 return is_good (value_of_rec (x));
88151 }
89152
153+ /* *
154+ * Check all the scalars inside the container.
155+ * @tparam T type of scalar
156+ * @param x container
157+ * @return `false` if any of the scalars fail the error check
158+ */
90159 template <typename T, typename = require_not_stan_scalar_t <T>,
91160 typename = void >
92161 bool is (const T& x) {
@@ -100,35 +169,42 @@ struct Iser {
100169} // namespace internal
101170
102171/* *
103- * Check that the predicate holds for the value of x, working elementwise on
104- * containers. If x is a container, check each element inside x, recursively.
105- * @tparam T_is_good type of is_good predicate
106- * @tparam T_x type of x
172+ * Check that the predicate holds for the value of `x`, working elementwise on
173+ * containers. If `x` is a scalar, check the double underlying the scalar. If
174+ * `x` is a container, check each element inside `x`, recursively.
175+ * @tparam F type of predicate
176+ * @tparam T type of `x`
107177 * @param is_good predicate to check, must accept doubles and produce bools
108178 * @param function function name (for error messages)
109179 * @param name variable name (for error messages)
110180 * @param x variable to check, can be a scalar, a container of scalars, a
111181 * container of containers of scalars, etc
112182 * @param suffix message to print at end of error message
113- * @throw <code> std::domain_error</code> if is_good returns false for the value
114- * of any element in x the predicate
183+ * @throws ` std::domain_error` if ` is_good` returns ` false` for the value
184+ * of any element in `x`
115185 */
116- template <typename T_is_good , typename T_x >
117- inline void elementwise_check (const T_is_good & is_good, const char * function,
118- const char * name, const T_x & x,
186+ template <typename F , typename T >
187+ inline void elementwise_check (const F & is_good, const char * function,
188+ const char * name, const T & x,
119189 const char * suffix) {
120- internal::Checker<T_is_good, std::domain_error>{is_good, function, name,
121- suffix}
190+ internal::Checker<F, std::domain_error>{is_good, function, name, suffix}
122191 .check (x);
123192}
124193
125194/* *
126- * Like elementwise_check, but indicate failure by returning false instead of
127- * by throwing.
195+ * Check that the predicate holds for the value of `x`, working elementwise on
196+ * containers. If `x` is a scalar, check the double underlying the scalar. If
197+ * `x` is a container, check each element inside `x`, recursively.
198+ * @tparam F type of predicate
199+ * @tparam T type of `x`
200+ * @param is_good predicate to check, must accept doubles and produce bools
201+ * @param x variable to check, can be a scalar, a container of scalars, a
202+ * container of containers of scalars, etc
203+ * @return `false` if any of the scalars fail the error check
128204 */
129- template <typename T_is_good , typename T_x >
130- inline bool elementwise_is (const T_is_good & is_good, const T_x & x) {
131- return internal::Iser<T_is_good >{is_good}.is (x);
205+ template <typename F , typename T >
206+ inline bool elementwise_is (const F & is_good, const T & x) {
207+ return internal::Iser<F >{is_good}.is (x);
132208}
133209
134210} // namespace math
0 commit comments