libcamera  v0.3.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  * Method bind and invocation
6  */
7 
8 #pragma once
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() = default;
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  R returnValue()
42  {
43  return ret_;
44  }
45 
46  std::tuple<typename std::remove_reference_t<Args>...> args_;
47  R ret_;
48 };
49 
50 template<typename... Args>
51 class BoundMethodPack<void, Args...> : public BoundMethodPackBase
52 {
53 public:
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 
66 class BoundMethodBase
67 {
68 public:
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 
83 protected:
84  bool activatePack(std::shared_ptr<BoundMethodPackBase> pack,
85  bool deleteMethod);
86 
87  void *obj_;
88  Object *object_;
89 
90 private:
91  ConnectionType connectionType_;
92 };
93 
94 template<typename R, typename... Args>
95 class BoundMethodArgs : public BoundMethodBase
96 {
97 public:
98  using PackType = BoundMethodPack<R, Args...>;
99 
100 private:
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 
118 public:
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 
131 template<typename T, typename R, typename Func, typename... Args>
132 class BoundMethodFunctor : public BoundMethodArgs<R, Args...>
133 {
134 public:
135  using PackType = typename BoundMethodArgs<R, Args...>::PackType;
136 
137  BoundMethodFunctor(T *obj, Object *object, Func func,
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 
158 private:
159  Func func_;
160 };
161 
162 template<typename T, typename R, typename... Args>
163 class BoundMethodMember : public BoundMethodArgs<R, Args...>
164 {
165 public:
166  using PackType = typename BoundMethodArgs<R, Args...>::PackType;
167 
168  BoundMethodMember(T *obj, Object *object, R (T::*func)(Args...),
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 
194 private:
195  R (T::*func_)(Args...);
196 };
197 
198 template<typename R, typename... Args>
199 class BoundMethodStatic : public BoundMethodArgs<R, Args...>
200 {
201 public:
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 
220 private:
221  R (*func_)(Args...);
222 };
223 
224 } /* namespace libcamera */
ConnectionType
Connection type for asynchronous communication.
Definition: bound_method.h:19
Top-level libcamera namespace.
Definition: backtrace.h:17
The receiver is invoked synchronously.
Definition: bound_method.h:23
The receiver is invoked asynchronously.
Definition: bound_method.h:22
The receiver is invoked immediately and synchronously in the sender&#39;s thread.
Definition: bound_method.h:21
Base object to support automatic signal disconnection.
Definition: object.h:24
If the sender and the receiver live in the same thread, ConnectionTypeDirect is used. Otherwise ConnectionTypeQueued is used.
Definition: bound_method.h:20