libcamera  v0.2.0+137-a2a61121
Supporting cameras in Linux since 2019
signal.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  * Signal & slot implementation
6  */
7 
8 #pragma once
9 
10 #include <functional>
11 #include <list>
12 #include <type_traits>
13 #include <vector>
14 
16 
17 namespace libcamera {
18 
19 class Object;
20 
21 class SignalBase
22 {
23 public:
24  void disconnect(Object *object);
25 
26 protected:
27  using SlotList = std::list<BoundMethodBase *>;
28 
29  void connect(BoundMethodBase *slot);
30  void disconnect(std::function<bool(SlotList::iterator &)> match);
31 
32  SlotList slots();
33 
34 private:
35  SlotList slots_;
36 };
37 
38 template<typename... Args>
39 class Signal : public SignalBase
40 {
41 public:
42  ~Signal()
43  {
44  disconnect();
45  }
46 
47 #ifndef __DOXYGEN__
48  template<typename T, typename R, std::enable_if_t<std::is_base_of<Object, T>::value> * = nullptr>
49  void connect(T *obj, R (T::*func)(Args...),
51  {
52  Object *object = static_cast<Object *>(obj);
53  SignalBase::connect(new BoundMethodMember<T, R, Args...>(obj, object, func, type));
54  }
55 
56  template<typename T, typename R, std::enable_if_t<!std::is_base_of<Object, T>::value> * = nullptr>
57 #else
58  template<typename T, typename R>
59 #endif
60  void connect(T *obj, R (T::*func)(Args...))
61  {
62  SignalBase::connect(new BoundMethodMember<T, R, Args...>(obj, nullptr, func));
63  }
64 
65 #ifndef __DOXYGEN__
66  template<typename T, typename Func,
67  std::enable_if_t<std::is_base_of<Object, T>::value
68 #if __cplusplus >= 201703L
69  && std::is_invocable_v<Func, Args...>
70 #endif
71  > * = nullptr>
72  void connect(T *obj, Func func, ConnectionType type = ConnectionTypeAuto)
73  {
74  Object *object = static_cast<Object *>(obj);
75  SignalBase::connect(new BoundMethodFunctor<T, void, Func, Args...>(obj, object, func, type));
76  }
77 
78  template<typename T, typename Func,
79  std::enable_if_t<!std::is_base_of<Object, T>::value
80 #if __cplusplus >= 201703L
81  && std::is_invocable_v<Func, Args...>
82 #endif
83  > * = nullptr>
84 #else
85  template<typename T, typename Func>
86 #endif
87  void connect(T *obj, Func func)
88  {
89  SignalBase::connect(new BoundMethodFunctor<T, void, Func, Args...>(obj, nullptr, func));
90  }
91 
92  template<typename R>
93  void connect(R (*func)(Args...))
94  {
95  SignalBase::connect(new BoundMethodStatic<R, Args...>(func));
96  }
97 
98  void disconnect()
99  {
100  SignalBase::disconnect([]([[maybe_unused]] SlotList::iterator &iter) {
101  return true;
102  });
103  }
104 
105  template<typename T>
106  void disconnect(T *obj)
107  {
108  SignalBase::disconnect([obj](SlotList::iterator &iter) {
109  return (*iter)->match(obj);
110  });
111  }
112 
113  template<typename T, typename R>
114  void disconnect(T *obj, R (T::*func)(Args...))
115  {
116  SignalBase::disconnect([obj, func](SlotList::iterator &iter) {
117  BoundMethodArgs<R, Args...> *slot =
118  static_cast<BoundMethodArgs<R, Args...> *>(*iter);
119 
120  if (!slot->match(obj))
121  return false;
122 
123  /*
124  * If the object matches the slot, the slot is
125  * guaranteed to be a member slot, so we can safely
126  * cast it to BoundMethodMember<T, Args...> to match
127  * func.
128  */
129  return static_cast<BoundMethodMember<T, R, Args...> *>(slot)->match(func);
130  });
131  }
132 
133  template<typename R>
134  void disconnect(R (*func)(Args...))
135  {
136  SignalBase::disconnect([func](SlotList::iterator &iter) {
137  BoundMethodArgs<R, Args...> *slot =
138  static_cast<BoundMethodArgs<R, Args...> *>(*iter);
139 
140  if (!slot->match(nullptr))
141  return false;
142 
143  return static_cast<BoundMethodStatic<R, Args...> *>(slot)->match(func);
144  });
145  }
146 
147  void emit(Args... args)
148  {
149  /*
150  * Make a copy of the slots list as the slot could call the
151  * disconnect operation, invalidating the iterator.
152  */
153  for (BoundMethodBase *slot : slots())
154  static_cast<BoundMethodArgs<void, Args...> *>(slot)->activate(args...);
155  }
156 };
157 
158 } /* namespace libcamera */
void emit(Args... args)
Emit the signal and call all connected slots.
Definition: signal.h:147
ConnectionType
Connection type for asynchronous communication.
Definition: bound_method.h:19
void connect(T *obj, Func func)
Connect the signal to a function object slot.
Definition: signal.h:87
void disconnect()
Disconnect the signal from all slots.
Definition: signal.h:98
void connect(T *obj, R(T::*func)(Args...))
Connect the signal to a member function slot.
Definition: signal.h:60
void disconnect(T *obj)
Disconnect the signal from all slots of the object.
Definition: signal.h:106
Top-level libcamera namespace.
Definition: backtrace.h:17
void disconnect(R(*func)(Args...))
Disconnect the signal from the slot static function func.
Definition: signal.h:134
void disconnect(T *obj, R(T::*func)(Args...))
Disconnect the signal from the object slot member function func.
Definition: signal.h:114
Base object to support automatic signal disconnection.
Definition: object.h:24
Method bind and invocation.
If the sender and the receiver live in the same thread, ConnectionTypeDirect is used. Otherwise ConnectionTypeQueued is used.
Definition: bound_method.h:20
void connect(R(*func)(Args...))
Connect the signal to a static function slot.
Definition: signal.h:93