|
| 1 | +/*! |
| 2 | +\file |
| 3 | +\brief Implementation of simple thread-safe event processing and notifying system |
| 4 | +
|
| 5 | +\details Will be useful when you need a system which allows you to handle events with calling the subscribed callbacks. |
| 6 | +*/ |
| 7 | + |
1 | 8 | #pragma once |
2 | 9 |
|
3 | 10 | #include "xrCommon/xr_smart_pointers.h" |
|
6 | 13 | #include "xrCore/Threading/Lock.hpp" |
7 | 14 | #include "xrCore/Threading/ScopeLock.hpp" |
8 | 15 |
|
| 16 | +/*! |
| 17 | + \brief Base abstract class for implementing event handling callbacks |
| 18 | +
|
| 19 | + \details Derive it and override @ref ProcessEvent method, then register the instanciated callback into the event |
| 20 | + notifier. The @ref ProcessEvent method will be called by the notifier every time when the selected event happens |
| 21 | +*/ |
9 | 22 | class CEventNotifierCallback |
10 | 23 | { |
11 | 24 | public: |
| 25 | + /*! Callback ID, type for identifying registered callbacks in the notifier */ |
12 | 26 | using CID = size_t; |
| 27 | + |
| 28 | + /*! Invalid callback ID, will be never returned after successful subscription */ |
13 | 29 | static const CID INVALID_CID = std::numeric_limits<CID>::max(); |
14 | 30 |
|
| 31 | + /*! This method will be automatically called by the notifier for processing the event */ |
15 | 32 | virtual void ProcessEvent() = 0; |
| 33 | + |
16 | 34 | virtual ~CEventNotifierCallback(){}; |
17 | 35 | }; |
18 | 36 |
|
| 37 | +/*! |
| 38 | + \brief Abstract class for event processing callback which stores own callback ID |
| 39 | +
|
| 40 | + \details Designed to use primarily in pair with @ref CEventNotifier::CreateRegisteredCallback method, |
| 41 | + very useful for self-unsubscribing callbacks |
| 42 | +*/ |
19 | 43 | class CEventNotifierCallbackWithCid : public CEventNotifierCallback |
20 | 44 | { |
21 | 45 | private: |
22 | 46 | const CID m_cid; |
23 | 47 |
|
24 | 48 | public: |
| 49 | + /*! Constructor, takes callback ID which was generated by the notifier |
| 50 | + /param[in] cid callback ID, should be generated by the notifier in subscription process only |
| 51 | + */ |
25 | 52 | CEventNotifierCallbackWithCid(CID cid) : m_cid(cid), CEventNotifierCallback(){}; |
| 53 | + |
| 54 | + /*! Returns the callback ID which was generated by the notifier and passed to the constructor */ |
26 | 55 | CID GetCid() const { return m_cid; } |
27 | 56 | }; |
28 | 57 |
|
| 58 | +/*! \brief Template class for the event processing dispatcher |
| 59 | + \details Manages with subscribing, calling and unsubscribing handlers. Template parameter CNT is a count of events |
| 60 | + which we are going to process using the dispatcher. Owns the event's handling callbacks and controls its lifetime. |
| 61 | +*/ |
29 | 62 | template <unsigned int CNT> |
30 | 63 | class CEventNotifier |
31 | 64 | { |
@@ -134,25 +167,67 @@ class CEventNotifier |
134 | 167 | xr_array<CCallbackStorage, CNT> m_callbacks; |
135 | 168 |
|
136 | 169 | public: |
| 170 | + /*! \brief Method for registering an existing event handler. |
| 171 | +
|
| 172 | + \details Use it to register in the notifier previously created event handling callback. |
| 173 | + \warning Please consider using @ref CreateRegisteredCallback method instead. When using the @ref |
| 174 | + RegisterCallback method you should register only the callbacks which were created by the other methods of the |
| 175 | + notifier. This restriction happens because the notifier owns the callbacks and destroyes it internally, so you |
| 176 | + can get some problems when creating the callbacks outside of the notifier (notifier will call improper |
| 177 | + destruction methods). |
| 178 | + \todo Provide the method for creating callbacks without the registration |
| 179 | + \param[in] cb pointer to |
| 180 | + the callback to register. After registration the notifier becomes an owner of the registered callback |
| 181 | + \param[in] event_id Index of the event type which the callback should process, must be lesser than the template |
| 182 | + parameter CNT |
| 183 | + \return Callback ID of the registered callback (unique for each event type) |
| 184 | + */ |
137 | 185 | CEventNotifierCallback::CID RegisterCallback(CEventNotifierCallback* cb, unsigned int event_id) |
138 | 186 | { |
139 | 187 | R_ASSERT(event_id < CNT); |
140 | 188 | return m_callbacks[event_id].RegisterCallback(cb); |
141 | 189 | } |
142 | 190 |
|
| 191 | + /*! \brief Template method which creates a new event handling callback and registers it in the notifier |
| 192 | +
|
| 193 | + \details Provides a convenient way for registering the event handlers. It's a preferred method for setting up |
| 194 | + the event handlers. The template parameter CB is a type of the event handling callback which we are going to |
| 195 | + create |
| 196 | +
|
| 197 | + \param[in] event_id Index of the event type which the callback should process, must be lesser than template |
| 198 | + parameter template parameter CNT |
| 199 | + \param[in] args Arguments which should be passed to the constructor of the callback |
| 200 | + \return Callback ID of the registered callback (unique for each event type) |
| 201 | + */ |
143 | 202 | template <class CB, class... Args> |
144 | 203 | CEventNotifierCallback::CID CreateRegisteredCallback(unsigned int event_id, Args&&... args) |
145 | 204 | { |
146 | 205 | R_ASSERT(event_id < CNT); |
147 | 206 | return m_callbacks[event_id].CreateRegisteredCallback<CB>(args...); |
148 | 207 | } |
149 | 208 |
|
| 209 | + /*! \brief Provides the way to unsubscribe and delete the callback |
| 210 | +
|
| 211 | + \details The callback will be automatically destroyed by the notifier after unsubscribing. However, the |
| 212 | + unsubscribing logic allows to unsubscribe the callback directly while processing the event. Callback won't be |
| 213 | + destroyed while its event handling method is executing. |
| 214 | +
|
| 215 | + \param[in] cid Callback ID which was returning by the subscribing function |
| 216 | + \param[in] event_id Index of the event type which the callback is subscribed to |
| 217 | + \return True if unsubscribing is successful, false otherwise |
| 218 | + */ |
150 | 219 | bool UnregisterCallback(CEventNotifierCallback::CID cid, unsigned int event_id) |
151 | 220 | { |
152 | 221 | R_ASSERT(event_id < CNT); |
153 | 222 | return m_callbacks[event_id].UnregisterCallback(cid); |
154 | 223 | } |
155 | 224 |
|
| 225 | + /*! \brief The method to notify the subscribed callbacks about the event |
| 226 | +
|
| 227 | + \details Call this method when the event happens. All the subscribed callbacks would be called one-by-one in the |
| 228 | + caller's thread. |
| 229 | + \param[in] event_id Index of the event type |
| 230 | + */ |
156 | 231 | void FireEvent(unsigned int event_id) |
157 | 232 | { |
158 | 233 | R_ASSERT(event_id < CNT); |
|
0 commit comments