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