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/Concepts.hpp"
0012
0013 #include <cassert>
0014 #include <functional>
0015 #include <memory>
0016 #include <type_traits>
0017
0018 namespace Acts {
0019
0020 enum class DelegateType { Owning, NonOwning };
0021
0022 template <auto C>
0023 struct DelegateFuncTag {
0024 explicit constexpr DelegateFuncTag() = default;
0025 };
0026
0027
0028 template <typename, typename H = void, DelegateType = DelegateType::NonOwning>
0029 class Delegate;
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045 template <typename R, typename H, DelegateType O, typename... Args>
0046 class Delegate<R(Args...), H, O> {
0047 public:
0048 static constexpr DelegateType kOwnership = O;
0049
0050
0051 using return_type = R;
0052 using holder_type = H;
0053 using function_type = return_type (*)(const holder_type *, Args...);
0054 using function_ptr_type = return_type (*)(Args...);
0055 using signature_type = R(Args...);
0056
0057 using deleter_type = void (*)(const holder_type *);
0058
0059 private:
0060 template <typename T, typename C>
0061 using isSignatureCompatible =
0062 decltype(std::declval<T &>() = std::declval<C>());
0063
0064 using OwningDelegate =
0065 Delegate<R(Args...), holder_type, DelegateType::Owning>;
0066 using NonOwningDelegate =
0067 Delegate<R(Args...), holder_type, DelegateType::NonOwning>;
0068
0069 template <typename T>
0070 using isNoFunPtr = std::conjunction<
0071 std::negation<std::is_convertible<std::decay_t<T>, function_type>>,
0072 std::negation<std::is_same<std::decay_t<T>, OwningDelegate>>,
0073 std::negation<std::is_same<std::decay_t<T>, NonOwningDelegate>>>;
0074
0075 public:
0076 Delegate() = default;
0077
0078 Delegate(Delegate &&) noexcept = default;
0079 Delegate &operator=(Delegate &&) noexcept = default;
0080 Delegate(const Delegate &) noexcept = default;
0081 Delegate &operator=(const Delegate &) noexcept = default;
0082
0083
0084
0085
0086
0087
0088
0089 explicit Delegate(function_type callable) { connect(callable); }
0090
0091
0092
0093
0094
0095
0096
0097 template <typename Callable>
0098 explicit Delegate(Callable &callable)
0099 requires(isNoFunPtr<Callable>::value)
0100 {
0101 connect(callable);
0102 }
0103
0104
0105
0106
0107 template <auto Callable>
0108 explicit Delegate(DelegateFuncTag<Callable> ) {
0109 connect<Callable>();
0110 }
0111
0112
0113
0114
0115
0116
0117
0118 template <auto Callable, typename Type>
0119
0120 Delegate(DelegateFuncTag<Callable> , const Type *instance)
0121 requires(kOwnership == DelegateType::NonOwning)
0122 {
0123 connect<Callable>(instance);
0124 }
0125
0126
0127
0128 template <typename Callable>
0129 Delegate(Callable &&)
0130 requires(isNoFunPtr<Callable>::value)
0131 = delete;
0132
0133
0134
0135
0136
0137
0138
0139 void operator=(function_type callable) { connect(callable); }
0140
0141
0142
0143
0144
0145
0146 template <typename Callable>
0147 void operator=(Callable &callable)
0148 requires(isNoFunPtr<Callable>::value)
0149 {
0150 connect(callable);
0151 }
0152
0153
0154
0155
0156 template <typename Callable>
0157 void operator=(Callable &&)
0158 requires(isNoFunPtr<Callable>::value)
0159 = delete;
0160
0161
0162
0163
0164
0165 template <auto Callable>
0166 void connect()
0167 requires(
0168 Concepts::invocable_and_returns<Callable, return_type, Args && ...>)
0169 {
0170 m_payload.payload = nullptr;
0171
0172 static_assert(
0173 Concepts::invocable_and_returns<Callable, return_type, Args &&...>,
0174 "Callable given does not correspond exactly to required call "
0175 "signature");
0176
0177 m_function = [](const holder_type * ,
0178 Args... args) -> return_type {
0179 return std::invoke(Callable, std::forward<Args>(args)...);
0180 };
0181 }
0182
0183
0184
0185
0186
0187
0188
0189 template <typename Callable>
0190 void connect(Callable &callable)
0191 requires(isNoFunPtr<Callable>::value)
0192 {
0193 connect<&Callable::operator(), Callable>(&callable);
0194 }
0195
0196
0197
0198 template <typename Callable>
0199 void connect(Callable &&)
0200 requires(isNoFunPtr<Callable>::value)
0201 = delete;
0202
0203
0204
0205
0206
0207
0208
0209 void connect(function_type callable) {
0210 if constexpr (kOwnership == DelegateType::NonOwning) {
0211 m_payload.payload = nullptr;
0212 }
0213 m_function = callable;
0214 }
0215
0216
0217 template <typename Type>
0218 void connect(function_type callable, const Type *instance)
0219 requires(kOwnership == DelegateType::NonOwning)
0220 {
0221 m_payload.payload = instance;
0222 m_function = callable;
0223 }
0224
0225
0226
0227
0228
0229
0230
0231 template <auto Callable, typename Type>
0232 void connect(const Type *instance)
0233 requires(kOwnership == DelegateType::NonOwning &&
0234 Concepts::invocable_and_returns<Callable, return_type, Type,
0235 Args && ...>)
0236
0237 {
0238 m_payload.payload = instance;
0239
0240 m_function = [](const holder_type *payload, Args... args) -> return_type {
0241 assert(payload != nullptr && "Payload is required, but not set");
0242 const auto *concretePayload = static_cast<const Type *>(payload);
0243 return std::invoke(Callable, concretePayload,
0244 std::forward<Args>(args)...);
0245 };
0246 }
0247
0248
0249
0250
0251
0252
0253 template <auto Callable, typename Type>
0254 void connect(std::unique_ptr<const Type> instance)
0255 requires(kOwnership == DelegateType::Owning &&
0256 Concepts::invocable_and_returns<Callable, return_type, Type,
0257 Args && ...>)
0258 {
0259 m_payload.payload = std::unique_ptr<const holder_type, deleter_type>(
0260 instance.release(), [](const holder_type *payload) {
0261 const auto *concretePayload = static_cast<const Type *>(payload);
0262 delete concretePayload;
0263 });
0264
0265 m_function = [](const holder_type *payload, Args &&...args) -> return_type {
0266 assert(payload != nullptr && "Payload is required, but not set");
0267 const auto *concretePayload = static_cast<const Type *>(payload);
0268 return std::invoke(Callable, concretePayload,
0269 std::forward<Args>(args)...);
0270 };
0271 }
0272
0273
0274
0275
0276 template <typename... Ts>
0277 return_type operator()(Ts &&...args) const
0278 requires(std::is_invocable_v<function_type, const holder_type *, Ts...>)
0279 {
0280 assert(connected() && "Delegate is not connected");
0281 return std::invoke(m_function, m_payload.ptr(), std::forward<Ts>(args)...);
0282 }
0283
0284
0285
0286 bool connected() const { return m_function != nullptr; }
0287
0288
0289
0290 explicit operator bool() const { return connected(); }
0291
0292
0293 void disconnect() {
0294 m_payload.clear();
0295 m_function = nullptr;
0296 }
0297
0298 const holder_type *instance() const
0299 requires(!std::same_as<holder_type, void>)
0300 {
0301 return m_payload.ptr();
0302 }
0303
0304 private:
0305
0306 static void noopDeleter(const holder_type * ) {
0307
0308 }
0309
0310
0311
0312
0313 struct NonOwningPayload {
0314 void clear() { payload = nullptr; }
0315
0316 const holder_type *ptr() const { return payload; }
0317
0318 const holder_type *payload{nullptr};
0319 };
0320
0321
0322 struct OwningPayload {
0323 void clear() { payload.reset(); }
0324
0325 const holder_type *ptr() const { return payload.get(); }
0326
0327 std::unique_ptr<const holder_type, deleter_type> payload{nullptr,
0328 &noopDeleter};
0329 };
0330
0331
0332 std::conditional_t<kOwnership == DelegateType::NonOwning, NonOwningPayload,
0333 OwningPayload>
0334 m_payload;
0335
0336
0337
0338
0339 function_type m_function{nullptr};
0340 };
0341
0342 template <typename, typename H = void>
0343 class OwningDelegate;
0344
0345
0346 template <typename R, typename H, typename... Args>
0347 class OwningDelegate<R(Args...), H>
0348 : public Delegate<R(Args...), H, DelegateType::Owning> {
0349 public:
0350 OwningDelegate() = default;
0351 OwningDelegate(Delegate<R(Args...), H, DelegateType::Owning> &&delegate)
0352 : Delegate<R(Args...), H, DelegateType::Owning>(std::move(delegate)) {}
0353 };
0354
0355 }