Ginkgo  Generated from pipelines/1589998975 branch based on develop. Ginkgo version 1.10.0
A numerical linear algebra library targeting many-core architectures
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 
18 namespace 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 
64 namespace detail {
65 
66 
67 template <typename T, typename T2 = void>
68 struct dynamic_type_helper {
69  static const std::type_info& get(const T& obj) { return typeid(obj); }
70 };
71 
72 template <typename T>
73 struct 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 
82 template <typename T>
83 const 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 
110 namespace detail {
111 
112 
113 template <typename T>
114 inline dim<2> get_size(const T& op)
115 {
116  return op->get_size();
117 }
118 
119 inline dim<2> get_size(const dim<2>& size) { return size; }
120 
121 
122 template <typename T>
123 inline batch_dim<2> get_batch_size(const T& op)
124 {
125  return op->get_size();
126 }
127 
128 inline batch_dim<2> get_batch_size(const batch_dim<2>& size) { return size; }
129 
130 
131 template <typename T>
132 inline 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 
705 namespace detail {
706 
707 
708 template <typename T>
709 inline 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_
gko::size_type
std::size_t size_type
Integral type used for allocation quantities.
Definition: types.hpp:89
gko
The Ginkgo namespace.
Definition: abstract_factory.hpp:20