Nebula
Loading...
Searching...
No Matches
message.h
Go to the documentation of this file.
1#pragma once
2//------------------------------------------------------------------------------
25//------------------------------------------------------------------------------
26#include "ids/id.h"
28#include "util/delegate.h"
29#include "util/hashtable.h"
30#include "util/arrayallocator.h"
31#include "util/string.h"
32#include "util/stringatom.h"
33#include "util/fourcc.h"
34
35#define __DeclareMsg(NAME, FOURCC, ...) \
36class NAME : public Game::Message<NAME, __VA_ARGS__> \
37{ \
38 public: \
39 NAME() = delete; \
40 ~NAME() = delete; \
41 \
42 constexpr static const char* GetName() \
43 { \
44 return #NAME; \
45 }; \
46 \
47 constexpr static const uint GetFourCC() \
48 { \
49 return FOURCC; \
50 }; \
51};
52
53#define __RegisterMsg(MSGTYPE, FUNCTION) \
54 MSGTYPE::Register(MSGTYPE::Delegate::FromFunction<FUNCTION>())
55
56#define __this_RegisterMsg(MSGTYPE, METHOD) \
57 MSGTYPE::Register(MSGTYPE::Delegate::FromMethod<std::remove_pointer<decltype(this)>::type, &std::remove_pointer<decltype(this)>::type::METHOD>(this))
58
60template<class T>
61using UnqualifiedType = typename std::remove_const<typename std::remove_reference<T>::type>::type;
62
63namespace Game
64{
65
67
68//------------------------------------------------------------------------------
76
77//------------------------------------------------------------------------------
80template <class MSG, class ... TYPES>
82{
83public:
85
86 Message();
88
89 Message<MSG, TYPES...>(const Message<MSG, TYPES...>&) = delete;
90 void operator=(const Message<MSG, TYPES...>&) = delete;
91
93 using Delegate = Util::Delegate<void(TYPES...)>;
94
97
99 static MessageListener Register(Delegate&& callback);
100
102 static void Deregister(MessageListener listener);
103
105 static void Send(TYPES ... values);
106
109
111 static void Defer(MessageQueueId qid, TYPES ... values);
112
114 static void DispatchMessageQueue(MessageQueueId id);
115
118
120 static bool IsMessageQueueValid(MessageQueueId id);
121
123 static void Distribute(TYPES ...);
124
126 static void DeregisterAll();
127
129 static bool IsValid(MessageListenerId listener);
130
134
135protected:
136 friend MSG;
137
138 static Message<MSG, TYPES...>* Instance()
139 {
140 static Message<MSG, TYPES...> instance;
141 return &instance;
142 }
143
145
148
154
157
160
164
165protected:
169
170
171private:
172 template<std::size_t...Is>
173 void send_expander(MessageQueue& data, const IndexT cid, const SizeT index, std::index_sequence<Is...>)
174 {
175 this->callbacks.Get<1>(cid)(std::get<Is>(data.Get<0>(index))...);
176 }
177
178 void send_expander(MessageQueue& data, const IndexT cid, const SizeT index)
179 {
180 this->send_expander(data, cid, index, std::make_index_sequence<sizeof...(TYPES)>());
181 }
182};
183
184//------------------------------------------------------------------------------
187template <typename MSG, class ... TYPES>
188inline
190{
191 this->name = MSG::GetName();
192 this->fourcc = MSG::GetFourCC();
193}
194
195//------------------------------------------------------------------------------
198template <typename MSG, class ... TYPES>
199inline
201{
202 // empty
203}
204
205//------------------------------------------------------------------------------
208template <typename MSG, class ... TYPES>
209inline MessageListener
211{
213 Instance()->listenerPool.Allocate(l.id);
214 IndexT index = Instance()->callbacks.Alloc();
215 Instance()->callbacks.Set(index, l, callback);
216 Instance()->listenerMap.Add(l, index);
217 MessageListener listener = { Instance()->fourcc, l };
218 return listener;
219}
220
221//------------------------------------------------------------------------------
224template <typename MSG, class ... TYPES>
225inline void
227{
228 auto instance = Instance();
229 n_assert(listener.messageId == instance->fourcc);
230 IndexT index = instance->listenerMap[listener.listenerId];
231 if (index != InvalidIndex)
232 {
233 instance->listenerMap.Erase(listener.listenerId);
234 instance->callbacks.EraseIndexSwap(index);
235 if (instance->callbacks.Size() != 0)
236 {
237 instance->listenerMap[instance->callbacks.Get<0>(index)] = index;
238 }
239 }
240}
241
242//------------------------------------------------------------------------------
245template <typename MSG, class ... TYPES>
246inline void
248{
249 auto instance = Instance();
250 SizeT size = instance->callbacks.Size();
251 for (SizeT i = 0; i < size; ++i)
252 {
253 // n_assert(instance->callbacks.Get<1>(i).GetObject() != nullptr);
254 instance->callbacks.Get<1>(i)(values...);
255 }
256}
257
258//------------------------------------------------------------------------------
261template<typename MSG, class ...TYPES>
262inline typename Message<MSG, TYPES...>::MessageQueueId
264{
265 auto instance = Instance();
267 instance->messageQueueIdPool.Allocate(id.id);
268
269 if (Ids::Index(id.id) >= instance->messageQueues.Size())
270 {
271 // This should garantuee that the id is the newest element
272 n_assert(instance->messageQueues.Size() == Ids::Index(id.id));
273 instance->messageQueues.Append({});
274 }
275
276 return id;
277}
278
279template<typename MSG, class ...TYPES>
280inline void
282{
283 auto instance = Instance();
284 SizeT index = Ids::Index(qid.id);
285
286 auto i = instance->messageQueues[index].Alloc();
287 instance->messageQueues[index].Set(i, std::make_tuple(values...));
288}
289
290//------------------------------------------------------------------------------
293template<typename MSG, class ... TYPES>
294inline void
296{
297 auto instance = Instance();
298
299 n_assert(instance->messageQueues.Size() > Ids::Index(id.id));
300 n_assert(instance->messageQueueIdPool.IsValid(id.id));
301
302 auto& data = instance->messageQueues[Ids::Index(id.id)];
303
304 SizeT size = data.Size();
305 SizeT cidSize = instance->callbacks.Size();
306
307 for (SizeT cid = 0; cid < cidSize; ++cid)
308 {
309 for (SizeT i = 0; i < size; i++)
310 {
311 instance->send_expander(data, cid, i);
312 }
313 }
314
315 // TODO: Should we call reset here instead?
316 data.Clear();
317}
318
319//------------------------------------------------------------------------------
322template<typename MSG, class ...TYPES> inline void
324{
325 auto instance = Instance();
326
327 n_assert(instance->messageQueues.Size() > Ids::Index(id.id));
328 n_assert(instance->messageQueueIdPool.IsValid(id.id));
329
330 instance->messageQueues[Ids::Index(id.id)].Clear();
331 instance->messageQueueIdPool.Deallocate(id.id);
332}
333
334template<typename MSG, class ...TYPES> inline bool
339
340//------------------------------------------------------------------------------
344template <typename MSG, class ... TYPES>
345inline void
347{
348 n_error("Network distributed messages not yet supported!");
349}
350
351//------------------------------------------------------------------------------
354template <typename MSG, class ... TYPES>
355inline void
357{
358 auto instance = Instance();
359 SizeT size = instance->callbacks.Size();
360 for (SizeT i = 0; i < size; i++)
361 {
362 instance->listenerPool.Deallocate((instance->callbacks.template Get<0>(i)).id);
363 }
364 instance->callbacks.Clear();
365 instance->distributedMessages.Clear();
366 instance->listenerMap.Clear();
367}
368
369//------------------------------------------------------------------------------
372template <typename MSG, class ... TYPES>
373inline bool
375{
376 return Instance()->listenerPool.IsValid(listener.id);
377}
378
379//------------------------------------------------------------------------------
382template <typename MSG, class ... TYPES>
383inline typename Message<MSG, TYPES...>::MessageQueue&
385{
386 return Instance()->messageQueues[id.id];
387}
388
389} // namespace Msg
typename std::remove_const< typename std::remove_reference< T >::type >::type UnqualifiedType
Removes const reference from T.
Definition message.h:61
Definition message.h:82
void send_expander(MessageQueue &data, const IndexT cid, const SizeT index, std::index_sequence< Is... >)
Definition message.h:173
typename Util::ArrayAllocator< Util::Tuple< UnqualifiedType< TYPES > ... > > MessageQueue
Type definition for this message's queues.
Definition message.h:96
static void Send(TYPES ... values)
Send a message.
Definition message.h:247
static Message< MSG, TYPES... > * Instance()
Definition message.h:138
static void DeAllocateMessageQueue(MessageQueueId id)
Deallocate a message queue. All messages in the queue will be destroyed.
Definition message.h:323
~Message()
Definition message.h:200
Ids::IdGenerationPool listenerPool
Definition message.h:168
Ids::IdGenerationPool messageQueueIdPool
id generation pool for the deferred messages queues.
Definition message.h:156
Util::ArrayAllocator< MessageListenerId, Delegate > callbacks
contains the callback and the listener it's attached to.
Definition message.h:153
static bool IsValid(MessageListenerId listener)
Returns whether a MessageListenerId is still registered or not.
Definition message.h:374
static MessageQueueId AllocateMessageQueue()
Creates a new message queue for deferred dispatching.
Definition message.h:263
MessageQueue distributedMessages
Contains the arguments of a recieved distributed message.
Definition message.h:163
Util::FourCC fourcc
Definition message.h:167
static MessageListener Register(Delegate &&callback)
Register a listener to this message. Returns an ID for the listener so that we can associate it.
Definition message.h:210
Util::StringAtom name
Definition message.h:166
static bool IsMessageQueueValid(MessageQueueId id)
Check whether a message queue is still valid.
Definition message.h:335
static void Distribute(TYPES ...)
Send a network distributed message.
Definition message.h:346
void send_expander(MessageQueue &data, const IndexT cid, const SizeT index)
Definition message.h:178
Message()
Definition message.h:189
static void DispatchMessageQueue(MessageQueueId id)
Dispatch all messages in a message queue.
Definition message.h:295
static void Defer(MessageQueueId qid, TYPES ... values)
Add a message to a message queue.
Definition message.h:281
friend MSG
Definition message.h:136
static void Deregister(MessageListener listener)
Deregister a listener.
Definition message.h:226
static void DeregisterAll()
Deregisters all listeners at once.
Definition message.h:356
Util::Array< MessageQueue > messageQueues
Deferred messages.
Definition message.h:159
Util::HashTable< MessageListenerId, IndexT > listenerMap
Internal singleton instance.
Definition message.h:147
void operator=(const Message< MSG, TYPES... > &)=delete
static MessageQueue & GetMessageQueue(MessageQueueId id)
Returns a message queue by id Can be used to manually dispatch queues.
Definition message.h:384
Provides a system for creating array friendly id numbers with reuse and generations.
Definition idgenerationpool.h:43
bool IsValid(Id32 id) const
check if valid
Definition idgenerationpool.cc:66
The ArrayAllocator provides a variadic list of types which is to be contained in the allocator and fe...
Definition arrayallocator.h:34
Nebula's dynamic array class.
Definition array.h:60
Nebula delegate class, allows to store a function, method or lambda call into a C++ object for later ...
Definition delegate.h:39
A four-character-code is a quasi-human-readable 32-bit-id.
Definition fourcc.h:19
Organizes key/value pairs by a hash code.
Definition hashtable.h:42
A StringAtom.
Definition stringatom.h:22
void __cdecl n_error(const char *msg,...)
This function is called when a serious situation is encountered which requires abortion of the applic...
Definition debug.cc:138
#define n_assert(exp)
Definition debug.h:50
#define ID_32_TYPE(x)
Definition id.h:16
Definition orientation.h:7
static constexpr Id24 Index(const Id32 id)
Definition idgenerationpool.h:72
Definition message.h:84
Definition message.h:72
Util::FourCC messageId
Definition message.h:73
MessageListenerId listenerId
Definition message.h:74
Definition message.h:66
static const int InvalidIndex
Definition types.h:54
int SizeT
Definition types.h:49
int IndexT
Definition types.h:48