]> git.ipfire.org Git - thirdparty/squid.git/blame - src/base/AsyncCallbacks.h
Source Format Enforcement (#1234)
[thirdparty/squid.git] / src / base / AsyncCallbacks.h
CommitLineData
e5ddd4ce 1/*
b8ae064d 2 * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
e5ddd4ce
AR
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
9#ifndef SQUID_SRC_BASE_ASYNCCALLBACKS_H
10#define SQUID_SRC_BASE_ASYNCCALLBACKS_H
11
12#include "base/AsyncCall.h"
13#include "base/AsyncJobCalls.h"
14#include "base/TypeTraits.h"
15
16/// access to a callback result carried by an asynchronous CallDialer
17template <typename AnswerT>
18class WithAnswer
19{
20public:
21 using Answer = AnswerT;
22
23 virtual ~WithAnswer() = default;
24
25 /// callback results setter
26 virtual Answer &answer() = 0;
27};
28
29/// a smart AsyncCall pointer for delivery of future results
30template <typename Answer>
31class AsyncCallback
32{
33public:
34 // all generated copying/moving functions are correct
35 AsyncCallback() = default;
36
37 template <class Call>
38 explicit AsyncCallback(const RefCount<Call> &call):
39 call_(call),
40 answer_(&(call->dialer.answer()))
41 {
42 }
43
44 Answer &answer()
45 {
46 assert(answer_);
47 return *answer_;
48 }
49
50 /// make this smart pointer nil
51 /// \return the AsyncCall pointer we used to manage before this call
52 AsyncCall::Pointer release()
53 {
54 answer_ = nullptr;
55 const auto call = call_;
56 call_ = nullptr;
57 return call;
58 }
59
60 /// whether the callback has been set but not released
61 explicit operator bool() const { return answer_; }
62
63 /* methods for decaying into an AsyncCall pointer w/o access to answer */
64 operator const AsyncCall::Pointer &() const { return call_; }
65 const AsyncCall &operator *() const { return call_.operator*(); }
66 const AsyncCall *operator ->() const { return call_.operator->(); }
67
68private:
69 /// callback carrying the answer
70 AsyncCall::Pointer call_;
71
72 /// (future) answer inside this->call, obtained when it was still possible
73 /// to reach it without dynamic casts and virtual methods
74 Answer *answer_ = nullptr;
75};
76
77/// CallDialer for single-parameter callback functions
78template <typename Argument1>
79class UnaryFunCallbackDialer:
80 public CallDialer,
81 public WithAnswer<Argument1>
82{
83public:
84 // stand-alone function that receives our answer
85 using Handler = void (Argument1 &);
86
87 explicit UnaryFunCallbackDialer(Handler * const aHandler): handler(aHandler) {}
337b9aa4 88 ~UnaryFunCallbackDialer() override = default;
e5ddd4ce
AR
89
90 /* CallDialer API */
91 bool canDial(AsyncCall &) { return bool(handler); }
92 void dial(AsyncCall &) { handler(arg1); }
337b9aa4 93 void print(std::ostream &os) const final { os << '(' << arg1 << ')'; }
e5ddd4ce
AR
94
95 /* WithAnswer API */
337b9aa4 96 Argument1 &answer() final { return arg1; }
e5ddd4ce
AR
97
98private:
99 Handler *handler; ///< the function to call
100 Argument1 arg1; ///< actual call parameter
101};
102
103/// CallDialer for single-parameter callback methods of cbdata-protected classes
104/// that are not AsyncJobs (use UnaryJobCallbackDialer for the latter).
105template <class Destination, typename Argument1>
106class UnaryCbcCallbackDialer:
107 public CallDialer,
108 public WithAnswer<Argument1>
109{
110public:
111 // class member function that receives our answer
112 typedef void (Destination::*Method)(Argument1 &);
113
114 UnaryCbcCallbackDialer(Method method, Destination *destination): destination_(destination), method_(method) {}
337b9aa4 115 ~UnaryCbcCallbackDialer() override = default;
e5ddd4ce
AR
116
117 /* CallDialer API */
118 bool canDial(AsyncCall &) { return destination_.valid(); }
119 void dial(AsyncCall &) {((*destination_).*method_)(arg1_); }
337b9aa4 120 void print(std::ostream &os) const final { os << '(' << arg1_ << ')'; }
e5ddd4ce
AR
121
122 /* WithAnswer API */
337b9aa4 123 Argument1 &answer() final { return arg1_; }
e5ddd4ce
AR
124
125private:
126 CbcPointer<Destination> destination_; ///< object to deliver the answer to
127 Method method_; ///< Destination method to call with the answer
128 Argument1 arg1_;
129};
130
131/// CallDialer for single-parameter callback methods of AsyncJob classes.
132/// \sa UnaryCbcCallbackDialer and UnaryFunCallbackDialer.
133template <class Job, typename Argument1>
134class UnaryJobCallbackDialer:
135 public UnaryMemFunT<Job, Argument1, Argument1&>,
136 public WithAnswer<Argument1>
137{
138public:
139 using Base = UnaryMemFunT<Job, Argument1, Argument1&>;
140
141 UnaryJobCallbackDialer(const CbcPointer<Job> &aJob, typename Base::Method aMethod):
142 Base(aJob, aMethod, {}) {}
143
144 /* WithAnswer API */
337b9aa4 145 Argument1 &answer() final { return this->arg1; }
e5ddd4ce
AR
146};
147
148/// whether the given type is an AsyncJob
149/// reduces code duplication in declarations further below
150template <typename T>
151using IsAsyncJob = typename std::conditional<
152 std::is_base_of<AsyncJob, T>::value,
153 std::true_type,
154 std::false_type
155 >::type;
156
157/// helper function to simplify UnaryCbcCallbackDialer creation
09835feb 158template <class Destination, typename Argument1, std::enable_if_t<!IsAsyncJob<Destination>::value, int> = 0>
e5ddd4ce
AR
159UnaryCbcCallbackDialer<Destination, Argument1>
160callbackDialer(void (Destination::*method)(Argument1 &), Destination * const destination)
161{
162 static_assert(!std::is_base_of<AsyncJob, Destination>::value, "wrong wrapper");
163 return UnaryCbcCallbackDialer<Destination, Argument1>(method, destination);
164}
165
166/// helper function to simplify UnaryJobCallbackDialer creation
09835feb 167template <class Destination, typename Argument1, std::enable_if_t<IsAsyncJob<Destination>::value, int> = 0>
e5ddd4ce
AR
168UnaryJobCallbackDialer<Destination, Argument1>
169callbackDialer(void (Destination::*method)(Argument1 &), Destination * const destination)
170{
171 static_assert(std::is_base_of<AsyncJob, Destination>::value, "wrong wrapper");
172 return UnaryJobCallbackDialer<Destination, Argument1>(destination, method);
173}
174
175/// helper function to simplify UnaryFunCallbackDialer creation
176template <typename Argument1>
177UnaryFunCallbackDialer<Argument1>
178callbackDialer(void (*destination)(Argument1 &))
179{
180 return UnaryFunCallbackDialer<Argument1>(destination);
181}
182
183/// helper function to create an AsyncCallback object that matches an AsyncCall
184/// based on a WithAnswer answer dialer.
185template <class Call>
186AsyncCallback<typename Call::Dialer::Answer>
187AsyncCallback_(const RefCount<Call> &call)
188{
189 return AsyncCallback<typename Call::Dialer::Answer>(call);
190}
191
192/// AsyncCall for calling back a class method compatible with
193/// callbackDialer(). TODO: Unify with JobCallback() which requires dialers
194/// that feed the job pointer to the non-default CommCommonCbParams constructor.
195#define asyncCallback(dbgSection, dbgLevel, method, object) \
196 AsyncCallback_(asyncCall((dbgSection), (dbgLevel), #method, \
197 callbackDialer(&method, (object))))
198
199// TODO: Use C++20 __VA_OPT__ to merge this with asyncCallback().
200/// AsyncCall for calling back a function
201#define asyncCallbackFun(dbgSection, dbgLevel, function) \
202 AsyncCallback_(asyncCall((dbgSection), (dbgLevel), #function, \
203 callbackDialer(&function)))
204
205#endif // SQUID_SRC_BASE_ASYNCCALLBACKS_H
206