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