File indexing completed on 2025-01-18 09:11:10
0001
0002
0003
0004
0005
0006
0007
0008
0009 #pragma once
0010
0011 #include "Acts/Utilities/Delegate.hpp"
0012 #include "Acts/Utilities/TypeList.hpp"
0013
0014 #include <tuple>
0015 #include <type_traits>
0016 #include <utility>
0017
0018 namespace Acts {
0019
0020 template <typename Fn, typename payload_types = TypeList<>, auto... Callables>
0021 class DelegateChainBuilder;
0022
0023 template <typename R, typename... payload_types, auto... callables,
0024 typename... callable_args>
0025 class DelegateChainBuilder<R(callable_args...), TypeList<payload_types...>,
0026 callables...> {
0027 using return_type =
0028 std::conditional_t<std::is_same_v<R, void>, void,
0029 std::array<R, sizeof...(payload_types)>>;
0030 using delegate_type =
0031 Delegate<return_type(callable_args...), void, DelegateType::Owning>;
0032 using tuple_type = std::tuple<payload_types...>;
0033
0034 public:
0035 template <typename, typename Ps, auto... Cs>
0036 friend class DelegateChainBuilder;
0037
0038 DelegateChainBuilder() = default;
0039
0040 template <typename D>
0041 DelegateChainBuilder(const D& ) {}
0042
0043 template <auto Callable, typename payload_type>
0044 constexpr auto add(payload_type payload)
0045 requires(std::is_pointer_v<payload_type>)
0046 {
0047 std::tuple<payload_types..., payload_type> payloads =
0048 std::tuple_cat(m_payloads, std::make_tuple(payload));
0049
0050 return DelegateChainBuilder<R(callable_args...),
0051 TypeList<payload_types..., payload_type>,
0052 callables..., Callable>{payloads};
0053 }
0054
0055 template <auto Callable>
0056 constexpr auto add() {
0057 std::tuple<payload_types..., std::nullptr_t> payloads =
0058 std::tuple_cat(m_payloads, std::make_tuple(std::nullptr_t{}));
0059
0060 return DelegateChainBuilder<R(callable_args...),
0061 TypeList<payload_types..., std::nullptr_t>,
0062 callables..., Callable>{payloads};
0063 }
0064
0065 delegate_type build()
0066 requires(sizeof...(callables) > 0)
0067 {
0068 auto block = std::make_unique<const DispatchBlock>(m_payloads);
0069 delegate_type delegate;
0070 delegate.template connect<&DispatchBlock::dispatch>(std::move(block));
0071 return delegate;
0072 }
0073
0074 void store(delegate_type& delegate)
0075 requires(sizeof...(callables) > 0)
0076 {
0077 auto block = std::make_unique<const DispatchBlock>(m_payloads);
0078 delegate.template connect<&DispatchBlock::dispatch>(std::move(block));
0079 }
0080
0081 void store(Delegate<R(callable_args...)>& delegate)
0082 requires(sizeof...(callables) == 1)
0083 {
0084 constexpr auto callable =
0085 DispatchBlock::template findCallable<0, 0, callables...>();
0086 delegate.template connect<callable>(std::get<0>(m_payloads));
0087 }
0088
0089 private:
0090 DelegateChainBuilder(std::tuple<payload_types...> payloads)
0091 : m_payloads(payloads) {}
0092
0093 struct DispatchBlock {
0094 template <std::size_t I, std::size_t J, auto head, auto... tail>
0095 static constexpr auto findCallable() {
0096 if constexpr (I == J) {
0097 return head;
0098 } else {
0099 return findCallable<I, J + 1, tail...>();
0100 }
0101 }
0102
0103 template <std::size_t I = 0, typename result_ptr>
0104 static constexpr auto invoke(result_ptr result, const tuple_type* payloads,
0105 callable_args&&... args) {
0106 const auto& callable = findCallable<I, 0, callables...>();
0107
0108 if constexpr (!std::is_same_v<std::tuple_element_t<I, tuple_type>,
0109 std::nullptr_t>) {
0110 auto payload = std::get<I>(*payloads);
0111
0112 if constexpr (!std::is_same_v<result_ptr, std::nullptr_t>) {
0113 std::get<I>(*result) = std::invoke(
0114 callable, payload, std::forward<callable_args>(args)...);
0115 } else {
0116 std::invoke(callable, payload, std::forward<callable_args>(args)...);
0117 }
0118
0119 } else {
0120 if constexpr (!std::is_same_v<result_ptr, std::nullptr_t>) {
0121 std::get<I>(*result) =
0122 std::invoke(callable, std::forward<callable_args>(args)...);
0123 } else {
0124 std::invoke(callable, std::forward<callable_args>(args)...);
0125 }
0126 }
0127
0128 if constexpr (I < sizeof...(payload_types) - 1) {
0129 invoke<I + 1>(result, payloads, std::forward<callable_args>(args)...);
0130 }
0131 }
0132
0133 DispatchBlock(tuple_type payloads) : m_payloads(std::move(payloads)) {}
0134
0135 tuple_type m_payloads{};
0136
0137 auto dispatch(callable_args&&... args) const {
0138 if constexpr (std::is_same_v<R, void>) {
0139 invoke(nullptr, &m_payloads, std::forward<callable_args>(args)...);
0140 } else {
0141 static_assert(
0142 std::is_same_v<R, void> || std::is_default_constructible_v<R>,
0143 "Delegate chain return type must be void or default constructible");
0144 return_type result{};
0145 invoke(&result, &m_payloads, std::forward<callable_args>(args)...);
0146 return result;
0147 }
0148 }
0149 };
0150
0151 private:
0152 tuple_type m_payloads{};
0153 };
0154
0155 template <typename D>
0156 DelegateChainBuilder(const D& )
0157 -> DelegateChainBuilder<typename D::signature_type>;
0158
0159 }