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