1+ // NOLINTBEGIN(readability-identifier-naming)
12// SPDX-FileCopyrightText: 2026 CExA-project
23// SPDX-License-Identifier: MIT or Apache-2.0 with LLVM-exception
34#pragma once
910#include " traits.hpp"
1011#include " tuple.hpp"
1112
13+ #ifdef CEXA_HAS_CXX23
14+ # include < functional>
15+ #endif
16+
1217namespace cexa {
1318
1419namespace impl {
@@ -18,102 +23,137 @@ template <class U>
1823constexpr bool is_reference_wrapper_v<std::reference_wrapper<U>> = true ;
1924
2025template <class C , class Pointed , class Object , class ... Args>
21- KOKKOS_INLINE_FUNCTION constexpr decltype (auto ) invoke_ptr(Pointed C::* member,
22- Object&& object,
23- Args&&... args) {
24- using object_t = remove_cvref_t <Object>;
25- constexpr bool is_wrapped = is_reference_wrapper_v<object_t >;
26- constexpr bool is_derived_object =
27- std::is_same_v<C, object_t > || std::is_base_of_v<C, object_t >;
28-
29- if constexpr (std::is_function_v<Pointed>) {
30- if constexpr (is_derived_object) {
31- return (std::forward<Object>(object).*
32- member)(std::forward<Args>(args)...);
33- } else if constexpr (is_wrapped) {
34- return (object.get ().*member)(std::forward<Args>(args)...);
35- } else {
36- return ((*std::forward<Object>(object)).*
37- member)(std::forward<Args>(args)...);
38- }
39- } else {
40- static_assert (std::is_object_v<Pointed> && sizeof ...(args) == 0 );
41- if constexpr (is_derived_object) {
42- return std::forward<Object>(object).*member;
43- } else if constexpr (is_wrapped) {
44- return object.get ().*member;
26+ KOKKOS_INLINE_FUNCTION constexpr decltype (auto ) invoke_ptr(
27+ Pointed C::*member,
28+ Object&& object,
29+ Args&&... args)
30+ {
31+ using object_t = std::remove_cvref_t <Object>;
32+ constexpr bool is_wrapped = is_reference_wrapper_v<object_t >;
33+ constexpr bool is_derived_object
34+ = std::is_same_v<C, object_t > || std::is_base_of_v<C, object_t >;
35+
36+ if constexpr (std::is_function_v<Pointed>) {
37+ if constexpr (is_derived_object) {
38+ return (std::forward<Object>(object).*member)(std::forward<Args>(args)...);
39+ } else if constexpr (is_wrapped) {
40+ return (object.get ().*member)(std::forward<Args>(args)...);
41+ } else {
42+ return ((*std::forward<Object>(object)).*member)(std::forward<Args>(args)...);
43+ }
4544 } else {
46- return (*std::forward<Object>(object)).*member;
45+ static_assert (std::is_object_v<Pointed> && sizeof ...(args) == 0 );
46+ if constexpr (is_derived_object) {
47+ return std::forward<Object>(object).*member;
48+ } else if constexpr (is_wrapped) {
49+ return object.get ().*member;
50+ } else {
51+ return (*std::forward<Object>(object)).*member;
52+ }
4753 }
48- }
4954}
5055
56+ // f may be a host function
57+ CEXA_NVCC_HOST_DEVICE_CHECK_DISABLE
5158template <class F , class ... Args>
52- KOKKOS_INLINE_FUNCTION constexpr decltype (auto ) invoke(F&& f, Args&&... args) {
53- if constexpr (std::is_member_pointer_v<remove_cvref_t <F>>) {
54- return invoke_ptr (f, std::forward<Args>(args)...);
55- } else {
56- return (std::forward<F>(f))(std::forward<Args>(args)...);
57- }
59+ KOKKOS_INLINE_FUNCTION constexpr decltype (auto ) invoke(F&& f, Args&&... args)
60+ {
61+ if constexpr (std::is_member_pointer_v<std::remove_cvref_t <F>>) {
62+ return invoke_ptr (f, std::forward<Args>(args)...);
63+ } else {
64+ return (std::forward<F>(f))(std::forward<Args>(args)...);
65+ }
5866}
5967
6068template <class F , class Tuple , std::size_t ... I>
61- KOKKOS_INLINE_FUNCTION constexpr decltype (auto ) apply(
62- F&& f, Tuple&& t, std::index_sequence<I...>) {
63- return invoke (std::forward<F>(f), cexa::get<I>(std::forward<Tuple>(t))...);
69+ KOKKOS_INLINE_FUNCTION constexpr decltype (auto ) apply(F&& f, Tuple&& t, std::index_sequence<I...>)
70+ {
71+ return invoke (std::forward<F>(f), cexa::get<I>(std::forward<Tuple>(t))...);
6472}
6573
74+ // This might call a host only constructor
75+ CEXA_NVCC_HOST_DEVICE_CHECK_DISABLE
6676template <class T , class Tuple , std::size_t ... I>
67- KOKKOS_INLINE_FUNCTION constexpr T make_from_tuple (Tuple&& t,
68- std::index_sequence<I...>) {
69- return T (cexa::get<I>(std::forward<Tuple>(t))...);
77+ KOKKOS_INLINE_FUNCTION constexpr T make_from_tuple (Tuple&& t, std::index_sequence<I...>)
78+ {
79+ return T (cexa::get<I>(std::forward<Tuple>(t))...);
7080}
7181
72- template <class U , class T , std::size_t = tuple_size_v<impl::remove_cvref_t <T>>>
73- struct make_tuple_constraint : std::true_type {};
82+ template <class U , class T , std::size_t = tuple_size_v<std::remove_cvref_t <T>>>
83+ struct make_tuple_constraint : std::true_type
84+ {
85+ };
7486
7587template <class U , class Tuple >
76- struct make_tuple_constraint <U, Tuple, 1 > {
77- static constexpr bool value = !impl::reference_constructs_from_temporary_v<
78- U, decltype (get<0 >(std::declval<Tuple>()))>;
88+ struct make_tuple_constraint <U, Tuple, 1 >
89+ {
90+ static constexpr bool value = !impl::reference_constructs_from_temporary_v<
91+ U,
92+ decltype (get<0 >(std::declval<Tuple>()))>;
7993};
8094
81- template <class T , class Tuple , class seq >
95+ template <class T , class Tuple , class Seq >
8296struct is_constructible_from_tuple ;
8397
8498template <class T , class Tuple , std::size_t ... Ints>
85- struct is_constructible_from_tuple <T, Tuple, std::index_sequence<Ints...>> {
86- static constexpr bool value =
87- std::is_constructible_v<T, decltype (get<Ints>(std::declval<Tuple>()))...>;
99+ struct is_constructible_from_tuple <T, Tuple, std::index_sequence<Ints...>>
100+ {
101+ static constexpr bool value
102+ = std::is_constructible_v<T, decltype (get<Ints>(std::declval<Tuple>()))...>;
88103};
89104
90105template <class T , class Tuple >
91- inline constexpr bool is_constructible_from_tuple_v =
92- is_constructible_from_tuple<T, Tuple,
93- std::make_index_sequence<tuple_size_v<
94- impl::remove_cvref_t <Tuple>>>>::value;
106+ inline constexpr bool is_constructible_from_tuple_v = is_constructible_from_tuple<
107+ T,
108+ Tuple,
109+ std::make_index_sequence<tuple_size_v<std::remove_cvref_t <Tuple>>>>::value;
110+
111+ #ifdef CEXA_HAS_CXX23
112+ template <class F , class Tuple , class Other >
113+ struct is_nothrow_applicable : std::false_type
114+ {
115+ };
95116
96- } // namespace impl
117+ template <class F , class Tuple , std::size_t ... Is>
118+ struct is_nothrow_applicable <F, Tuple, std::index_sequence<Is...>>
119+ {
120+ static constexpr bool value
121+ = noexcept (std::invoke(std::declval<F>(), get<Is>(std::declval<Tuple>())...));
122+ };
97123
98124template <class F , class Tuple >
99- KOKKOS_INLINE_FUNCTION constexpr decltype (auto ) apply(F&& f, Tuple&& t) {
100- static_assert (impl::is_tuple_v<impl::remove_cvref_t <Tuple>>,
101- " cexa::apply can only be called with cexa::tuple" );
102- return impl::apply (
103- std::forward<F>(f), std::forward<Tuple>(t),
104- std::make_index_sequence<tuple_size_v<std::remove_reference_t <Tuple>>>{});
125+ constexpr bool is_nothrow_applicable_v = is_nothrow_applicable<
126+ F,
127+ Tuple,
128+ decltype (std::make_index_sequence<tuple_size_v<std::remove_cvref_t <Tuple>>> {})>::value;
129+ #endif
130+ } // namespace impl
131+
132+ template <class F , class Tuple >
133+ KOKKOS_INLINE_FUNCTION constexpr decltype (auto ) apply(F&& f, Tuple&& t)
134+ #ifdef CEXA_HAS_CXX23
135+ noexcept (impl::is_nothrow_applicable_v<F, Tuple>)
136+ #endif
137+ {
138+ static_assert (
139+ impl::is_tuple_v<std::remove_cvref_t <Tuple>>,
140+ " cexa::apply can only be called with cexa::tuple" );
141+ return impl::
142+ apply (std::forward<F>(f),
143+ std::forward<Tuple>(t),
144+ std::make_index_sequence<tuple_size_v<std::remove_reference_t <Tuple>>> {});
105145}
106146
107- template <
108- class T , class Tuple ,
109- class = std::enable_if_t <impl::is_constructible_from_tuple_v<T, Tuple>>>
110- KOKKOS_INLINE_FUNCTION constexpr T make_from_tuple (Tuple&& t) {
111- static_assert (impl::is_tuple_v<impl::remove_cvref_t <Tuple>>,
112- " cexa::make_from_tuple can only be called with cexa::tuple" );
113- constexpr std::size_t size = tuple_size_v<std::remove_reference_t <Tuple>>;
114- static_assert (
115- impl::make_tuple_constraint<T, impl::remove_cvref_t <Tuple>>::value);
116- return impl::make_from_tuple<T>(std::forward<Tuple>(t),
117- std::make_index_sequence<size>{});
147+ template <class T , class Tuple >
148+ requires impl::is_constructible_from_tuple_v<T, Tuple>
149+ KOKKOS_INLINE_FUNCTION constexpr T make_from_tuple (Tuple&& t)
150+ {
151+ static_assert (
152+ impl::is_tuple_v<std::remove_cvref_t <Tuple>>,
153+ " cexa::make_from_tuple can only be called with cexa::tuple" );
154+ constexpr std::size_t size = tuple_size_v<std::remove_reference_t <Tuple>>;
155+ static_assert (impl::make_tuple_constraint<T, std::remove_cvref_t <Tuple>>::value);
156+ return impl::make_from_tuple<T>(std::forward<Tuple>(t), std::make_index_sequence<size> {});
118157}
119- } // namespace cexa
158+ } // namespace cexa
159+ // NOLINTEND(readability-identifier-naming)
0 commit comments