From b60a633df6273c6e4a4d72df53cf947b84aac7b9 Mon Sep 17 00:00:00 2001 From: Marcel Koch Date: Wed, 10 Jan 2024 13:11:53 +0000 Subject: [PATCH 1/4] add exception for 2D access --- include/ginkgo/core/base/exception_helpers.hpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/include/ginkgo/core/base/exception_helpers.hpp b/include/ginkgo/core/base/exception_helpers.hpp index c9d7e612de0..0482a50a334 100644 --- a/include/ginkgo/core/base/exception_helpers.hpp +++ b/include/ginkgo/core/base/exception_helpers.hpp @@ -774,6 +774,20 @@ inline T ensure_allocated_impl(T ptr, const std::string& file, int line, "semi-colon warnings") +/** + * Ensures that an access is within the specified 2D dimensions. + * + * @param _row the row access + * @param _col the column access + * @param _bound the dimension bound + * + * @throw OutOfBoundsError if `_row >= _bound[0] || _col >= _bound[1]` + */ +#define GKO_ENSURE_IN_DIMENSION_BOUNDS(_row, _col, _bound) \ + GKO_ENSURE_IN_BOUNDS(_row, ::gko::detail::get_size(_bound)[0]); \ + GKO_ENSURE_IN_BOUNDS(_col, ::gko::detail::get_size(_bound)[1]) + + /** * Creates a StreamError exception. * This macro sets the correct information about the location of the error From 242542b9b0c6f9bfcce02dd66bc9163d71164ad4 Mon Sep 17 00:00:00 2001 From: Marcel Koch Date: Wed, 18 Oct 2023 10:15:21 +0200 Subject: [PATCH 2/4] allow dispatch helper to return value --- core/base/dispatch_helper.hpp | 127 ++++++++++++++++++++++++++-------- 1 file changed, 98 insertions(+), 29 deletions(-) diff --git a/core/base/dispatch_helper.hpp b/core/base/dispatch_helper.hpp index 5c030dedd17..62eccfde0c6 100644 --- a/core/base/dispatch_helper.hpp +++ b/core/base/dispatch_helper.hpp @@ -13,20 +13,55 @@ namespace gko { +namespace detail { + + +/** + * + * @copydoc run + * + * @note this is the end case + */ +template +ReturnType run_impl(T obj, Func&&, Args&&...) +{ + GKO_NOT_SUPPORTED(obj); +} + +/** + * @copydoc run + * + * @note This has additionally the return type encoded. + */ +template +ReturnType run_impl(T obj, Func&& f, Args&&... args) +{ + if (auto dobj = dynamic_cast(obj)) { + return f(dobj, std::forward(args)...); + } else { + return run_impl(obj, std::forward(f), + std::forward(args)...); + } +} /** * run uses template to go through the list and select the valid * template and run it. * - * @tparam T the type of input object - * @tparam Func the function will run if the object can be converted to K - * @tparam ...Args the additional arguments for the Func + * @tparam Base the Base class with one template + * @tparam T the type of input object waiting converted + * @tparam Func the validation + * @tparam ...Args the variadic arguments. * * @note this is the end case */ -template -void run(T obj, Func, Args...) +template class Base, typename T, + typename Func, typename... Args> +ReturnType run_impl(T obj, Func, Args...) { GKO_NOT_SUPPORTED(obj); } @@ -35,45 +70,68 @@ void run(T obj, Func, Args...) * run uses template to go through the list and select the valid * template and run it. * - * @tparam K the current type tried in the conversion + * @tparam Base the Base class with one template + * @tparam K the current template type of B. pointer of const Base is tried + * in the conversion. * @tparam ...Types the other types will be tried in the conversion if K fails - * @tparam T the type of input object - * @tparam Func the function will run if the object can be converted to K + * @tparam T the type of input object waiting converted + * @tparam Func the function will run if the object can be converted to pointer + * of const Base * @tparam ...Args the additional arguments for the Func * * @param obj the input object waiting converted * @param f the function will run if obj can be converted successfully * @param args the additional arguments for the function */ -template -void run(T obj, Func f, Args... args) +template class Base, typename K, + typename... Types, typename T, typename Func, typename... Args> +ReturnType run_impl(T obj, Func&& f, Args&&... args) { - if (auto dobj = dynamic_cast(obj)) { - f(dobj, args...); + if (auto dobj = std::dynamic_pointer_cast>(obj)) { + return f(dobj, args...); } else { - run(obj, f, args...); + return run_impl( + obj, std::forward(f), std::forward(args)...); } } + +} // namespace detail + + /** * run uses template to go through the list and select the valid * template and run it. * - * @tparam Base the Base class with one template - * @tparam T the type of input object waiting converted - * @tparam Func the validation - * @tparam ...Args the variadic arguments. + * @tparam K the current type tried in the conversion + * @tparam ...Types the other types will be tried in the conversion if K fails + * @tparam T the type of input object + * @tparam Func the function will run if the object can be converted to K + * @tparam ...Args the additional arguments for the Func * - * @note this is the end case + * @param obj the input object waiting converted + * @param f the function will run if obj can be converted successfully + * @param args the additional arguments for the function + * + * @note This assumes that each invocation of f with types (K, Types...) + * returns the same type + * + * @return the result of f invoked with obj cast to the first matching type */ -template