libcamera v0.5.2
Supporting cameras in Linux since 2019
Loading...
Searching...
No Matches
bound_method.h
Go to the documentation of this file.
1/* SPDX-License-Identifier: LGPL-2.1-or-later */
2/*
3 * Copyright (C) 2019, Google Inc.
4 *
5 * Method bind and invocation
6 */
7
8#pragma once
9
10#include <memory>
11#include <tuple>
12#include <type_traits>
13#include <utility>
14
15namespace libcamera {
16
17class Object;
18
25
26class BoundMethodPackBase
27{
28public:
29 virtual ~BoundMethodPackBase() = default;
30};
31
32template<typename R, typename... Args>
33class BoundMethodPack : public BoundMethodPackBase
34{
35public:
36 template<typename... Ts>
37 BoundMethodPack(Ts &&...args)
38 : args_(std::forward<Ts>(args)...)
39 {
40 }
41
42 std::tuple<typename std::remove_reference_t<Args>...> args_;
43 R ret_;
44};
45
46template<typename... Args>
47class BoundMethodPack<void, Args...> : public BoundMethodPackBase
48{
49public:
50 template<typename... Ts>
51 BoundMethodPack(Ts &&...args)
52 : args_(std::forward<Ts>(args)...)
53 {
54 }
55
56 std::tuple<typename std::remove_reference_t<Args>...> args_;
57};
58
59class BoundMethodBase
60{
61public:
62 BoundMethodBase(void *obj, Object *object, ConnectionType type)
63 : obj_(obj), object_(object), connectionType_(type)
64 {
65 }
66 virtual ~BoundMethodBase() = default;
67
68 template<typename T, std::enable_if_t<!std::is_same<Object, T>::value> * = nullptr>
69 bool match(T *obj) { return obj == obj_; }
70 bool match(Object *object) { return object == object_; }
71
72 Object *object() const { return object_; }
73
74 virtual void invokePack(BoundMethodPackBase *pack) = 0;
75
76protected:
77 bool activatePack(std::shared_ptr<BoundMethodPackBase> pack,
78 bool deleteMethod);
79
80 void *obj_;
81 Object *object_;
82
83private:
84 ConnectionType connectionType_;
85};
86
87template<typename R, typename... Args>
88class BoundMethodArgs : public BoundMethodBase
89{
90public:
91 using PackType = BoundMethodPack<R, Args...>;
92
93private:
94 template<std::size_t... I>
95 void invokePack(BoundMethodPackBase *pack, std::index_sequence<I...>)
96 {
97 [[maybe_unused]] auto *args = static_cast<PackType *>(pack);
98
99 if constexpr (!std::is_void_v<R>)
100 args->ret_ = invoke(std::get<I>(args->args_)...);
101 else
102 invoke(std::get<I>(args->args_)...);
103 }
104
105public:
106 BoundMethodArgs(void *obj, Object *object, ConnectionType type)
107 : BoundMethodBase(obj, object, type) {}
108
109 void invokePack(BoundMethodPackBase *pack) override
110 {
111 invokePack(pack, std::make_index_sequence<sizeof...(Args)>{});
112 }
113
114 virtual R activate(Args... args, bool deleteMethod = false) = 0;
115 virtual R invoke(Args... args) = 0;
116};
117
118template<typename T, typename R, typename Func, typename... Args>
119class BoundMethodFunctor : public BoundMethodArgs<R, Args...>
120{
121public:
122 using PackType = typename BoundMethodArgs<R, Args...>::PackType;
123
124 BoundMethodFunctor(T *obj, Object *object, Func func,
126 : BoundMethodArgs<R, Args...>(obj, object, type), func_(std::move(func))
127 {
128 }
129
130 R activate(Args... args, bool deleteMethod = false) override
131 {
132 if (!this->object_)
133 return func_(std::forward<Args>(args)...);
134
135 auto pack = std::make_shared<PackType>(std::forward<Args>(args)...);
136 [[maybe_unused]] bool sync = BoundMethodBase::activatePack(pack, deleteMethod);
137
138 if constexpr (!std::is_void_v<R>)
139 return sync ? std::move(pack->ret_) : R();
140 }
141
142 R invoke(Args... args) override
143 {
144 return func_(std::forward<Args>(args)...);
145 }
146
147private:
148 Func func_;
149};
150
151template<typename T, typename R, typename... Args>
152class BoundMethodMember : public BoundMethodArgs<R, Args...>
153{
154public:
155 using PackType = typename BoundMethodArgs<R, Args...>::PackType;
156
157 BoundMethodMember(T *obj, Object *object, R (T::*func)(Args...),
159 : BoundMethodArgs<R, Args...>(obj, object, type), func_(func)
160 {
161 }
162
163 bool match(R (T::*func)(Args...)) const { return func == func_; }
164
165 R activate(Args... args, bool deleteMethod = false) override
166 {
167 if (!this->object_) {
168 T *obj = static_cast<T *>(this->obj_);
169 return (obj->*func_)(std::forward<Args>(args)...);
170 }
171
172 auto pack = std::make_shared<PackType>(std::forward<Args>(args)...);
173 [[maybe_unused]] bool sync = BoundMethodBase::activatePack(pack, deleteMethod);
174
175 if constexpr (!std::is_void_v<R>)
176 return sync ? std::move(pack->ret_) : R();
177 }
178
179 R invoke(Args... args) override
180 {
181 T *obj = static_cast<T *>(this->obj_);
182 return (obj->*func_)(std::forward<Args>(args)...);
183 }
184
185private:
186 R (T::*func_)(Args...);
187};
188
189template<typename R, typename... Args>
190class BoundMethodStatic : public BoundMethodArgs<R, Args...>
191{
192public:
193 BoundMethodStatic(R (*func)(Args...))
194 : BoundMethodArgs<R, Args...>(nullptr, nullptr, ConnectionTypeAuto),
195 func_(func)
196 {
197 }
198
199 bool match(R (*func)(Args...)) const { return func == func_; }
200
201 R activate(Args... args, [[maybe_unused]] bool deleteMethod = false) override
202 {
203 return (*func_)(std::forward<Args>(args)...);
204 }
205
206 R invoke(Args...) override
207 {
208 return R();
209 }
210
211private:
212 R (*func_)(Args...);
213};
214
215} /* namespace libcamera */
Top-level libcamera namespace.
Definition bound_method.h:15
ConnectionType
Connection type for asynchronous communication.
Definition bound_method.h:19
@ ConnectionTypeDirect
The receiver is invoked immediately and synchronously in the sender's thread.
Definition bound_method.h:21
@ ConnectionTypeBlocking
The receiver is invoked synchronously.
Definition bound_method.h:23
@ ConnectionTypeQueued
The receiver is invoked asynchronously.
Definition bound_method.h:22
@ ConnectionTypeAuto
If the sender and the receiver live in the same thread, ConnectionTypeDirect is used....
Definition bound_method.h:20