xtensor
 
Loading...
Searching...
No Matches
xexception.hpp
1/***************************************************************************
2 * Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht *
3 * Copyright (c) QuantStack *
4 * *
5 * Distributed under the terms of the BSD 3-Clause License. *
6 * *
7 * The full license is in the file LICENSE, distributed with this software. *
8 ****************************************************************************/
9
10#ifndef XTENSOR_EXCEPTION_HPP
11#define XTENSOR_EXCEPTION_HPP
12
13#include <iterator>
14#include <sstream>
15#include <stdexcept>
16#include <string>
17#include <type_traits>
18
19#include <xtl/xcompare.hpp>
20#include <xtl/xsequence.hpp>
21#include <xtl/xspan_impl.hpp>
22
23#include "../core/xtensor_config.hpp"
24
25#ifdef __GNUC__
26#define XTENSOR_UNUSED_VARIABLE __attribute__((unused))
27#else
28#define XTENSOR_UNUSED_VARIABLE
29#endif
30
31namespace xt
32{
34 {
35 };
36
37 namespace
38 {
39 missing_type XTENSOR_UNUSED_VARIABLE missing;
40 }
41
42 namespace detail
43 {
44 template <class... Args>
45 struct last_type_is_missing_impl
46 : std::is_same<missing_type, xtl::mpl::back_t<xtl::mpl::vector<Args...>>>
47 {
48 };
49
50 template <>
51 struct last_type_is_missing_impl<> : std::false_type
52 {
53 };
54
55 template <class... Args>
56 constexpr bool last_type_is_missing = last_type_is_missing_impl<Args...>::value;
57 }
58
59 /*******************
60 * broadcast_error *
61 *******************/
62
63 class broadcast_error : public std::runtime_error
64 {
65 public:
66
67 explicit broadcast_error(const char* msg)
68 : std::runtime_error(msg)
69 {
70 }
71 };
72
73 template <class S1, class S2>
74 [[noreturn]] void throw_broadcast_error(const S1& lhs, const S2& rhs);
75
76 /*********************
77 * concatenate_error *
78 *********************/
79
80 class concatenate_error : public std::runtime_error
81 {
82 public:
83
84 explicit concatenate_error(const char* msg)
85 : std::runtime_error(msg)
86 {
87 }
88 };
89
90 template <class S1, class S2>
91 [[noreturn]] void throw_concatenate_error(const S1& lhs, const S2& rhs);
92
93 /**********************************
94 * broadcast_error implementation *
95 **********************************/
96
97 namespace detail
98 {
99 template <class S1, class S2>
100 inline std::string shape_error_message(const S1& lhs, const S2& rhs)
101 {
102 std::ostringstream buf("Incompatible dimension of arrays:", std::ios_base::ate);
103
104 buf << "\n LHS shape = (";
105 using size_type1 = typename S1::value_type;
106 std::ostream_iterator<size_type1> iter1(buf, ", ");
107 std::copy(lhs.cbegin(), lhs.cend(), iter1);
108
109 buf << ")\n RHS shape = (";
110 using size_type2 = typename S2::value_type;
111 std::ostream_iterator<size_type2> iter2(buf, ", ");
112 std::copy(rhs.cbegin(), rhs.cend(), iter2);
113 buf << ")";
114
115 return buf.str();
116 }
117 }
118
119#ifdef NDEBUG
120 // Do not inline this function
121 template <class S1, class S2>
122 [[noreturn]] void throw_broadcast_error(const S1&, const S2&)
123 {
124 XTENSOR_THROW(broadcast_error, "Incompatible dimension of arrays, compile in DEBUG for more info");
125 }
126#else
127 template <class S1, class S2>
128 [[noreturn]] void throw_broadcast_error(const S1& lhs, const S2& rhs)
129 {
130 std::string msg = detail::shape_error_message(lhs, rhs);
131 XTENSOR_THROW(broadcast_error, msg.c_str());
132 }
133#endif
134
135 /************************************
136 * concatenate_error implementation *
137 ************************************/
138
139#ifdef NDEBUG
140 // Do not inline this function
141 template <class S1, class S2>
142 [[noreturn]] void throw_concatenate_error(const S1&, const S2&)
143 {
144 XTENSOR_THROW(concatenate_error, "Incompatible dimension of arrays, compile in DEBUG for more info");
145 }
146#else
147 template <class S1, class S2>
148 [[noreturn]] void throw_concatenate_error(const S1& lhs, const S2& rhs)
149 {
150 std::string msg = detail::shape_error_message(lhs, rhs);
151 XTENSOR_THROW(concatenate_error, msg.c_str());
152 }
153#endif
154
155 /*******************
156 * transpose_error *
157 *******************/
158
159 class transpose_error : public std::runtime_error
160 {
161 public:
162
163 explicit transpose_error(const char* msg)
164 : std::runtime_error(msg)
165 {
166 }
167 };
168
169 /***************
170 * check_index *
171 ***************/
172
173 template <class S, class... Args>
174 void check_index(const S& shape, Args... args);
175
176 template <class S, class It>
177 void check_element_index(const S& shape, It first, It last);
178
179 namespace detail
180 {
181 template <class S, std::size_t dim>
182 inline void check_index_impl(const S&)
183 {
184 }
185
186 template <class S, std::size_t dim>
187 inline void check_index_impl(const S&, missing_type)
188 {
189 }
190
191 template <class S, std::size_t dim, class T, class... Args>
192 inline void check_index_impl(const S& shape, T arg, Args... args)
193 {
194 if (std::size_t(arg) >= std::size_t(shape[dim]) && shape[dim] != 1)
195 {
196 XTENSOR_THROW(
197 std::out_of_range,
198 "index " + std::to_string(arg) + " is out of bounds for axis " + std::to_string(dim)
199 + " with size " + std::to_string(shape[dim])
200 );
201 }
202 check_index_impl<S, dim + 1>(shape, args...);
203 }
204 }
205
206 template <class S>
207 inline void check_index(const S&)
208 {
209 }
210
211 template <class S>
212 inline void check_index(const S&, missing_type)
213 {
214 }
215
216 template <class S, class Arg, class... Args>
217 inline void check_index(const S& shape, Arg arg, Args... args)
218 {
219 constexpr std::size_t nargs = sizeof...(Args) + 1;
220 if (nargs == shape.size())
221 {
222 detail::check_index_impl<S, 0>(shape, arg, args...);
223 }
224 else if (nargs > shape.size())
225 {
226 // Too many arguments: drop the first
227 check_index(shape, args...);
228 }
229 else if (detail::last_type_is_missing<Args...>)
230 {
231 // Too few arguments & last argument xt::missing: postfix index with zeros
232 detail::check_index_impl<S, 0>(shape, arg, args...);
233 }
234 else
235 {
236 // Too few arguments: ignore the beginning of the shape
237 auto it = shape.end() - nargs;
238 detail::check_index_impl<decltype(it), 0>(it, arg, args...);
239 }
240 }
241
242 template <class S, class It>
243 inline void check_element_index(const S& shape, It first, It last)
244 {
245 using value_type = typename std::iterator_traits<It>::value_type;
246 using size_type = typename S::size_type;
247 auto dst = static_cast<size_type>(last - first);
248 It efirst = last - static_cast<std::ptrdiff_t>((std::min)(shape.size(), dst));
249 std::size_t axis = 0;
250
251 while (efirst != last)
252 {
253 if (*efirst >= value_type(shape[axis]) && shape[axis] != 1)
254 {
255 XTENSOR_THROW(
256 std::out_of_range,
257 "index " + std::to_string(*efirst) + " is out of bounds for axis " + std::to_string(axis)
258 + " with size " + std::to_string(shape[axis])
259 );
260 }
261 ++efirst, ++axis;
262 }
263 }
264
265 /*******************
266 * check_dimension *
267 *******************/
268
269 template <class S, class... Args>
270 inline void check_dimension(const S& shape, Args...)
271 {
272 if (sizeof...(Args) > shape.size())
273 {
274 XTENSOR_THROW(
275 std::out_of_range,
276 "Number of arguments (" + std::to_string(sizeof...(Args))
277 + ") is greater than the number of dimensions (" + std::to_string(shape.size()) + ")"
278 );
279 }
280 }
281
282 /*******************************
283 * check_axis implementation *
284 *******************************/
285
286 template <class A, class D>
287 inline void check_axis_in_dim(A axis, D dim, const char* subject = "Axis")
288 {
289 const auto sdim = static_cast<std::make_signed_t<D>>(dim);
290 if (xtl::cmp_greater_equal(axis, dim) || xtl::cmp_less(axis, -sdim))
291 {
292 XTENSOR_THROW(
293 std::out_of_range,
294 std::string(subject) + " (" + std::to_string(axis)
295 + ") is not within the number of dimensions (" + std::to_string(dim) + ')'
296 );
297 }
298 }
299
300 /****************
301 * check_access *
302 ****************/
303
304 template <class S, class... Args>
305 inline void check_access(const S& shape, Args... args)
306 {
307 check_dimension(shape, args...);
308 check_index(shape, args...);
309 }
310
311#if (defined(XTENSOR_ENABLE_ASSERT) && !defined(XTENSOR_DISABLE_EXCEPTIONS))
312#define XTENSOR_TRY(expr) XTENSOR_TRY_IMPL(expr, __FILE__, __LINE__)
313#define XTENSOR_TRY_IMPL(expr, file, line) \
314 try \
315 { \
316 expr; \
317 } \
318 catch (std::exception & e) \
319 { \
320 XTENSOR_THROW( \
321 std::runtime_error, \
322 std::string(file) + ':' + std::to_string(line) + ": check failed\n\t" + std::string(e.what()) \
323 ); \
324 }
325#else
326#define XTENSOR_TRY(expr)
327#endif
328
329#ifdef XTENSOR_ENABLE_ASSERT
330#define XTENSOR_ASSERT(expr) XTENSOR_ASSERT_IMPL(expr, __FILE__, __LINE__)
331#define XTENSOR_ASSERT_IMPL(expr, file, line) \
332 if (!(expr)) \
333 { \
334 XTENSOR_THROW( \
335 std::runtime_error, \
336 std::string(file) + ':' + std::to_string(line) + ": assertion failed (" #expr ") \n\t" \
337 ); \
338 }
339#else
340#define XTENSOR_ASSERT(expr)
341#endif
342
343#ifdef XTENSOR_ENABLE_CHECK_DIMENSION
344#define XTENSOR_CHECK_DIMENSION(S, ARGS) XTENSOR_TRY(check_dimension(S, ARGS))
345#else
346#define XTENSOR_CHECK_DIMENSION(S, ARGS)
347#endif
348
349#ifdef XTENSOR_ENABLE_ASSERT
350#define XTENSOR_ASSERT_MSG(expr, msg) \
351 if (!(expr)) \
352 { \
353 XTENSOR_THROW( \
354 std::runtime_error, \
355 std::string("Assertion error!\n") + msg + "\n " + __FILE__ + '(' + std::to_string(__LINE__) + ")\n" \
356 ); \
357 }
358#else
359#define XTENSOR_ASSERT_MSG(expr, msg)
360#endif
361
362#define XTENSOR_PRECONDITION(expr, msg) \
363 if (!(expr)) \
364 { \
365 XTENSOR_THROW( \
366 std::runtime_error, \
367 std::string("Precondition violation!\n") + msg + "\n " + __FILE__ + '(' \
368 + std::to_string(__LINE__) + ")\n" \
369 ); \
370 }
371}
372#endif // XEXCEPTION_HPP
auto arg(E &&e) noexcept
Calculates the phase angle (in radians) elementwise for the complex numbers in e.
Definition xcomplex.hpp:221
standard mathematical functions for xexpressions