Ocean
ScopedSubscription.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) Meta Platforms, Inc. and affiliates.
3  *
4  * This source code is licensed under the MIT license found in the
5  * LICENSE file in the root directory of this source tree.
6  */
7 
8 #ifndef META_OCEAN_BASE_SCOPED_SUBSCRIPTION_H
9 #define META_OCEAN_BASE_SCOPED_SUBSCRIPTION_H
10 
11 #include "ocean/base/Base.h"
12 #include "ocean/base/Lock.h"
13 
14 #include <functional>
15 
16 namespace Ocean
17 {
18 
19 /**
20  * This class implements a subscription object which can be used unique subscriptions to e.g., callback functions.
21  * The subscription exists as long as the object exists.
22  * @tparam T The data type of the subscription id
23  * @tparam TOwner The data type of the class in which this subscription object will be defined
24  * @ingroup base
25  */
26 template <typename T, typename TOwner>
28 {
29  friend TOwner;
30 
31  protected:
32 
33  /**
34  * Definition of a callback function for release requests.
35  * @param subscriptionId The id of the subscription to be released
36  */
37  using ReleaseCallbackFunction = std::function<void(const T& subscriptionId)>;
38 
39  public:
40 
41  /**
42  * Creates an invalid (unsubscribed) subscription object.
43  */
44  ScopedSubscriptionT() = default;
45 
46  /**
47  * Move constructor.
48  * @param scopedSubscription The object to be moved
49  */
51 
52  /**
53  * Destructs the object and releases the subscription if any.
54  */
56 
57  /**
58  * Explicitly releases the subscription before this object is disposes.
59  */
60  void release();
61 
62  /**
63  * Returns whether this object holds a valid subscription.
64  * @return True, if so
65  */
66  inline bool isValid() const;
67 
68  /**
69  * Returns whether this object holds a valid subscription.
70  * @return True, if so
71  */
72  explicit inline operator bool() const;
73 
74  /**
75  * Move operator.
76  * @param scopedSubscription The object to be moved
77  * @return Reference to this object
78  */
80 
81  /**
82  * Returns whether two subscription objects are identical.
83  * @param scopedSubscription The second subscription object to compare
84  * @return True, if so
85  */
86  inline bool operator==(const ScopedSubscriptionT<T, TOwner>& scopedSubscription) const;
87 
88  /**
89  * Returns whether two subscription objects are not identical.
90  * @param scopedSubscription The second subscription object to compare
91  * @return True, if so
92  */
93  inline bool operator!=(const ScopedSubscriptionT<T, TOwner>& scopedSubscription) const;
94 
95  /**
96  * Hash function.
97  * @param scopedSubscription The object for which the hash value will be determined
98  * @return The resulting hash value
99  */
100  inline size_t operator()(const ScopedSubscriptionT<T, TOwner>& scopedSubscription) const;
101 
102  protected:
103 
104  /**
105  * Disabled copy constructor.
106  * @param scopedSubscription The object which would be copied
107  */
108  ScopedSubscriptionT(const ScopedSubscriptionT<T, TOwner>& scopedSubscription) = delete;
109 
110  /**
111  * Creates a new subscription object for a valid subscription id.
112  * @param subscriptionId The subscription id, must be valid
113  * @param releaseCallbackFunction The callback function which will be used when the subscription needs to be released, must be valid
114  */
115  explicit inline ScopedSubscriptionT(const T& subscriptionId, ReleaseCallbackFunction releaseCallbackFunction);
116 
117  /**
118  * The disabled assign operator.
119  * @param scopedSubscription The object which would be assigned
120  * @return The reference to this object
121  */
123 
124  protected:
125 
126  /// The subscription id, nullptr if invalid.
127  std::unique_ptr<T> subscriptionId_ = nullptr;
128 
129  /// The callback function which will be used when the subscription needs to be released.
131 };
132 
133 /**
134  * This class implements the base class for all subscription handlers.
135  * @ingroup base
136  */
138 {
139  public:
140 
141  /**
142  * Definition of a scoped subscription object
143  */
145 
146  protected:
147 
148  /**
149  * Returns the subscription object for a given subscription id.
150  * @param subscriptionId The subscription id of the resulting subscription object
151  * @param releaseCallbackFunction The release function of the subscription, must be valid
152  * @return The subscription object
153  */
154  inline ScopedSubscriptionType scopedSubscription(const unsigned int& subscriptionId, ScopedSubscriptionType::ReleaseCallbackFunction releaseCallbackFunction);
155 };
156 
157 /**
158  * This class implements a handler for scoped subscriptions to callback functions.
159  * The class mainly wraps a counter for subscription ids and a map holding the callback functions.
160  * @tparam TCallbackFunction The data type of the callback function
161  * @tparam TOwner The owner of this handler (the class in which the handler will be located)
162  * @tparam tThreadSafe True, to make the handler thread-safe
163  * @ingroup base
164  */
165 template <typename TCallbackFunction, typename TOwner, bool tThreadSafe>
167 {
168  friend TOwner;
169 
170  public:
171 
172  /**
173  * Definition of the data type of the callback function.
174  */
175  using CallbackFunctionType = TCallbackFunction;
176 
177  /// True, if this handler is thread-safe.
178  static constexpr bool isThreadSafe_ = tThreadSafe;
179 
180  protected:
181 
182  /**
183  * Definition of an unordered map mapping subscription ids to callback functions.
184  */
185  using CallbackMap = std::unordered_map<unsigned int, TCallbackFunction>;
186 
187  public:
188 
189  /**
190  * Adds a new callback function to this handler.
191  * @param callbackFunction The callback function to add, must be valid
192  * @return The resulting scoped subscription object, the callback function will be in use until the resulting subscription object exists
193  */
194  [[nodiscard]] ScopedSubscriptionType addCallback(TCallbackFunction callbackFunction);
195 
196  /**
197  * Returns the number of subscriptions.
198  * @return The handler's subscriptions
199  */
200  size_t subscriptions() const;
201 
202  /**
203  * Returns whether no subscription exists.
204  * @return True, if so
205  */
206  bool isEmpty() const;
207 
208  protected:
209 
210  /**
211  * Calls all callback functions of this handler.
212  * @param args The arguments of the callback function
213  * @return The resulting of any of the callback functions
214  * @tparam TArgs The data types of the callback functions
215  */
216  template <class... TArgs>
217  typename TCallbackFunction::result_type callCallbacks(TArgs&& ... args);
218 
219  /**
220  * Removes a callback function from the handler.
221  * @param subscriptionId The id of the subscription to be removed
222  */
223  void removeCallback(const unsigned int& subscriptionId);
224 
225  protected:
226 
227  /// The map mapping subscription ids to callback functions.
229 
230  /// The counter for subscription ids.
231  unsigned int subscriptionIdCounter_ = 0u;
232 
233  /// The optional lock object.
235 };
236 
237 template <typename T, typename TOwner>
239 {
240  *this = std::move(scopedSubscription);
241 }
242 
243 template <typename T, typename TOwner>
244 inline ScopedSubscriptionT<T, TOwner>::ScopedSubscriptionT(const T& subscriptionId, ReleaseCallbackFunction releaseCallbackFunction) :
245  subscriptionId_(std::make_unique<T>(subscriptionId)),
246  releaseCallbackFunction_(std::move(releaseCallbackFunction))
247 {
248  ocean_assert(isValid());
249 }
250 
251 template <typename T, typename TOwner>
253 {
254  release();
255 }
256 
257 template <typename T, typename TOwner>
259 {
260  if (subscriptionId_)
261  {
262  ocean_assert(releaseCallbackFunction_);
263  releaseCallbackFunction_(*subscriptionId_);
264 
265  releaseCallbackFunction_ = nullptr;
266  subscriptionId_ = nullptr;
267  }
268 }
269 
270 template <typename T, typename TOwner>
272 {
273  return subscriptionId_ != nullptr;
274 }
275 
276 template <typename T, typename TOwner>
278 {
279  return isValid();
280 }
281 
282 template <typename T, typename TOwner>
284 {
285  if (this != &scopedSubscription)
286  {
287  release();
288 
289  subscriptionId_ = std::move(scopedSubscription.subscriptionId_);
290  releaseCallbackFunction_ = std::move(scopedSubscription.releaseCallbackFunction_);
291  }
292 
293  return *this;
294 }
295 
296 template <typename T, typename TOwner>
298 {
299  return subscriptionId_ == scopedSubscription.subscriptionId_ && releaseCallbackFunction_ == scopedSubscription.releaseCallbackFunction_;
300 }
301 
302 template <typename T, typename TOwner>
304 {
305  return !(*this == scopedSubscription);
306 }
307 
308 template <typename T, typename TOwner>
310 {
311  return std::hash<std::unique_ptr<T>>()(scopedSubscription.subscriptionId_);
312 }
313 
315 {
316  ocean_assert(releaseCallbackFunction);
317  return ScopedSubscriptionType(subscriptionId, std::move(releaseCallbackFunction));
318 }
319 
320 template <typename TCallbackFunction, typename TOwner, bool tThreadSafe>
322 {
323  const TemplatedScopedLock<tThreadSafe> scopedLock(lock_);
324 
325  const unsigned int subscriptionId = ++subscriptionIdCounter_;
326 
327  ocean_assert(callbackMap_.find(subscriptionId) == callbackMap_.cend());
328  callbackMap_.emplace(subscriptionId, std::move(callbackFunction));
329 
330  return scopedSubscription(subscriptionId, std::bind(&ScopedSubscriptionCallbackHandlerT<TCallbackFunction, TOwner, tThreadSafe>::removeCallback, this, std::placeholders::_1));
331 }
332 
333 template <typename TCallbackFunction, typename TOwner, bool tThreadSafe>
335 {
336  const TemplatedScopedLock<tThreadSafe> scopedLock(lock_);
337 
338  return callbackMap_.size();
339 }
340 
341 template <typename TCallbackFunction, typename TOwner, bool tThreadSafe>
343 {
344  const TemplatedScopedLock<tThreadSafe> scopedLock(lock_);
345 
346  return callbackMap_.empty();
347 }
348 
349 template <typename TCallbackFunction, typename TOwner, bool tThreadSafe>
350 template <class... TArgs>
352 {
353  const TemplatedScopedLock<tThreadSafe> scopedLock(lock_);
354 
355  for (typename CallbackMap::const_iterator iCallback = callbackMap_.cbegin(); iCallback != callbackMap_.cend(); ++iCallback)
356  {
357  const TCallbackFunction& callbackFunction = iCallback->second;
358 
359  typename CallbackMap::const_iterator iNextCallback(iCallback);
360 
361  if (++iNextCallback == callbackMap_.cend())
362  {
363  return callbackFunction(std::forward<TArgs>(args)...);
364  }
365  else
366  {
367  callbackFunction(std::forward<TArgs>(args)...);
368  }
369  }
370 }
371 
372 template <typename TCallbackFunction, typename TOwner, bool tThreadSafe>
374 {
375  const TemplatedScopedLock<tThreadSafe> scopedLock(lock_);
376 
377  ocean_assert(callbackMap_.find(subscriptionId) != callbackMap_.cend());
378 
379  callbackMap_.erase(subscriptionId);
380 }
381 
382 }
383 
384 #endif // META_OCEAN_BASE_SCOPED_SUBSCRIPTION_H
This class implements a handler for scoped subscriptions to callback functions.
Definition: ScopedSubscription.h:167
static constexpr bool isThreadSafe_
True, if this handler is thread-safe.
Definition: ScopedSubscription.h:178
friend TOwner
Definition: ScopedSubscription.h:168
unsigned int subscriptionIdCounter_
The counter for subscription ids.
Definition: ScopedSubscription.h:231
TCallbackFunction CallbackFunctionType
Definition of the data type of the callback function.
Definition: ScopedSubscription.h:175
void removeCallback(const unsigned int &subscriptionId)
Removes a callback function from the handler.
Definition: ScopedSubscription.h:373
ScopedSubscriptionType addCallback(TCallbackFunction callbackFunction)
Adds a new callback function to this handler.
Definition: ScopedSubscription.h:321
std::unordered_map< unsigned int, TCallbackFunction > CallbackMap
Definition of an unordered map mapping subscription ids to callback functions.
Definition: ScopedSubscription.h:185
size_t subscriptions() const
Returns the number of subscriptions.
Definition: ScopedSubscription.h:334
CallbackMap callbackMap_
The map mapping subscription ids to callback functions.
Definition: ScopedSubscription.h:228
TemplatedLock< tThreadSafe > lock_
The optional lock object.
Definition: ScopedSubscription.h:234
TCallbackFunction::result_type callCallbacks(TArgs &&... args)
Calls all callback functions of this handler.
Definition: ScopedSubscription.h:351
bool isEmpty() const
Returns whether no subscription exists.
Definition: ScopedSubscription.h:342
This class implements the base class for all subscription handlers.
Definition: ScopedSubscription.h:138
ScopedSubscriptionT< unsigned int, ScopedSubscriptionHandler > ScopedSubscriptionType
Definition of a scoped subscription object.
Definition: ScopedSubscription.h:144
ScopedSubscriptionType scopedSubscription(const unsigned int &subscriptionId, ScopedSubscriptionType::ReleaseCallbackFunction releaseCallbackFunction)
Returns the subscription object for a given subscription id.
Definition: ScopedSubscription.h:314
This class implements a subscription object which can be used unique subscriptions to e....
Definition: ScopedSubscription.h:28
bool operator==(const ScopedSubscriptionT< T, TOwner > &scopedSubscription) const
Returns whether two subscription objects are identical.
Definition: ScopedSubscription.h:297
friend TOwner
Definition: ScopedSubscription.h:29
ScopedSubscriptionT< T, TOwner > & operator=(const ScopedSubscriptionT< T, TOwner > &scopedSubscription)=delete
The disabled assign operator.
ScopedSubscriptionT(ScopedSubscriptionT< T, TOwner > &&scopedSubscription)
Move constructor.
Definition: ScopedSubscription.h:238
void release()
Explicitly releases the subscription before this object is disposes.
Definition: ScopedSubscription.h:258
std::unique_ptr< T > subscriptionId_
The subscription id, nullptr if invalid.
Definition: ScopedSubscription.h:127
std::function< void(const T &subscriptionId)> ReleaseCallbackFunction
Definition of a callback function for release requests.
Definition: ScopedSubscription.h:37
size_t operator()(const ScopedSubscriptionT< T, TOwner > &scopedSubscription) const
Hash function.
Definition: ScopedSubscription.h:309
ScopedSubscriptionT()=default
Creates an invalid (unsubscribed) subscription object.
ScopedSubscriptionT(const T &subscriptionId, ReleaseCallbackFunction releaseCallbackFunction)
Creates a new subscription object for a valid subscription id.
Definition: ScopedSubscription.h:244
bool operator!=(const ScopedSubscriptionT< T, TOwner > &scopedSubscription) const
Returns whether two subscription objects are not identical.
Definition: ScopedSubscription.h:303
bool isValid() const
Returns whether this object holds a valid subscription.
Definition: ScopedSubscription.h:271
ScopedSubscriptionT(const ScopedSubscriptionT< T, TOwner > &scopedSubscription)=delete
Disabled copy constructor.
~ScopedSubscriptionT()
Destructs the object and releases the subscription if any.
Definition: ScopedSubscription.h:252
ReleaseCallbackFunction releaseCallbackFunction_
The callback function which will be used when the subscription needs to be released.
Definition: ScopedSubscription.h:130
ScopedSubscriptionT< T, TOwner > & operator=(ScopedSubscriptionT< T, TOwner > &&scopedSubscription)
Move operator.
Definition: ScopedSubscription.h:283
This class implements a recursive scoped lock object that is activated by a boolean template paramete...
Definition: Lock.h:178
void release(T *object)
This functions allows to release a DirectShow object if it does exist.
Definition: DSObject.h:266
The namespace covering the entire Ocean framework.
Definition: Accessor.h:15