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