libcamera: include/libcamera/base/bound_method.h Source File

libcamera v0.0.1 Supporting cameras in Linux since 2019

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 * bound_method.h - 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
19 enum ConnectionType {
20 ConnectionTypeAuto,
21 ConnectionTypeDirect,
22 ConnectionTypeQueued,
23 ConnectionTypeBlocking,
24};
25
26class BoundMethodPackBase
27{
28public:
29 virtual ~BoundMethodPackBase() = default;
30};
31
32template<typename R, typename... Args>
33class BoundMethodPack : public BoundMethodPackBase
34{
35public:
36 BoundMethodPack(const Args &... args)
37 : args_(args...)
38 {
39 }
40
41 R returnValue()
42 {
43 return ret_;
44 }
45
46 std::tuple<typename std::remove_reference_t<Args>...> args_;
47 R ret_;
48};
49
50template<typename... Args>
51class BoundMethodPack<void, Args...> : public BoundMethodPackBase
52{
53public:
54 BoundMethodPack(const Args &... args)
55 : args_(args...)
56 {
57 }
58
59 void returnValue()
60 {
61 }
62
63 std::tuple<typename std::remove_reference_t<Args>...> args_;
64};
65
66class BoundMethodBase
67{
68public:
69 BoundMethodBase(void *obj, Object *object, ConnectionType type)
70 : obj_(obj), object_(object), connectionType_(type)
71 {
72 }
73 virtual ~BoundMethodBase() = default;
74
75 template<typename T, std::enable_if_t<!std::is_same<Object, T>::value> * = nullptr>
76 bool match(T *obj) { return obj == obj_; }
77 bool match(Object *object) { return object == object_; }
78
79 Object *object() const { return object_; }
80
81 virtual void invokePack(BoundMethodPackBase *pack) = 0;
82
83protected:
84 bool activatePack(std::shared_ptr<BoundMethodPackBase> pack,
85 bool deleteMethod);
86
87 void *obj_;
88 Object *object_;
89
90private:
91 ConnectionType connectionType_;
92};
93
94template<typename R, typename... Args>
95class BoundMethodArgs : public BoundMethodBase
96{
97public:
98 using PackType = BoundMethodPack<R, Args...>;
99
100private:
101 template<std::size_t... I, typename T = R>
102 std::enable_if_t<!std::is_void<T>::value, void>
103 invokePack(BoundMethodPackBase *pack, std::index_sequence<I...>)
104 {
105 PackType *args = static_cast<PackType *>(pack);
106 args->ret_ = invoke(std::get<I>(args->args_)...);
107 }
108
109 template<std::size_t... I, typename T = R>
110 std::enable_if_t<std::is_void<T>::value, void>
111 invokePack(BoundMethodPackBase *pack, std::index_sequence<I...>)
112 {
113 /* args is effectively unused when the sequence I is empty. */
114 PackType *args [[gnu::unused]] = static_cast<PackType *>(pack);
115 invoke(std::get<I>(args->args_)...);
116 }
117
118public:
119 BoundMethodArgs(void *obj, Object *object, ConnectionType type)
120 : BoundMethodBase(obj, object, type) {}
121
122 void invokePack(BoundMethodPackBase *pack) override
123 {
124 invokePack(pack, std::make_index_sequence<sizeof...(Args)>{});
125 }
126
127 virtual R activate(Args... args, bool deleteMethod = false) = 0;
128 virtual R invoke(Args... args) = 0;
129};
130
131template<typename T, typename R, typename Func, typename... Args>
132class BoundMethodFunctor : public BoundMethodArgs<R, Args...>
133{
134public:
135 using PackType = typename BoundMethodArgs<R, Args...>::PackType;
136
137 BoundMethodFunctor(T *obj, Object *object, Func func,
138 ConnectionType type = ConnectionTypeAuto)
139 : BoundMethodArgs<R, Args...>(obj, object, type), func_(func)
140 {
141 }
142
143 R activate(Args... args, bool deleteMethod = false) override
144 {
145 if (!this->object_)
146 return func_(args...);
147
148 auto pack = std::make_shared<PackType>(args...);
149 bool sync = BoundMethodBase::activatePack(pack, deleteMethod);
150 return sync ? pack->returnValue() : R();
151 }
152
153 R invoke(Args... args) override
154 {
155 return func_(args...);
156 }
157
158private:
159 Func func_;
160};
161
162template<typename T, typename R, typename... Args>
163class BoundMethodMember : public BoundMethodArgs<R, Args...>
164{
165public:
166 using PackType = typename BoundMethodArgs<R, Args...>::PackType;
167
168 BoundMethodMember(T *obj, Object *object, R (T::*func)(Args...),
169 ConnectionType type = ConnectionTypeAuto)
170 : BoundMethodArgs<R, Args...>(obj, object, type), func_(func)
171 {
172 }
173
174 bool match(R (T::*func)(Args...)) const { return func == func_; }
175
176 R activate(Args... args, bool deleteMethod = false) override
177 {
178 if (!this->object_) {
179 T *obj = static_cast<T *>(this->obj_);
180 return (obj->*func_)(args...);
181 }
182
183 auto pack = std::make_shared<PackType>(args...);
184 bool sync = BoundMethodBase::activatePack(pack, deleteMethod);
185 return sync ? pack->returnValue() : R();
186 }
187
188 R invoke(Args... args) override
189 {
190 T *obj = static_cast<T *>(this->obj_);
191 return (obj->*func_)(args...);
192 }
193
194private:
195 R (T::*func_)(Args...);
196};
197
198template<typename R, typename... Args>
199class BoundMethodStatic : public BoundMethodArgs<R, Args...>
200{
201public:
202 BoundMethodStatic(R (*func)(Args...))
203 : BoundMethodArgs<R, Args...>(nullptr, nullptr, ConnectionTypeAuto),
204 func_(func)
205 {
206 }
207
208 bool match(R (*func)(Args...)) const { return func == func_; }
209
210 R activate(Args... args, [[maybe_unused]] bool deleteMethod = false) override
211 {
212 return (*func_)(args...);
213 }
214
215 R invoke(Args...) override
216 {
217 return R();
218 }
219
220private:
221 R (*func_)(Args...);
222};
223
224} /* namespace libcamera */
libcamera
Top-level libcamera namespace.
Definition: backtrace.h:17
libcamera::ConnectionType
ConnectionType
Connection type for asynchronous communication.
Definition: bound_method.h:19
libcamera::ConnectionTypeQueued
@ ConnectionTypeQueued
The receiver is invoked asynchronously.
Definition: bound_method.h:22
libcamera::ConnectionTypeDirect
@ ConnectionTypeDirect
The receiver is invoked immediately and synchronously in the sender's thread.
Definition: bound_method.h:21
libcamera::ConnectionTypeAuto
@ ConnectionTypeAuto
If the sender and the receiver live in the same thread, ConnectionTypeDirect is used....
Definition: bound_method.h:20
libcamera::ConnectionTypeBlocking
@ ConnectionTypeBlocking
The receiver is invoked synchronously.
Definition: bound_method.h:23