Ginkgo Generated from branch based on main. Ginkgo version 1.10.0
A numerical linear algebra library targeting many-core architectures
Loading...
Searching...
No Matches
exception_helpers.hpp
1// SPDX-FileCopyrightText: 2017 - 2024 The Ginkgo authors
2//
3// SPDX-License-Identifier: BSD-3-Clause
4
5#ifndef GKO_PUBLIC_CORE_BASE_EXCEPTION_HELPERS_HPP_
6#define GKO_PUBLIC_CORE_BASE_EXCEPTION_HELPERS_HPP_
7
8
9#include <typeinfo>
10
11#include <ginkgo/core/base/batch_dim.hpp>
12#include <ginkgo/core/base/dim.hpp>
13#include <ginkgo/core/base/exception.hpp>
14#include <ginkgo/core/base/name_demangling.hpp>
15#include <ginkgo/core/base/utils_helper.hpp>
16
17
18namespace gko {
19
20
28#define GKO_QUOTE(...) #__VA_ARGS__
29
30
37#define GKO_NOT_IMPLEMENTED \
38 { \
39 throw ::gko::NotImplemented(__FILE__, __LINE__, __func__); \
40 } \
41 static_assert(true, \
42 "This assert is used to counter the false positive extra " \
43 "semi-colon warnings")
44
45
54#define GKO_NOT_COMPILED(_module) \
55 { \
56 throw ::gko::NotCompiled(__FILE__, __LINE__, __func__, \
57 GKO_QUOTE(_module)); \
58 } \
59 static_assert(true, \
60 "This assert is used to counter the false positive extra " \
61 "semi-colon warnings")
62
63
64namespace detail {
65
66
67template <typename T, typename T2 = void>
68struct dynamic_type_helper {
69 static const std::type_info& get(const T& obj) { return typeid(obj); }
70};
71
72template <typename T>
73struct dynamic_type_helper<T,
74 typename std::enable_if<std::is_pointer<T>::value ||
75 have_ownership<T>()>::type> {
76 static const std::type_info& get(const T& obj)
77 {
78 return obj ? typeid(*obj) : typeid(nullptr);
79 }
80};
81
82template <typename T>
83const std::type_info& get_dynamic_type(const T& obj)
84{
85 return dynamic_type_helper<T>::get(obj);
86}
87
88
89} // namespace detail
90
91
99#define GKO_NOT_SUPPORTED(_obj) \
100 { \
101 throw ::gko::NotSupported(__FILE__, __LINE__, __func__, \
102 ::gko::name_demangling::get_type_name( \
103 ::gko::detail::get_dynamic_type(_obj))); \
104 } \
105 static_assert(true, \
106 "This assert is used to counter the false positive extra " \
107 "semi-colon warnings")
108
109
110namespace detail {
111
112
113template <typename T>
114inline dim<2> get_size(const T& op)
115{
116 return op->get_size();
117}
118
119inline dim<2> get_size(const dim<2>& size) { return size; }
120
121
122template <typename T>
123inline batch_dim<2> get_batch_size(const T& op)
124{
125 return op->get_size();
126}
127
128inline batch_dim<2> get_batch_size(const batch_dim<2>& size) { return size; }
129
130
131template <typename T>
132inline size_type get_num_batch_items(const T& obj)
133{
134 return obj.get_num_batch_items();
135}
136
137
138} // namespace detail
139
140
146#define GKO_ASSERT_EQ(_val1, _val2) \
147 if (_val1 != _val2) { \
148 throw ::gko::ValueMismatch(__FILE__, __LINE__, __func__, _val1, _val2, \
149 "expected equal values"); \
150 }
151
152
159#define GKO_ASSERT_IS_SQUARE_MATRIX(_op1) \
160 if (::gko::detail::get_size(_op1)[0] != \
161 ::gko::detail::get_size(_op1)[1]) { \
162 throw ::gko::DimensionMismatch( \
163 __FILE__, __LINE__, __func__, #_op1, \
164 ::gko::detail::get_size(_op1)[0], \
165 ::gko::detail::get_size(_op1)[1], #_op1, \
166 ::gko::detail::get_size(_op1)[0], \
167 ::gko::detail::get_size(_op1)[1], "expected square matrix"); \
168 }
169
170
176#define GKO_ASSERT_IS_NON_EMPTY_MATRIX(_op1) \
177 if (!(::gko::detail::get_size(_op1))) { \
178 throw ::gko::BadDimension(__FILE__, __LINE__, __func__, #_op1, \
179 ::gko::detail::get_size(_op1)[0], \
180 ::gko::detail::get_size(_op1)[1], \
181 "expected non-empty matrix"); \
182 }
183
184
190#define GKO_ASSERT_IS_POWER_OF_TWO(_val) \
191 do { \
192 if (_val == 0 || (_val & (_val - 1)) != 0) { \
193 throw ::gko::BadDimension(__FILE__, __LINE__, __func__, #_val, \
194 _val, _val, \
195 "expected power-of-two dimension"); \
196 } \
197 } while (false)
198
199
205#define GKO_ASSERT_CONFORMANT(_op1, _op2) \
206 if (::gko::detail::get_size(_op1)[1] != \
207 ::gko::detail::get_size(_op2)[0]) { \
208 throw ::gko::DimensionMismatch(__FILE__, __LINE__, __func__, #_op1, \
209 ::gko::detail::get_size(_op1)[0], \
210 ::gko::detail::get_size(_op1)[1], \
211 #_op2, \
212 ::gko::detail::get_size(_op2)[0], \
213 ::gko::detail::get_size(_op2)[1], \
214 "expected matching inner dimensions"); \
215 }
216
217
223#define GKO_ASSERT_REVERSE_CONFORMANT(_op1, _op2) \
224 if (::gko::detail::get_size(_op1)[0] != \
225 ::gko::detail::get_size(_op2)[1]) { \
226 throw ::gko::DimensionMismatch(__FILE__, __LINE__, __func__, #_op1, \
227 ::gko::detail::get_size(_op1)[0], \
228 ::gko::detail::get_size(_op1)[1], \
229 #_op2, \
230 ::gko::detail::get_size(_op2)[0], \
231 ::gko::detail::get_size(_op2)[1], \
232 "expected matching inner dimensions"); \
233 }
234
235
241#define GKO_ASSERT_EQUAL_ROWS(_op1, _op2) \
242 if (::gko::detail::get_size(_op1)[0] != \
243 ::gko::detail::get_size(_op2)[0]) { \
244 throw ::gko::DimensionMismatch( \
245 __FILE__, __LINE__, __func__, #_op1, \
246 ::gko::detail::get_size(_op1)[0], \
247 ::gko::detail::get_size(_op1)[1], #_op2, \
248 ::gko::detail::get_size(_op2)[0], \
249 ::gko::detail::get_size(_op2)[1], "expected matching row length"); \
250 }
251
252
259#define GKO_ASSERT_EQUAL_COLS(_op1, _op2) \
260 if (::gko::detail::get_size(_op1)[1] != \
261 ::gko::detail::get_size(_op2)[1]) { \
262 throw ::gko::DimensionMismatch(__FILE__, __LINE__, __func__, #_op1, \
263 ::gko::detail::get_size(_op1)[0], \
264 ::gko::detail::get_size(_op1)[1], \
265 #_op2, \
266 ::gko::detail::get_size(_op2)[0], \
267 ::gko::detail::get_size(_op2)[1], \
268 "expected matching column length"); \
269 }
270
271
278#define GKO_ASSERT_EQUAL_DIMENSIONS(_op1, _op2) \
279 if (::gko::detail::get_size(_op1) != ::gko::detail::get_size(_op2)) { \
280 throw ::gko::DimensionMismatch( \
281 __FILE__, __LINE__, __func__, #_op1, \
282 ::gko::detail::get_size(_op1)[0], \
283 ::gko::detail::get_size(_op1)[1], #_op2, \
284 ::gko::detail::get_size(_op2)[0], \
285 ::gko::detail::get_size(_op2)[1], "expected equal dimensions"); \
286 }
287
288
294#define GKO_ASSERT_BATCH_EQUAL_NUM_ITEMS(_op1, _op2) \
295 { \
296 auto equal_num_items = \
297 ::gko::detail::get_batch_size(_op1).get_num_batch_items() == \
298 ::gko::detail::get_batch_size(_op2).get_num_batch_items(); \
299 if (!equal_num_items) { \
300 throw ::gko::ValueMismatch( \
301 __FILE__, __LINE__, __func__, \
302 ::gko::detail::get_batch_size(_op1).get_num_batch_items(), \
303 ::gko::detail::get_batch_size(_op2).get_num_batch_items(), \
304 "expected equal number of batch items"); \
305 } \
306 }
307
308
314#define GKO_ASSERT_BATCH_CONFORMANT(_op1, _op2) \
315 { \
316 GKO_ASSERT_BATCH_EQUAL_NUM_ITEMS(_op1, _op2); \
317 auto equal_inner_size = \
318 ::gko::detail::get_batch_size(_op1).get_common_size()[1] == \
319 ::gko::detail::get_batch_size(_op2).get_common_size()[0]; \
320 if (!equal_inner_size) { \
321 throw ::gko::DimensionMismatch( \
322 __FILE__, __LINE__, __func__, #_op1, \
323 ::gko::detail::get_batch_size(_op1).get_common_size()[0], \
324 ::gko::detail::get_batch_size(_op1).get_common_size()[1], \
325 #_op2, \
326 ::gko::detail::get_batch_size(_op2).get_common_size()[0], \
327 ::gko::detail::get_batch_size(_op2).get_common_size()[1], \
328 "expected matching inner dimensions among all batch items"); \
329 } \
330 }
331
332
338#define GKO_ASSERT_BATCH_REVERSE_CONFORMANT(_op1, _op2) \
339 { \
340 GKO_ASSERT_BATCH_EQUAL_NUM_ITEMS(_op1, _op2); \
341 auto equal_outer_size = \
342 ::gko::detail::get_batch_size(_op1).get_common_size()[0] == \
343 ::gko::detail::get_batch_size(_op2).get_common_size()[1]; \
344 if (!equal_outer_size) { \
345 throw ::gko::DimensionMismatch( \
346 __FILE__, __LINE__, __func__, #_op1, \
347 ::gko::detail::get_batch_size(_op1).get_common_size()[0], \
348 ::gko::detail::get_batch_size(_op1).get_common_size()[1], \
349 #_op2, \
350 ::gko::detail::get_batch_size(_op2).get_common_size()[0], \
351 ::gko::detail::get_batch_size(_op2).get_common_size()[1], \
352 "expected matching outer dimensions among all batch items"); \
353 } \
354 }
355
356
362#define GKO_ASSERT_BATCH_EQUAL_ROWS(_op1, _op2) \
363 { \
364 GKO_ASSERT_BATCH_EQUAL_NUM_ITEMS(_op1, _op2); \
365 auto equal_rows = \
366 ::gko::detail::get_batch_size(_op1).get_common_size()[0] == \
367 ::gko::detail::get_batch_size(_op2).get_common_size()[0]; \
368 if (!equal_rows) { \
369 throw ::gko::DimensionMismatch( \
370 __FILE__, __LINE__, __func__, #_op1, \
371 ::gko::detail::get_batch_size(_op1).get_common_size()[0], \
372 ::gko::detail::get_batch_size(_op1).get_common_size()[1], \
373 #_op2, \
374 ::gko::detail::get_batch_size(_op2).get_common_size()[0], \
375 ::gko::detail::get_batch_size(_op2).get_common_size()[1], \
376 "expected matching number of rows among all batch items"); \
377 } \
378 }
379
380
387#define GKO_ASSERT_BATCH_EQUAL_COLS(_op1, _op2) \
388 { \
389 GKO_ASSERT_BATCH_EQUAL_NUM_ITEMS(_op1, _op2); \
390 auto equal_cols = \
391 ::gko::detail::get_batch_size(_op1).get_common_size()[1] == \
392 ::gko::detail::get_batch_size(_op2).get_common_size()[1]; \
393 if (!equal_cols) { \
394 throw ::gko::DimensionMismatch( \
395 __FILE__, __LINE__, __func__, #_op1, \
396 ::gko::detail::get_batch_size(_op1).get_common_size()[0], \
397 ::gko::detail::get_batch_size(_op1).get_common_size()[1], \
398 #_op2, \
399 ::gko::detail::get_batch_size(_op2).get_common_size()[0], \
400 ::gko::detail::get_batch_size(_op2).get_common_size()[1], \
401 "expected matching number of cols among all batch items"); \
402 } \
403 }
404
405
412#define GKO_ASSERT_BATCH_EQUAL_DIMENSIONS(_op1, _op2) \
413 { \
414 GKO_ASSERT_BATCH_EQUAL_NUM_ITEMS(_op1, _op2); \
415 auto equal_size = \
416 ::gko::detail::get_batch_size(_op1).get_common_size() == \
417 ::gko::detail::get_batch_size(_op2).get_common_size(); \
418 if (!equal_size) { \
419 throw ::gko::DimensionMismatch( \
420 __FILE__, __LINE__, __func__, #_op1, \
421 ::gko::detail::get_batch_size(_op1).get_common_size()[0], \
422 ::gko::detail::get_batch_size(_op1).get_common_size()[1], \
423 #_op2, \
424 ::gko::detail::get_batch_size(_op2).get_common_size()[0], \
425 ::gko::detail::get_batch_size(_op2).get_common_size()[1], \
426 "expected matching size among all batch items"); \
427 } \
428 }
429
430
437#define GKO_ASSERT_BATCH_HAS_SQUARE_DIMENSIONS(_op1) \
438 { \
439 auto is_square = \
440 ::gko::detail::get_batch_size(_op1).get_common_size()[0] == \
441 ::gko::detail::get_batch_size(_op1).get_common_size()[1]; \
442 if (!is_square) { \
443 throw ::gko::BadDimension( \
444 __FILE__, __LINE__, __func__, #_op1, \
445 ::gko::detail::get_batch_size(_op1).get_common_size()[0], \
446 ::gko::detail::get_batch_size(_op1).get_common_size()[1], \
447 "expected common size of matrices to be square"); \
448 } \
449 }
450
451
457#define GKO_MPI_ERROR(_errcode) \
458 ::gko::MpiError(__FILE__, __LINE__, __func__, _errcode)
459
460
466#define GKO_CUDA_ERROR(_errcode) \
467 ::gko::CudaError(__FILE__, __LINE__, __func__, _errcode)
468
469
475#define GKO_CUBLAS_ERROR(_errcode) \
476 ::gko::CublasError(__FILE__, __LINE__, __func__, _errcode)
477
478
484#define GKO_CURAND_ERROR(_errcode) \
485 ::gko::CurandError(__FILE__, __LINE__, __func__, _errcode)
486
487
493#define GKO_CUSPARSE_ERROR(_errcode) \
494 ::gko::CusparseError(__FILE__, __LINE__, __func__, _errcode)
495
496
502#define GKO_CUFFT_ERROR(_errcode) \
503 ::gko::CufftError(__FILE__, __LINE__, __func__, _errcode)
504
505
511#define GKO_ASSERT_NO_CUDA_ERRORS(_cuda_call) \
512 do { \
513 auto _errcode = _cuda_call; \
514 if (_errcode != cudaSuccess) { \
515 throw GKO_CUDA_ERROR(_errcode); \
516 } \
517 } while (false)
518
519
525#define GKO_ASSERT_NO_CUBLAS_ERRORS(_cublas_call) \
526 do { \
527 auto _errcode = _cublas_call; \
528 if (_errcode != CUBLAS_STATUS_SUCCESS) { \
529 throw GKO_CUBLAS_ERROR(_errcode); \
530 } \
531 } while (false)
532
533
539#define GKO_ASSERT_NO_CURAND_ERRORS(_curand_call) \
540 do { \
541 auto _errcode = _curand_call; \
542 if (_errcode != CURAND_STATUS_SUCCESS) { \
543 throw GKO_CURAND_ERROR(_errcode); \
544 } \
545 } while (false)
546
547
553#define GKO_ASSERT_NO_CUSPARSE_ERRORS(_cusparse_call) \
554 do { \
555 auto _errcode = _cusparse_call; \
556 if (_errcode != CUSPARSE_STATUS_SUCCESS) { \
557 throw GKO_CUSPARSE_ERROR(_errcode); \
558 } \
559 } while (false)
560
561
567#define GKO_ASSERT_NO_CUFFT_ERRORS(_cufft_call) \
568 do { \
569 auto _errcode = _cufft_call; \
570 if (_errcode != CUFFT_SUCCESS) { \
571 throw GKO_CUFFT_ERROR(_errcode); \
572 } \
573 } while (false)
574
575
581#define GKO_HIP_ERROR(_errcode) \
582 ::gko::HipError(__FILE__, __LINE__, __func__, _errcode)
583
584
590#define GKO_HIPBLAS_ERROR(_errcode) \
591 ::gko::HipblasError(__FILE__, __LINE__, __func__, _errcode)
592
593
599#define GKO_HIPRAND_ERROR(_errcode) \
600 ::gko::HiprandError(__FILE__, __LINE__, __func__, _errcode)
601
602
608#define GKO_HIPSPARSE_ERROR(_errcode) \
609 ::gko::HipsparseError(__FILE__, __LINE__, __func__, _errcode)
610
611
617#define GKO_HIPFFT_ERROR(_errcode) \
618 ::gko::HipfftError(__FILE__, __LINE__, __func__, _errcode)
619
620
626#define GKO_ASSERT_NO_HIP_ERRORS(_hip_call) \
627 do { \
628 auto _errcode = _hip_call; \
629 if (_errcode != hipSuccess) { \
630 throw GKO_HIP_ERROR(_errcode); \
631 } \
632 } while (false)
633
634
640#define GKO_ASSERT_NO_HIPBLAS_ERRORS(_hipblas_call) \
641 do { \
642 auto _errcode = _hipblas_call; \
643 if (_errcode != HIPBLAS_STATUS_SUCCESS) { \
644 throw GKO_HIPBLAS_ERROR(_errcode); \
645 } \
646 } while (false)
647
648
654#define GKO_ASSERT_NO_HIPRAND_ERRORS(_hiprand_call) \
655 do { \
656 auto _errcode = _hiprand_call; \
657 if (_errcode != HIPRAND_STATUS_SUCCESS) { \
658 throw GKO_HIPRAND_ERROR(_errcode); \
659 } \
660 } while (false)
661
662
668#define GKO_ASSERT_NO_HIPSPARSE_ERRORS(_hipsparse_call) \
669 do { \
670 auto _errcode = _hipsparse_call; \
671 if (_errcode != HIPSPARSE_STATUS_SUCCESS) { \
672 throw GKO_HIPSPARSE_ERROR(_errcode); \
673 } \
674 } while (false)
675
676
682#define GKO_ASSERT_NO_HIPFFT_ERRORS(_hipfft_call) \
683 do { \
684 auto _errcode = _hipfft_call; \
685 if (_errcode != HIPFFT_SUCCESS) { \
686 throw GKO_HIPFFT_ERROR(_errcode); \
687 } \
688 } while (false)
689
690
696#define GKO_ASSERT_NO_MPI_ERRORS(_mpi_call) \
697 do { \
698 auto _errcode = _mpi_call; \
699 if (_errcode != MPI_SUCCESS) { \
700 throw GKO_MPI_ERROR(_errcode); \
701 } \
702 } while (false)
703
704
705namespace detail {
706
707
708template <typename T>
709inline T ensure_allocated_impl(T ptr, const std::string& file, int line,
710 const std::string& dev, size_type size)
711{
712 if (ptr == nullptr) {
713 throw AllocationError(file, line, dev, size);
714 }
715 return ptr;
716}
717
718
719} // namespace detail
720
721
736#define GKO_ENSURE_ALLOCATED(_ptr, _dev, _size) \
737 ::gko::detail::ensure_allocated_impl(_ptr, __FILE__, __LINE__, _dev, _size)
738
739
748#define GKO_ENSURE_IN_BOUNDS(_index, _bound) \
749 if (_index >= _bound) { \
750 throw ::gko::OutOfBoundsError(__FILE__, __LINE__, _index, _bound); \
751 } \
752 static_assert(true, \
753 "This assert is used to counter the false positive extra " \
754 "semi-colon warnings")
755
756
767#define GKO_ENSURE_COMPATIBLE_BOUNDS(_source, _target) \
768 if (_source > _target) { \
769 throw ::gko::OutOfBoundsError(__FILE__, __LINE__, _source, _target); \
770 } \
771 static_assert(true, \
772 "This assert is used to counter the false positive extra " \
773 "semi-colon warnings")
774
775
785#define GKO_ENSURE_IN_DIMENSION_BOUNDS(_row, _col, _bound) \
786 GKO_ENSURE_IN_BOUNDS(_row, ::gko::detail::get_size(_bound)[0]); \
787 GKO_ENSURE_IN_BOUNDS(_col, ::gko::detail::get_size(_bound)[1])
788
789
800#define GKO_STREAM_ERROR(_message) \
801 ::gko::StreamError(__FILE__, __LINE__, __func__, _message)
802
803
810#define GKO_KERNEL_NOT_FOUND \
811 { \
812 throw ::gko::KernelNotFound(__FILE__, __LINE__, __func__); \
813 } \
814 static_assert(true, \
815 "This assert is used to counter the false positive extra " \
816 "semi-colon warnings")
817
818
825#define GKO_UNSUPPORTED_MATRIX_PROPERTY(_message) \
826 { \
827 throw ::gko::UnsupportedMatrixProperty(__FILE__, __LINE__, _message); \
828 } \
829 static_assert(true, \
830 "This assert is used to counter the false positive extra " \
831 "semi-colon warnings")
832
833
844#define GKO_ASSERT_BLOCK_SIZE_CONFORMANT(_size, _block_size) \
845 if (_size % _block_size != 0) { \
846 throw BlockSizeError<decltype(_size)>(__FILE__, __LINE__, _block_size, \
847 _size); \
848 } \
849 static_assert(true, \
850 "This assert is used to counter the false positive extra " \
851 "semi-colon warnings")
852
853
861#define GKO_ASSERT_IS_SCALAR(_op) \
862 { \
863 auto sz = gko::detail::get_size(_op); \
864 if (sz[0] != 1 || sz[1] != 1) { \
865 throw ::gko::BadDimension(__FILE__, __LINE__, __func__, #_op, \
866 sz[0], sz[1], "expected scalar"); \
867 } \
868 } \
869 static_assert(true, \
870 "This assert is used to counter the false positive extra " \
871 "semi-colon warnings")
872
873
881#define GKO_INVALID_STATE(_message) \
882 { \
883 throw ::gko::InvalidStateError(__FILE__, __LINE__, __func__, \
884 _message); \
885 } \
886 static_assert(true, \
887 "This assert is used to counter the false positive extra " \
888 "semi-colon warnings")
889
890
899#define GKO_THROW_IF_INVALID(_condition, _message) \
900 { \
901 if (!(_condition)) { \
902 throw ::gko::InvalidStateError(__FILE__, __LINE__, __func__, \
903 _message); \
904 } \
905 } \
906 static_assert(true, \
907 "This assert is used to counter the false positive extra " \
908 "semi-colon warnings")
909
910
911} // namespace gko
912
913
914#endif // GKO_PUBLIC_CORE_BASE_EXCEPTION_HELPERS_HPP_
The Ginkgo namespace.
Definition abstract_factory.hpp:20
std::size_t size_type
Integral type used for allocation quantities.
Definition types.hpp:90