From cb285cf82447705e7f34f75b06d54cb87df39b48 Mon Sep 17 00:00:00 2001 From: Joseph Schuchart Date: Tue, 3 Sep 2024 18:15:10 -0400 Subject: [PATCH 1/6] Consolidate make_tt_tpl and make_tt We can map make_tt_tpl onto the same mechanism we use for make_tt by adding a template template parameter that signals whether arguments are passed as tuple or unpacked. Signed-off-by: Joseph Schuchart --- ttg/ttg/make_tt.h | 297 ++++++++++++++++------------------------------ 1 file changed, 103 insertions(+), 194 deletions(-) diff --git a/ttg/ttg/make_tt.h b/ttg/ttg/make_tt.h index 81897b816..7ba01b56d 100644 --- a/ttg/ttg/make_tt.h +++ b/ttg/ttg/make_tt.h @@ -3,127 +3,6 @@ #ifndef TTG_MAKE_TT_H #define TTG_MAKE_TT_H -// Class to wrap a callable with signature -// -// case 1 (keyT != void): void op(auto&& key, std::tuple&&, std::tuple&) -// case 2 (keyT == void): void op(std::tuple&&, std::tuple&) -// -template -class CallableWrapTT - : public TT, - ttg::typelist> { - using baseT = typename CallableWrapTT::ttT; - - using input_values_tuple_type = typename baseT::input_values_tuple_type; - using input_refs_tuple_type = typename baseT::input_refs_tuple_type; - using input_edges_type = typename baseT::input_edges_type; - using output_edges_type = typename baseT::output_edges_type; - - using noref_funcT = std::remove_reference_t; - std::conditional_t, std::add_pointer_t, noref_funcT> func; - - template - void call_func(Key &&key, Tuple &&args, output_terminalsT &out) { - if constexpr (funcT_receives_outterm_tuple) - func(std::forward(key), std::forward(args), out); - else { - auto old_output_tls_ptr = this->outputs_tls_ptr_accessor(); - this->set_outputs_tls_ptr(); - func(std::forward(key), std::forward(args)); - this->set_outputs_tls_ptr(old_output_tls_ptr); - } - } - - template - void call_func(TupleOrKey &&args, output_terminalsT &out) { - if constexpr (funcT_receives_outterm_tuple) - func(std::forward(args), out); - else { - auto old_output_tls_ptr = this->outputs_tls_ptr_accessor(); - this->set_outputs_tls_ptr(); - func(std::forward(args)); - this->set_outputs_tls_ptr(old_output_tls_ptr); - } - } - - void call_func(output_terminalsT &out) { - if constexpr (funcT_receives_outterm_tuple) - func(std::tuple<>(), out); - else { - auto old_output_tls_ptr = this->outputs_tls_ptr_accessor(); - this->set_outputs_tls_ptr(); - func(std::tuple<>()); - this->set_outputs_tls_ptr(old_output_tls_ptr); - } - } - - public: - template - CallableWrapTT(funcT_ &&f, const input_edges_type &inedges, const output_edges_type &outedges, - const std::string &name, const std::vector &innames, - const std::vector &outnames) - : baseT(inedges, outedges, name, innames, outnames), func(std::forward(f)) {} - - template - CallableWrapTT(funcT_ &&f, const std::string &name, const std::vector &innames, - const std::vector &outnames) - : baseT(name, innames, outnames), func(std::forward(f)) {} - - template - std::enable_if_t && !ttg::meta::is_empty_tuple_v && - !ttg::meta::is_void_v, - void> - op(Key &&key, ArgsTuple &&args_tuple, output_terminalsT &out) { - call_func(std::forward(key), std::forward(args_tuple), out); - } - - template - std::enable_if_t && !ttg::meta::is_empty_tuple_v && - ttg::meta::is_void_v, - void> - op(ArgsTuple &&args_tuple, output_terminalsT &out) { - call_func(std::forward(args_tuple), out); - } - - template - std::enable_if_t && !ttg::meta::is_void_v, void> op( - Key &&key, output_terminalsT &out) { - call_func(std::forward(key), out); - } - - template - std::enable_if_t && ttg::meta::is_void_v, void> op( - output_terminalsT &out) { - call_func(out); - } -}; - -template -struct CallableWrapTTUnwrapTypelist; - -template -struct CallableWrapTTUnwrapTypelist> { - using type = CallableWrapTT...>; -}; - -template -struct CallableWrapTTUnwrapTypelist> { - using type = CallableWrapTT...>; -}; // Class to wrap a callable with signature // @@ -131,12 +10,13 @@ struct CallableWrapTTUnwrapTypelist&) // // returnT is void for funcT = synchronous (ordinary) function and the appropriate return type for funcT=coroutine -template class CallableWrapTTArgs : public TT< keyT, output_terminalsT, - CallableWrapTTArgs, + CallableWrapTTArgs, ttg::typelist> { using baseT = typename CallableWrapTTArgs::ttT; @@ -224,104 +104,105 @@ class CallableWrapTTArgs template auto call_func(Key &&key, Tuple &&args_tuple, output_terminalsT &out, std::index_sequence) { using func_args_t = ttg::meta::tuple_concat_t, input_refs_tuple_type, output_edges_type>; - - if constexpr (funcT_receives_outterm_tuple) { + auto invoke_func_handle_ret = [&](auto&&... args){ if constexpr (std::is_void_v) { - func(std::forward(key), - baseT::template get>(std::forward(args_tuple))..., out); - return; + func(std::forward(key), std::forward(args)...); } else { - auto ret = func( - std::forward(key), - baseT::template get>(std::forward(args_tuple))..., out); - - return process_return(std::move(ret), out); + return process_return(func(std::forward(key), std::forward(args)...), out); + } + }; + auto unpack_input_tuple_if_needed = [&](auto&&... args){ + static_assert(!funcT_receives_input_tuple); + if constexpr (funcT_receives_input_tuple) { + return invoke_func_handle_ret(std::forward(args_tuple), std::forward(args)...); + } else { + return invoke_func_handle_ret(baseT::template get>(std::forward(args_tuple))..., + std::forward(args)...); } + }; + + if constexpr (funcT_receives_outterm_tuple) { + return unpack_input_tuple_if_needed(out); } else { auto old_output_tls_ptr = this->outputs_tls_ptr_accessor(); this->set_outputs_tls_ptr(); - if constexpr (std::is_void_v) { - func(std::forward(key), - baseT::template get>(std::forward(args_tuple))...); - this->set_outputs_tls_ptr(old_output_tls_ptr); - return; - } else { - auto ret = - func(std::forward(key), - baseT::template get>(std::forward(args_tuple))...); - this->set_outputs_tls_ptr(old_output_tls_ptr); - return process_return(std::move(ret), out); - } + // make sure the output tls is reset + auto _ = ttg::detail::finally([this, old_output_tls_ptr](){ this->set_outputs_tls_ptr(old_output_tls_ptr); }); + return unpack_input_tuple_if_needed(); } } template auto call_func(Tuple &&args_tuple, output_terminalsT &out, std::index_sequence) { using func_args_t = ttg::meta::tuple_concat_t; - if constexpr (funcT_receives_outterm_tuple) { + + auto invoke_func_handle_ret = [&](auto&&... args){ if constexpr (std::is_void_v) { - func(baseT::template get>(std::forward(args_tuple))..., out); + func(std::forward(args)...); + } else { + return process_return(func(std::forward(args)...), out); + } + }; + auto unpack_input_tuple_if_needed = [&](auto&& fn, auto&&... args){ + if constexpr (funcT_receives_input_tuple) { + return fn(std::forward(args_tuple), std::forward(args)...); } else { - auto ret = func(baseT::template get>(std::forward(args_tuple))..., out); - return process_return(std::move(ret), out); + return fn(baseT::template get>(std::forward(args_tuple))..., + std::forward(args)...); } + }; + + if constexpr (funcT_receives_outterm_tuple) { + return unpack_input_tuple_if_needed(invoke_func_handle_ret, out); } else { auto old_output_tls_ptr = this->outputs_tls_ptr_accessor(); this->set_outputs_tls_ptr(); - if constexpr (std::is_void_v) { - func(baseT::template get>(std::forward(args_tuple))...); - this->set_outputs_tls_ptr(old_output_tls_ptr); - } else { - auto ret = func(baseT::template get>(std::forward(args_tuple))...); - this->set_outputs_tls_ptr(old_output_tls_ptr); - return process_return(std::move(ret), out); - } + // make sure the output tls is reset + auto _ = ttg::detail::finally([this, old_output_tls_ptr](){ this->set_outputs_tls_ptr(old_output_tls_ptr); }); + return unpack_input_tuple_if_needed(invoke_func_handle_ret); } } template auto call_func(Key &&key, output_terminalsT &out) { - if constexpr (funcT_receives_outterm_tuple) { + auto invoke_func_handle_ret = [&](auto&&... args){ if constexpr (std::is_void_v) { - func(std::forward(key), out); + func(std::forward(key), std::forward(args)...); } else { - auto ret = func(std::forward(key), out); - return process_return(std::move(ret), out); + return process_return(func(std::forward(key), std::forward(args)...), out); } + }; + + if constexpr (funcT_receives_outterm_tuple) { + invoke_func_handle_ret(out); } else { auto old_output_tls_ptr = this->outputs_tls_ptr_accessor(); this->set_outputs_tls_ptr(); - if constexpr (std::is_void_v) { - func(std::forward(key)); - this->set_outputs_tls_ptr(old_output_tls_ptr); - } else { - auto ret = func(std::forward(key)); - this->set_outputs_tls_ptr(old_output_tls_ptr); - return process_return(std::move(ret), out); - } + // make sure the output tls is reset + auto _ = ttg::detail::finally([this, old_output_tls_ptr](){ this->set_outputs_tls_ptr(old_output_tls_ptr); }); + return invoke_func_handle_ret(); } } template auto call_func(OutputTerminals &out) { - if constexpr (funcT_receives_outterm_tuple) { + + auto invoke_func_handle_ret = [&](auto&&... args){ if constexpr (std::is_void_v) { - func(out); + func(std::forward(args)...); } else { - auto ret = func(out); - return process_return(std::move(ret), out); + return process_return(func(std::forward(args)...), out); } + }; + + if constexpr (funcT_receives_outterm_tuple) { + return invoke_func_handle_ret(out); } else { auto old_output_tls_ptr = this->outputs_tls_ptr_accessor(); this->set_outputs_tls_ptr(); - if constexpr (std::is_void_v) { - func(); - this->set_outputs_tls_ptr(old_output_tls_ptr); - } else { - auto ret = func(out); - this->set_outputs_tls_ptr(old_output_tls_ptr); - return process_return(std::move(ret), out); - } + // make sure the output tls is reset + auto _ = ttg::detail::finally([this, old_output_tls_ptr](){ this->set_outputs_tls_ptr(old_output_tls_ptr); }); + return invoke_func_handle_ret(); } } @@ -378,23 +259,30 @@ class CallableWrapTTArgs }; }; -template struct CallableWrapTTArgsAsTypelist; -template -struct CallableWrapTTArgsAsTypelist> { - using type = CallableWrapTTArgs...>; }; -template -struct CallableWrapTTArgsAsTypelist> { - using type = CallableWrapTTArgs...>; }; @@ -425,7 +313,11 @@ struct CallableWrapTTArgsAsTypelist +template auto make_tt_tpl(funcT &&func, const std::tuple...> &inedges = std::tuple<>{}, const std::tuple &outedges = std::tuple<>{}, const std::string &name = "wrapper", const std::vector &innames = std::vector(sizeof...(input_edge_valuesT), @@ -446,14 +338,17 @@ auto make_tt_tpl(funcT &&func, const std::tuple>, ttg::meta::candidate_argument_bindings_t< std::tuple::value_type>...>>, - ttg::meta::typelist>; + ttg::meta::typelist>; // net list of candidate argument types excludes the empty typelists for void arguments using candidate_func_args_t = ttg::meta::filter_t; // compute list of argument types with which func can be invoked constexpr static auto func_is_generic = ttg::meta::is_generic_callable_v; - using gross_func_args_t = decltype(ttg::meta::compute_arg_binding_types_r(func, candidate_func_args_t{})); + using return_type_typelist_and_gross_func_args_t = + decltype(ttg::meta::compute_arg_binding_types(func, candidate_func_args_t{})); + using func_return_t = std::tuple_element_t<0, std::tuple_element_t<0, return_type_typelist_and_gross_func_args_t>>; + using gross_func_args_t = std::tuple_element_t<1, return_type_typelist_and_gross_func_args_t>; constexpr auto DETECTED_HOW_TO_INVOKE_GENERIC_FUNC = func_is_generic ? !std::is_same_v> : true; static_assert(DETECTED_HOW_TO_INVOKE_GENERIC_FUNC, @@ -499,14 +394,28 @@ auto make_tt_tpl(funcT &&func, const std::tuple; using decayed_input_args_t = ttg::meta::decayed_typelist_t; - using wrapT = - typename CallableWrapTTUnwrapTypelist::type; + using wrapT = typename CallableWrapTTArgsAsTypelist::type; static_assert(std::is_same_v>, "ttg::make_tt_tpl(func, inedges, outedges): inedges value types do not match argument types of func"); return std::make_unique(std::forward(func), inedges, outedges, name, innames, outnames); } +template +auto make_tt_tpl(funcT &&func, const std::tuple...> &inedges = std::tuple<>{}, + const std::tuple &outedges = std::tuple<>{}, const std::string &name = "wrapper", + const std::vector &innames = std::vector(sizeof...(input_edge_valuesT), + "input"), + const std::vector &outnames = std::vector(sizeof...(output_edgesT), + "output")) +{ + return make_tt_tpl( + std::forward(func), inedges, outedges, name, innames, outnames); +} // clang-format off /// @brief Factory function to assist in wrapping a callable with signature /// @@ -631,7 +540,7 @@ auto make_tt(funcT &&func, const std::tuple. using decayed_input_args_t = ttg::meta::decayed_typelist_t; // 3. full_input_args_t = edge-types with non-void types replaced by input_args_t using full_input_args_t = ttg::meta::replace_nonvoid_t; - using wrapT = typename CallableWrapTTArgsAsTypelist::type; return std::make_unique(std::forward(func), inedges, outedges, name, innames, outnames); From 81abc565b4924fb81aa5c2be36f08eee18c0fb05 Mon Sep 17 00:00:00 2001 From: Joseph Schuchart Date: Tue, 29 Oct 2024 19:30:14 -0400 Subject: [PATCH 2/6] Add ttg::detail::finally, taken from GSL Signed-off-by: Joseph Schuchart --- ttg/ttg/util/finally.h | 57 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 ttg/ttg/util/finally.h diff --git a/ttg/ttg/util/finally.h b/ttg/ttg/util/finally.h new file mode 100644 index 000000000..d37a94dc3 --- /dev/null +++ b/ttg/ttg/util/finally.h @@ -0,0 +1,57 @@ +#ifndef TTG_UTIL_FINALLY_H +#define TTG_UTIL_FINALLY_H + +/////////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2015 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +/////////////////////////////////////////////////////////////////////////////// + +namespace ttg::detail { + + /* finally, taken from GSL: https://github.com/microsoft/GSL */ + + // final_action allows you to ensure something gets run at the end of a scope + template + class final_action + { + public: + explicit final_action(const F& ff) noexcept : f{ff} { } + explicit final_action(F&& ff) noexcept : f{std::move(ff)} { } + + ~final_action() noexcept { if (invoke) f(); } + + final_action(final_action&& other) noexcept + : f(std::move(other.f)), invoke(std::exchange(other.invoke, false)) + { } + + final_action(const final_action&) = delete; + void operator=(const final_action&) = delete; + void operator=(final_action&&) = delete; + + private: + F f; + bool invoke = true; + }; + + + // finally() - convenience function to generate a final_action + template + [[nodiscard]] auto finally(F&& f) noexcept + { + return final_action>{std::forward(f)}; + } + +} // namespace ttg::detail + +#endif // TTG_UTIL_FINALLY_H From 899ba186ee37b4195e6f89c22bd8db523da8d09d Mon Sep 17 00:00:00 2001 From: Joseph Schuchart Date: Wed, 30 Oct 2024 10:22:47 -0400 Subject: [PATCH 3/6] Replace finally with scope_exit Signed-off-by: Joseph Schuchart --- ttg/CMakeLists.txt | 1 + ttg/ttg/madness/ttg.h | 1 + ttg/ttg/make_tt.h | 20 +++++++++++--- ttg/ttg/parsec/ttg.h | 1 + ttg/ttg/util/finally.h | 57 -------------------------------------- ttg/ttg/util/scope_exit.h | 58 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 77 insertions(+), 61 deletions(-) delete mode 100644 ttg/ttg/util/finally.h create mode 100644 ttg/ttg/util/scope_exit.h diff --git a/ttg/CMakeLists.txt b/ttg/CMakeLists.txt index b1fa72947..272f005ab 100644 --- a/ttg/CMakeLists.txt +++ b/ttg/CMakeLists.txt @@ -22,6 +22,7 @@ set(ttg-util-headers ${CMAKE_CURRENT_SOURCE_DIR}/ttg/util/meta.h ${CMAKE_CURRENT_SOURCE_DIR}/ttg/util/meta/callable.h ${CMAKE_CURRENT_SOURCE_DIR}/ttg/util/print.h + ${CMAKE_CURRENT_SOURCE_DIR}/ttg/util/scope_exit.h ${CMAKE_CURRENT_SOURCE_DIR}/ttg/util/span.h ${CMAKE_CURRENT_SOURCE_DIR}/ttg/util/trace.h ${CMAKE_CURRENT_SOURCE_DIR}/ttg/util/tree.h diff --git a/ttg/ttg/madness/ttg.h b/ttg/ttg/madness/ttg.h index 5d2360cfb..85dee437f 100644 --- a/ttg/ttg/madness/ttg.h +++ b/ttg/ttg/madness/ttg.h @@ -22,6 +22,7 @@ #include "ttg/util/macro.h" #include "ttg/util/meta.h" #include "ttg/util/meta/callable.h" +#include "ttg/util/scope_exit.h" #include "ttg/util/void.h" #include "ttg/world.h" #include "ttg/coroutine.h" diff --git a/ttg/ttg/make_tt.h b/ttg/ttg/make_tt.h index 7ba01b56d..97e6dfccc 100644 --- a/ttg/ttg/make_tt.h +++ b/ttg/ttg/make_tt.h @@ -127,7 +127,10 @@ class CallableWrapTTArgs auto old_output_tls_ptr = this->outputs_tls_ptr_accessor(); this->set_outputs_tls_ptr(); // make sure the output tls is reset - auto _ = ttg::detail::finally([this, old_output_tls_ptr](){ this->set_outputs_tls_ptr(old_output_tls_ptr); }); + auto _ = ttg::detail::scope_exit( + [this, old_output_tls_ptr](){ + this->set_outputs_tls_ptr(old_output_tls_ptr); + }); return unpack_input_tuple_if_needed(); } } @@ -158,7 +161,10 @@ class CallableWrapTTArgs auto old_output_tls_ptr = this->outputs_tls_ptr_accessor(); this->set_outputs_tls_ptr(); // make sure the output tls is reset - auto _ = ttg::detail::finally([this, old_output_tls_ptr](){ this->set_outputs_tls_ptr(old_output_tls_ptr); }); + auto _ = ttg::detail::scope_exit( + [this, old_output_tls_ptr](){ + this->set_outputs_tls_ptr(old_output_tls_ptr); + }); return unpack_input_tuple_if_needed(invoke_func_handle_ret); } } @@ -179,7 +185,10 @@ class CallableWrapTTArgs auto old_output_tls_ptr = this->outputs_tls_ptr_accessor(); this->set_outputs_tls_ptr(); // make sure the output tls is reset - auto _ = ttg::detail::finally([this, old_output_tls_ptr](){ this->set_outputs_tls_ptr(old_output_tls_ptr); }); + auto _ = ttg::detail::scope_exit( + [this, old_output_tls_ptr](){ + this->set_outputs_tls_ptr(old_output_tls_ptr); + }); return invoke_func_handle_ret(); } } @@ -201,7 +210,10 @@ class CallableWrapTTArgs auto old_output_tls_ptr = this->outputs_tls_ptr_accessor(); this->set_outputs_tls_ptr(); // make sure the output tls is reset - auto _ = ttg::detail::finally([this, old_output_tls_ptr](){ this->set_outputs_tls_ptr(old_output_tls_ptr); }); + auto _ = ttg::detail::scope_exit( + [this, old_output_tls_ptr](){ + this->set_outputs_tls_ptr(old_output_tls_ptr); + }); return invoke_func_handle_ret(); } } diff --git a/ttg/ttg/parsec/ttg.h b/ttg/ttg/parsec/ttg.h index 0a0ddefcb..2fc62bd91 100644 --- a/ttg/ttg/parsec/ttg.h +++ b/ttg/ttg/parsec/ttg.h @@ -33,6 +33,7 @@ #include "ttg/util/meta.h" #include "ttg/util/meta/callable.h" #include "ttg/util/print.h" +#include "ttg/util/scope_exit.h" #include "ttg/util/trace.h" #include "ttg/util/typelist.h" #ifdef TTG_HAVE_DEVICE diff --git a/ttg/ttg/util/finally.h b/ttg/ttg/util/finally.h deleted file mode 100644 index d37a94dc3..000000000 --- a/ttg/ttg/util/finally.h +++ /dev/null @@ -1,57 +0,0 @@ -#ifndef TTG_UTIL_FINALLY_H -#define TTG_UTIL_FINALLY_H - -/////////////////////////////////////////////////////////////////////////////// -// -// Copyright (c) 2015 Microsoft Corporation. All rights reserved. -// -// This code is licensed under the MIT License (MIT). -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -// -/////////////////////////////////////////////////////////////////////////////// - -namespace ttg::detail { - - /* finally, taken from GSL: https://github.com/microsoft/GSL */ - - // final_action allows you to ensure something gets run at the end of a scope - template - class final_action - { - public: - explicit final_action(const F& ff) noexcept : f{ff} { } - explicit final_action(F&& ff) noexcept : f{std::move(ff)} { } - - ~final_action() noexcept { if (invoke) f(); } - - final_action(final_action&& other) noexcept - : f(std::move(other.f)), invoke(std::exchange(other.invoke, false)) - { } - - final_action(const final_action&) = delete; - void operator=(const final_action&) = delete; - void operator=(final_action&&) = delete; - - private: - F f; - bool invoke = true; - }; - - - // finally() - convenience function to generate a final_action - template - [[nodiscard]] auto finally(F&& f) noexcept - { - return final_action>{std::forward(f)}; - } - -} // namespace ttg::detail - -#endif // TTG_UTIL_FINALLY_H diff --git a/ttg/ttg/util/scope_exit.h b/ttg/ttg/util/scope_exit.h new file mode 100644 index 000000000..5e5fe6722 --- /dev/null +++ b/ttg/ttg/util/scope_exit.h @@ -0,0 +1,58 @@ +#ifndef TTG_UTIL_SCOPE_EXIT_H +#define TTG_UTIL_SCOPE_EXIT_H + +// +// N4189: Scoped Resource - Generic RAII Wrapper for the Standard Library +// Peter Sommerlad and Andrew L. Sandoval +// Adopted from https://github.com/tandasat/ScopedResource/tree/master +// + +#include + +namespace ttg::detail { + template + struct scope_exit + { + // construction + explicit + scope_exit(EF &&f) + : exit_function(std::move(f)) + , execute_on_destruction{ true } + { } + + // move + scope_exit(scope_exit &&rhs) + : exit_function(std::move(rhs.exit_function)) + , execute_on_destruction{ rhs.execute_on_destruction } + { + rhs.release(); + } + + // release + ~scope_exit() + { + if (execute_on_destruction) this->exit_function(); + } + + void release() + { + this->execute_on_destruction = false; + } + + private: + scope_exit(scope_exit const &) = delete; + void operator=(scope_exit const &) = delete; + scope_exit& operator=(scope_exit &&) = delete; + EF exit_function; + bool execute_on_destruction; // exposition only + }; + + template + auto make_scope_exit(EF &&exit_function) + { + return scope_exit>(std::forward(exit_function)); + } + +} // namespace ttg::detail + +#endif // TTG_UTIL_SCOPE_EXIT_H \ No newline at end of file From fb55a37a6623bc3124211725f04a3425bb83b3e6 Mon Sep 17 00:00:00 2001 From: Joseph Schuchart Date: Wed, 30 Oct 2024 10:23:09 -0400 Subject: [PATCH 4/6] Fix tuple_element index in make_tt Signed-off-by: Joseph Schuchart --- ttg/ttg/make_tt.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ttg/ttg/make_tt.h b/ttg/ttg/make_tt.h index 97e6dfccc..f999677d6 100644 --- a/ttg/ttg/make_tt.h +++ b/ttg/ttg/make_tt.h @@ -150,7 +150,7 @@ class CallableWrapTTArgs if constexpr (funcT_receives_input_tuple) { return fn(std::forward(args_tuple), std::forward(args)...); } else { - return fn(baseT::template get>(std::forward(args_tuple))..., + return fn(baseT::template get>(std::forward(args_tuple))..., std::forward(args)...); } }; From 70a1f0e024852ee078d5f07b1272f1e307ef101f Mon Sep 17 00:00:00 2001 From: Joseph Schuchart Date: Wed, 30 Oct 2024 12:06:21 -0400 Subject: [PATCH 5/6] make_tt: fixes for passing empty tuple to callback Signed-off-by: Joseph Schuchart --- ttg/ttg/make_tt.h | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/ttg/ttg/make_tt.h b/ttg/ttg/make_tt.h index f999677d6..5f49edfd8 100644 --- a/ttg/ttg/make_tt.h +++ b/ttg/ttg/make_tt.h @@ -112,7 +112,6 @@ class CallableWrapTTArgs } }; auto unpack_input_tuple_if_needed = [&](auto&&... args){ - static_assert(!funcT_receives_input_tuple); if constexpr (funcT_receives_input_tuple) { return invoke_func_handle_ret(std::forward(args_tuple), std::forward(args)...); } else { @@ -179,6 +178,14 @@ class CallableWrapTTArgs } }; + auto invoke_func_empty_tuple = [&](auto&&... args){ + if constexpr(funcT_receives_input_tuple) { + invoke_func_handle_ret(std::tuple<>{}, std::forward(args)...); + } else { + invoke_func_handle_ret(std::forward(args)...); + } + }; + if constexpr (funcT_receives_outterm_tuple) { invoke_func_handle_ret(out); } else { @@ -204,8 +211,16 @@ class CallableWrapTTArgs } }; + auto invoke_func_empty_tuple = [&](auto&&... args){ + if constexpr(funcT_receives_input_tuple) { + invoke_func_handle_ret(std::tuple<>{}, std::forward(args)...); + } else { + invoke_func_handle_ret(std::forward(args)...); + } + }; + if constexpr (funcT_receives_outterm_tuple) { - return invoke_func_handle_ret(out); + return invoke_func_empty_tuple(out); } else { auto old_output_tls_ptr = this->outputs_tls_ptr_accessor(); this->set_outputs_tls_ptr(); @@ -214,7 +229,7 @@ class CallableWrapTTArgs [this, old_output_tls_ptr](){ this->set_outputs_tls_ptr(old_output_tls_ptr); }); - return invoke_func_handle_ret(); + return invoke_func_empty_tuple(); } } @@ -406,7 +421,7 @@ auto make_tt_tpl(funcT &&func, const std::tuple; using decayed_input_args_t = ttg::meta::decayed_typelist_t; - using wrapT = typename CallableWrapTTArgsAsTypelist::type; static_assert(std::is_same_v>, "ttg::make_tt_tpl(func, inedges, outedges): inedges value types do not match argument types of func"); @@ -425,7 +440,7 @@ auto make_tt_tpl(funcT &&func, const std::tuple &outnames = std::vector(sizeof...(output_edgesT), "output")) { - return make_tt_tpl( + return make_tt_tpl( std::forward(func), inedges, outedges, name, innames, outnames); } // clang-format off From 19c23c43514a5eeb479efc521616d2c061211e7b Mon Sep 17 00:00:00 2001 From: Joseph Schuchart Date: Thu, 31 Oct 2024 09:02:58 -0400 Subject: [PATCH 6/6] Rename CallableWrapTTArgs to CallableWrapTT and fix mrattg example Signed-off-by: Joseph Schuchart --- examples/madness/mrattg.cc | 12 ++++++++---- ttg/ttg/make_tt.h | 32 ++++++++++++++++---------------- 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/examples/madness/mrattg.cc b/examples/madness/mrattg.cc index 2341ba864..8fcc2c6a9 100644 --- a/examples/madness/mrattg.cc +++ b/examples/madness/mrattg.cc @@ -177,7 +177,8 @@ namespace detail { using compress_out_type = std::tuple>; using compress_in_type = std::tuple; template - using compwrap_type = ttg::CallableWrapTT, compress_out_type, Rin, Rin>; + using compwrap_type = ttg::CallableWrapTT, compress_out_type, Rin, Rin>; }; template @@ -187,7 +188,8 @@ namespace detail { using compress_out_type = std::tuple>; using compress_in_type = std::tuple; template - using compwrap_type = ttg::CallableWrapTT, compress_out_type, Rin, Rin, Rin, Rin>; + using compwrap_type = ttg::CallableWrapTT, compress_out_type, Rin, Rin, Rin, Rin>; }; template @@ -198,7 +200,8 @@ namespace detail { using compress_in_type = std::tuple; template using compwrap_type = - ttg::CallableWrapTT, compress_out_type, Rin, Rin, Rin, Rin, Rin, Rin, Rin, Rin>; + ttg::CallableWrapTT, compress_out_type, Rin, Rin, Rin, Rin, Rin, Rin, Rin, Rin>; }; }; // namespace detail @@ -277,7 +280,8 @@ auto make_compress(rnodeEdge& in, cnodeEdge& out, const using sendfuncT = decltype(&send_leaves_up); using sendwrapT = - ttg::CallableWrapTT, typename ::detail::tree_types::compress_out_type, + ttg::CallableWrapTT, typename ::detail::tree_types::compress_out_type, FunctionReconstructedNode>; using compfuncT = decltype(&do_compress); using compwrapT = typename ::detail::tree_types::template compwrap_type; diff --git a/ttg/ttg/make_tt.h b/ttg/ttg/make_tt.h index 5f49edfd8..d3912576a 100644 --- a/ttg/ttg/make_tt.h +++ b/ttg/ttg/make_tt.h @@ -13,12 +13,12 @@ template -class CallableWrapTTArgs +class CallableWrapTT : public TT< keyT, output_terminalsT, - CallableWrapTTArgs, + CallableWrapTT, ttg::typelist> { - using baseT = typename CallableWrapTTArgs::ttT; + using baseT = typename CallableWrapTT::ttT; using input_values_tuple_type = typename baseT::input_values_tuple_type; using input_refs_tuple_type = typename baseT::input_refs_tuple_type; @@ -54,7 +54,7 @@ class CallableWrapTTArgs template auto process_return(ReturnT&& ret, output_terminalsT &out) { static_assert(std::is_same_v, returnT>, - "CallableWrapTTArgs: returnT does not match the actual return type of funcT"); + "CallableWrapTT: returnT does not match the actual return type of funcT"); if constexpr (!std::is_void_v) { // protect from compiling for void returnT #ifdef TTG_HAVE_COROUTINE if constexpr (std::is_same_v) { @@ -83,10 +83,10 @@ class CallableWrapTTArgs #endif { static_assert(std::tuple_size_v> == 1, - "CallableWrapTTArgs <= 2, - "CallableWrapTTArgs == 0) @@ -241,13 +241,13 @@ class CallableWrapTTArgs public: template - CallableWrapTTArgs(funcT_ &&f, const input_edges_type &inedges, const typename baseT::output_edges_type &outedges, + CallableWrapTT(funcT_ &&f, const input_edges_type &inedges, const typename baseT::output_edges_type &outedges, const std::string &name, const std::vector &innames, const std::vector &outnames) : baseT(inedges, outedges, name, innames, outnames), func(std::forward(f)) {} template - CallableWrapTTArgs(funcT_ &&f, const std::string &name, const std::vector &innames, + CallableWrapTT(funcT_ &&f, const std::string &name, const std::vector &innames, const std::vector &outnames) : baseT(name, innames, outnames), func(std::forward(f)) {} @@ -289,15 +289,15 @@ class CallableWrapTTArgs template -struct CallableWrapTTArgsAsTypelist; +struct CallableWrapTTAsTypelist; template -struct CallableWrapTTArgsAsTypelist> { - using type = CallableWrapTTArgs...>; }; @@ -305,10 +305,10 @@ struct CallableWrapTTArgsAsTypelist -struct CallableWrapTTArgsAsTypelist> { - using type = CallableWrapTTArgs...>; }; @@ -421,7 +421,7 @@ auto make_tt_tpl(funcT &&func, const std::tuple; using decayed_input_args_t = ttg::meta::decayed_typelist_t; - using wrapT = typename CallableWrapTTArgsAsTypelist::type; static_assert(std::is_same_v>, "ttg::make_tt_tpl(func, inedges, outedges): inedges value types do not match argument types of func"); @@ -552,7 +552,7 @@ auto make_tt(funcT &&func, const std::tuple. OUTTERM_TUPLE_PASSED_AS_NONCONST_LVALUE_REF, "ttg::make_tt(func, ...): if given to func, the output terminal tuple must be passed by nonconst lvalue ref"); - // TT needs actual types of arguments to func ... extract them and pass to CallableWrapTTArgs + // TT needs actual types of arguments to func ... extract them and pass to CallableWrapTT using input_edge_value_types = ttg::meta::typelist...>; // input_args_t = {input_valuesT&&...} using input_args_t = typename ttg::meta::take_first_n< @@ -567,7 +567,7 @@ auto make_tt(funcT &&func, const std::tuple. using decayed_input_args_t = ttg::meta::decayed_typelist_t; // 3. full_input_args_t = edge-types with non-void types replaced by input_args_t using full_input_args_t = ttg::meta::replace_nonvoid_t; - using wrapT = typename CallableWrapTTArgsAsTypelist::type; return std::make_unique(std::forward(func), inedges, outedges, name, innames, outnames);