/**************************************************************************** * Copyright (c) 2017-2023 by the ArborX authors * * All rights reserved. * * * * This file is part of the ArborX library. ArborX is * * distributed under a BSD 3-clause license. For the licensing terms see * * the LICENSE file in the top-level directory. * * * * SPDX-License-Identifier: BSD-3-Clause * ****************************************************************************/ #ifndef ARBORX_CALLBACKS_HPP #define ARBORX_CALLBACKS_HPP #include #include // is_valid_predicate_tag #include #include #include namespace ArborX { enum class CallbackTreeTraversalControl { early_exit, normal_continuation }; namespace Details { struct PostCallbackTag {}; struct DefaultCallback { template KOKKOS_FUNCTION void operator()(Predicate const &, Value const &value, OutputFunctor const &out) const { out(value); } }; // archetypal alias for a 'tag' type member in user callbacks template using CallbackTagArchetypeAlias = typename Callback::tag; template struct is_tagged_post_callback : Kokkos::is_detected_exact::type {}; // output functor to pass to the callback during detection template struct Sink { KOKKOS_FUNCTION void operator()(T const &) const {} }; template using OutputFunctorHelper = Sink; template void check_generic_lambda_support(Callback const &) { #ifdef __NVCC__ // Without it would get a segmentation fault and no diagnostic whatsoever static_assert( !__nv_is_extended_host_device_lambda_closure_type(Callback), "__host__ __device__ extended lambdas cannot be generic lambdas"); #endif } template void check_valid_callback(Callback const &callback, Predicates const &, OutputView const &) { check_generic_lambda_support(callback); using Predicate = typename AccessValues::value_type; using PredicateTag = typename Predicate::Tag; static_assert(!(std::is_same_v && std::is_invocable_v>), R"error(Callback signature has changed for nearest predicates. See https://github.com/arborx/ArborX/pull/366 for more details. Sorry!)error"); static_assert(is_valid_predicate_tag::value && std::is_invocable_v>, "Callback 'operator()' does not have the correct signature"); static_assert( std::is_void_v>>, "Callback 'operator()' return type must be void"); } template KOKKOS_FUNCTION bool invoke_callback_and_check_early_exit(Callback &&callback, Predicate &&predicate, Primitive &&primitive) { if constexpr (std::is_same_v>) { // Invoke a callback that may return a hint to interrupt the tree traversal // and return true for early exit, or false for normal continuation. return ((Callback &&) callback)((Predicate &&) predicate, (Primitive &&) primitive) == CallbackTreeTraversalControl::early_exit; } else { // Invoke a callback that does not return a hint. Always return false to // signify that the tree traversal should continue normally. ((Callback &&) callback)((Predicate &&) predicate, (Primitive &&) primitive); return false; } } template void check_valid_callback(Callback const &callback, Predicates const &) { check_generic_lambda_support(callback); using Predicate = typename AccessValues::value_type; using PredicateTag = typename Predicate::Tag; static_assert(is_valid_predicate_tag::value, "The predicate tag is not valid"); static_assert(std::is_invocable_v, "Callback 'operator()' does not have the correct signature"); static_assert( !(std::is_same_v || std::is_same_v) || (std::is_same_v< CallbackTreeTraversalControl, std::invoke_result_t> || std::is_void_v< std::invoke_result_t>), "Callback 'operator()' return type must be void or " "ArborX::CallbackTreeTraversalControl"); static_assert( !std::is_same_v || std::is_void_v< std::invoke_result_t>, "Callback 'operator()' return type must be void"); } } // namespace Details } // namespace ArborX #endif