COMMS
Template library intended to help with implementation of communication protocols.
Loading...
Searching...
No Matches
DispatchMsgPolymorphicHelper.h
1//
2// Copyright 2019 - 2025 (C). Alex Robenko. All rights reserved.
3//
4// This Source Code Form is subject to the terms of the Mozilla Public
5// License, v. 2.0. If a copy of the MPL was not distributed with this
6// file, You can obtain one at http://mozilla.org/MPL/2.0/.
7
8#pragma once
9
10#include "comms/Assert.h"
13#include "comms/details/DispatchMsgIdRetrieveHelper.h"
14#include "comms/details/tag.h"
15#include "comms/Message.h"
16#include "comms/MessageBase.h"
17#include "comms/util/Tuple.h"
19
20#include <algorithm>
21#include <array>
22#include <limits>
23#include <type_traits>
24#include <utility>
25
26namespace comms
27{
28
29namespace details
30{
31
32template <typename TMsgBase, typename THandler>
33class PolymorphicDirectDispatchMethod
34{
35public:
36 PolymorphicDirectDispatchMethod(const PolymorphicDirectDispatchMethod&) = delete;
37 PolymorphicDirectDispatchMethod& operator=(const PolymorphicDirectDispatchMethod&) = delete;
38
39 virtual auto dispatch(TMsgBase& msg, THandler& handler) const ->
40 MessageInterfaceDispatchRetType<THandler>
41 {
42 return dispatchImpl(msg, handler);
43 }
44
45protected:
46 PolymorphicDirectDispatchMethod() = default;
47 ~PolymorphicDirectDispatchMethod() = default;
48
49 virtual auto dispatchImpl(TMsgBase& msg, THandler& handler) const ->
50 MessageInterfaceDispatchRetType<THandler> = 0;
51};
52
53template <typename TMsgBase, typename THandler, typename TMessage>
54class PolymorphicDirectDispatchMethodImpl : public
55 PolymorphicDirectDispatchMethod<TMsgBase, THandler>
56{
57public:
58 PolymorphicDirectDispatchMethodImpl() = default;
59 PolymorphicDirectDispatchMethodImpl(const PolymorphicDirectDispatchMethodImpl&) = delete;
60 PolymorphicDirectDispatchMethodImpl& operator=(const PolymorphicDirectDispatchMethodImpl&) = delete;
61
62protected:
63 virtual auto dispatchImpl(TMsgBase& msg, THandler& handler) const ->
64 MessageInterfaceDispatchRetType<THandler>
65#ifndef COMMS_COMPILER_GCC47
66 override final
67#endif
68 {
69 static_assert(std::is_base_of<TMsgBase, TMessage>::value, "TMessage must extend TMsgBase");
70 auto& castedMsg = static_cast<TMessage&>(msg);
71 return handler.handle(castedMsg);
72 }
73};
74
75template <typename TMsgBase, typename THandler>
76class PolymorphicBinSearchDispatchMethod
77{
78public:
79 PolymorphicBinSearchDispatchMethod(const PolymorphicBinSearchDispatchMethod&) = delete;
80 PolymorphicBinSearchDispatchMethod& operator=(const PolymorphicBinSearchDispatchMethod&) = delete;
81
82 static_assert(TMsgBase::hasMsgIdType(), "Message interface class must define its id type");
83 using MsgIdParamType = typename TMsgBase::MsgIdParamType;
84 using MsgIdType = typename TMsgBase::MsgIdType;
85
86 virtual MsgIdParamType getId() const
87 {
88 return getIdImpl();
89 }
90
91 virtual auto dispatch(TMsgBase& msg, THandler& handler) const ->
92 MessageInterfaceDispatchRetType<THandler>
93 {
94 return dispatchImpl(msg, handler);
95 }
96
97protected:
98 PolymorphicBinSearchDispatchMethod() = default;
99 ~PolymorphicBinSearchDispatchMethod() = default;
100
101 virtual MsgIdParamType getIdImpl() const = 0;
102 virtual auto dispatchImpl(TMsgBase& msg, THandler& handler) const ->
103 MessageInterfaceDispatchRetType<THandler> = 0;
104};
105
106template <typename TMsgBase, typename THandler, typename TMessage>
107class PolymorphicBinSearchDispatchMethodImpl : public
108 PolymorphicBinSearchDispatchMethod<TMsgBase, THandler>
109{
110 using Base = PolymorphicBinSearchDispatchMethod<TMsgBase, THandler>;
111public:
112 static_assert(TMsgBase::hasMsgIdType(), "Message interface class must define its id type");
113 using MsgIdParamType = typename Base::MsgIdParamType;
114 using MsgIdType = typename Base::MsgIdType;
115
116 PolymorphicBinSearchDispatchMethodImpl() = default;
117 PolymorphicBinSearchDispatchMethodImpl(const PolymorphicBinSearchDispatchMethodImpl&) = delete;
118 PolymorphicBinSearchDispatchMethodImpl& operator=(const PolymorphicBinSearchDispatchMethodImpl&) = delete;
119
120
121 static MsgIdParamType doGetId()
122 {
123 return dispatchMsgGetMsgId<TMessage>();
124 }
125
126protected:
127
128 virtual MsgIdParamType getIdImpl() const
129#ifndef COMMS_COMPILER_GCC47
130 override final
131#endif
132 {
133 return doGetId();
134 }
135
136 virtual auto dispatchImpl(TMsgBase& msg, THandler& handler) const ->
137 MessageInterfaceDispatchRetType<THandler>
138#ifndef COMMS_COMPILER_GCC47
139 override final
140#endif
141 {
142 static_assert(std::is_base_of<TMsgBase, TMessage>::value, "TMessage must extend TMsgBase");
143 auto& castedMsg = static_cast<TMessage&>(msg);
144 return handler.handle(castedMsg);
145 }
146};
147
148template <typename TMsgBase, typename THandler, std::size_t TSize>
149using PolymorphicDirectDispatchMsgRegistry =
150 std::array<const PolymorphicDirectDispatchMethod<TMsgBase, THandler>*, TSize>;
151
152template <typename TMsgBase, typename THandler, std::size_t TSize>
153using PolymorphicBinSearchDispatchMsgRegistry =
154 std::array<const PolymorphicBinSearchDispatchMethod<TMsgBase, THandler>*, TSize>;
155
156
157template <typename TMsgBase, typename THandler>
158class PolymorphicDirectDispatchRegistryFiller
159{
160public:
161 using DispatchMethod = PolymorphicDirectDispatchMethod<TMsgBase, THandler>;
162 PolymorphicDirectDispatchRegistryFiller(const DispatchMethod** registry)
163 : m_registry(registry)
164 {
165 }
166
167 template <typename TMessage>
168 void operator()()
169 {
170 static_assert(comms::isMessageBase<TMessage>(), "Must be actual message");
171 static_assert(messageHasStaticNumId<TMessage>(), "Message must define static ID");
172 static const PolymorphicDirectDispatchMethodImpl<TMsgBase, THandler, TMessage> Method{};
173 m_registry[static_cast<std::size_t>(TMessage::doGetId())] = &Method;
174 }
175private:
176 const DispatchMethod** m_registry;
177};
178
179template <typename TMsgBase, typename THandler, std::size_t TSize>
180PolymorphicDirectDispatchRegistryFiller<TMsgBase, THandler>
181polymorphicDirectDispatchMakeRegistryFiller(
182 PolymorphicDirectDispatchMsgRegistry<TMsgBase, THandler, TSize>& registry)
183{
184 return PolymorphicDirectDispatchRegistryFiller<TMsgBase, THandler>(&registry[0]);
185}
186
187template <typename TRegistry, typename TAllMessages>
188class PolymorphicDirectDispatchRegistryInitializer
189{
190public:
191 PolymorphicDirectDispatchRegistryInitializer() = delete;
192 PolymorphicDirectDispatchRegistryInitializer(const PolymorphicDirectDispatchRegistryInitializer&) = delete;
193 explicit PolymorphicDirectDispatchRegistryInitializer(TRegistry& registry)
194 {
195 std::fill(registry.begin(), registry.end(), nullptr);
196 comms::util::tupleForEachType<TAllMessages>(polymorphicDirectDispatchMakeRegistryFiller(registry));
197 }
198};
199
200template <typename TMsgBase, typename THandler>
201class PolymorphicBinSearchDispatchRegistryFiller
202{
203public:
204 using DispatchMethod = PolymorphicBinSearchDispatchMethod<TMsgBase, THandler>;
205 PolymorphicBinSearchDispatchRegistryFiller(const DispatchMethod** registry)
206 : m_registry(registry)
207 {
208 }
209
210 template <typename TMessage>
211 void operator()()
212 {
213 static_assert(comms::isMessageBase<TMessage>(), "Must be actual message");
214 static_assert(messageHasStaticNumId<TMessage>(), "Message must define static ID");
215 static const PolymorphicBinSearchDispatchMethodImpl<TMsgBase, THandler, TMessage> Method{};
216 m_registry[m_idx] = &Method;
217 ++m_idx;
218 }
219
220private:
221 const DispatchMethod** m_registry;
222 std::size_t m_idx = 0U;
223};
224
225template <typename TMsgBase, typename THandler, std::size_t TSize>
226PolymorphicBinSearchDispatchRegistryFiller<TMsgBase, THandler>
227polymorphicBinSearchDispatchMakeRegistryFiller(
228 PolymorphicBinSearchDispatchMsgRegistry<TMsgBase, THandler, TSize>& registry)
229{
230 return PolymorphicBinSearchDispatchRegistryFiller<TMsgBase, THandler>(&registry[0]);
231}
232
233template <typename TRegistry, typename TAllMessages>
234class PolymorphicBinSearchDispatchRegistryInitializer
235{
236public:
237 explicit PolymorphicBinSearchDispatchRegistryInitializer(TRegistry& registry)
238 {
239 std::fill(registry.begin(), registry.end(), nullptr);
240 comms::util::tupleForEachType<TAllMessages>(polymorphicBinSearchDispatchMakeRegistryFiller(registry));
241 }
242};
243
244template <typename TAllMessages, std::size_t TMaxSize>
245class PolymorphicDirectDispatchRegSizeDetect
246{
247 using MsgType = typename std::tuple_element<TMaxSize - 1, TAllMessages>::type;
248 static_assert(comms::isMessageBase<MsgType>(), "Must be actual message");
249 static_assert(messageHasStaticNumId<MsgType>(), "Message must define static numeric ID");
250 static_assert(MsgType::hasMsgIdType(), "Message interface class must define its id type");
251 static const typename MsgType::MsgIdParamType MsgId = MsgType::doGetId();
252public:
253 static const std::size_t Value = static_cast<std::size_t>(MsgId) + 1U;
254};
255
256template <typename TAllMessages>
257class PolymorphicDirectDispatchRegSizeDetect<TAllMessages, 0U>
258{
259public:
260 static const std::size_t Value = 0;
261};
262
263template <typename TAllMessages, typename TMsgBase, typename THandler>
264class DispatchMsgDirectPolymorphicHelper
265{
266public:
267 static_assert(TMsgBase::hasMsgIdType(), "Message interface class must define its id type");
268 using MsgIdParamType = typename TMsgBase::MsgIdParamType;
269 static auto dispatch(MsgIdParamType id, TMsgBase& msg, THandler& handler) ->
270 MessageInterfaceDispatchRetType<
271 typename std::decay<decltype(handler)>::type>
272 {
273 // Access initializer object to ensure it hasn't been erased by the optimizer
274 static_cast<void>(s_initializer);
275
276 using RetType =
277 MessageInterfaceDispatchRetType<
278 typename std::decay<decltype(handler)>::type>;
279
280 auto regIdx = static_cast<std::size_t>(id);
281 if ((s_registry.size() <= regIdx) ||
282 (s_registry[regIdx] == nullptr)) {
283 return static_cast<RetType>(handler.handle(msg));
284 }
285
286 return static_cast<RetType>(s_registry[regIdx]->dispatch(msg, handler));
287 }
288
289private:
290 static const std::size_t RegistrySize =
291 PolymorphicDirectDispatchRegSizeDetect<TAllMessages, std::tuple_size<TAllMessages>::value>::Value;
292 using Registry = PolymorphicDirectDispatchMsgRegistry<TMsgBase, THandler, RegistrySize>;
293 using Initializer = PolymorphicDirectDispatchRegistryInitializer<Registry, TAllMessages>;
294
295 static Registry s_registry;
296 static const Initializer s_initializer;
297};
298
299template <typename TAllMessages, typename TMsgBase, typename THandler>
300typename DispatchMsgDirectPolymorphicHelper<TAllMessages, TMsgBase, THandler>::Registry
301DispatchMsgDirectPolymorphicHelper<TAllMessages, TMsgBase, THandler>::s_registry;
302
303template <typename TAllMessages, typename TMsgBase, typename THandler>
304const typename DispatchMsgDirectPolymorphicHelper<TAllMessages, TMsgBase, THandler>::Initializer
305DispatchMsgDirectPolymorphicHelper<TAllMessages, TMsgBase, THandler>::s_initializer(s_registry);
306
307template <typename TAllMessages, typename TMsgBase, typename THandler>
308class DispatchMsgBinSearchPolymorphicHelperBase
309{
310protected:
311 static const std::size_t RegistrySize = std::tuple_size<TAllMessages>::value;
312 using Registry = PolymorphicBinSearchDispatchMsgRegistry<TMsgBase, THandler, RegistrySize>;
313 using Initializer = PolymorphicBinSearchDispatchRegistryInitializer<Registry, TAllMessages>;
314
315 static Registry s_registry;
316 static Initializer s_initializer;
317};
318
319template <typename TAllMessages, typename TMsgBase, typename THandler>
320typename DispatchMsgBinSearchPolymorphicHelperBase<TAllMessages, TMsgBase, THandler>::Registry
321DispatchMsgBinSearchPolymorphicHelperBase<TAllMessages, TMsgBase, THandler>::s_registry;
322
323template <typename TAllMessages, typename TMsgBase, typename THandler>
324typename DispatchMsgBinSearchPolymorphicHelperBase<TAllMessages, TMsgBase, THandler>::Initializer
325DispatchMsgBinSearchPolymorphicHelperBase<TAllMessages, TMsgBase, THandler>::s_initializer(s_registry);
326
327template <typename TAllMessages, typename TMsgBase, typename THandler>
328class DispatchMsgBinSearchStrongPolymorphicHelper : public
329 DispatchMsgBinSearchPolymorphicHelperBase<TAllMessages, TMsgBase, THandler>
330{
331 using Base = DispatchMsgBinSearchPolymorphicHelperBase<TAllMessages, TMsgBase, THandler>;
332 using Registry = typename Base::Registry;
333public:
334 static_assert(TMsgBase::hasMsgIdType(), "Message interface class must define its id type");
335 using MsgIdParamType = typename TMsgBase::MsgIdParamType;
336 static auto dispatch(MsgIdParamType id, TMsgBase& msg, THandler& handler) ->
337 MessageInterfaceDispatchRetType<
338 typename std::decay<decltype(handler)>::type>
339 {
340 // Access initializer object to ensure it hasn't been erased by the optimizer
341 static_cast<void>(Base::s_initializer);
342
343 using RetType =
344 MessageInterfaceDispatchRetType<
345 typename std::decay<decltype(handler)>::type>;
346
347 auto iter =
348 std::lower_bound(
349 Base::s_registry.begin(), Base::s_registry.end(), id,
350 [](typename Registry::value_type method, MsgIdParamType idParam) -> bool
351 {
352 COMMS_ASSERT(method != nullptr);
353 return method->getId() < idParam;
354 });
355
356 if ((iter == Base::s_registry.end()) || ((*iter)->getId() != id)) {
357 return static_cast<RetType>(handler.handle(msg));
358 }
359
360 return static_cast<RetType>((*iter)->dispatch(msg, handler));
361 }
362};
363
364template <typename TAllMessages, typename TMsgBase, typename THandler>
365class DispatchMsgBinSearchWeakPolymorphicHelper : public
366 DispatchMsgBinSearchPolymorphicHelperBase<TAllMessages, TMsgBase, THandler>
367{
368 using Base = DispatchMsgBinSearchPolymorphicHelperBase<TAllMessages, TMsgBase, THandler>;
369 using Registry = typename Base::Registry;
370public:
371 template <typename TId>
372 static auto dispatch(TId&& id, std::size_t offset, TMsgBase& msg, THandler& handler) ->
373 MessageInterfaceDispatchRetType<
374 typename std::decay<decltype(handler)>::type>
375 {
376 // Access initializer object to ensure it hasn't been erased by the optimizer
377 static_cast<void>(Base::s_initializer);
378
379 using RetType =
380 MessageInterfaceDispatchRetType<
381 typename std::decay<decltype(handler)>::type>;
382
383 using IdType = typename std::decay<decltype(id)>::type;
384
385 auto lowerIter =
386 std::lower_bound(
387 Base::s_registry.begin(), Base::s_registry.end(), id,
388 [](typename Registry::value_type method, IdType idParam) -> bool
389 {
390 COMMS_ASSERT(method != nullptr);
391 return static_cast<IdType>(method->getId()) < idParam;
392 });
393
394 if ((lowerIter == Base::s_registry.end()) ||
395 (static_cast<IdType>((*lowerIter)->getId()) != id)) {
396 return static_cast<RetType>(handler.handle(msg));
397 }
398
399 auto upperIter =
400 std::upper_bound(
401 lowerIter, Base::s_registry.end(), id,
402 [](IdType idParam, typename Registry::value_type method)
403 {
404 return idParam < static_cast<IdType>(method->getId());
405 }
406 );
407
408 COMMS_ASSERT(lowerIter < upperIter);
409
410 auto dist = static_cast<std::size_t>(upperIter - lowerIter);
411 if (dist <= offset) {
412 return static_cast<RetType>(handler.handle(msg));
413 }
414
415 auto actualIter = lowerIter + offset;
416 return static_cast<RetType>((*actualIter)->dispatch(msg, handler));
417 }
418};
419
420template <typename TElem, bool TIsMessage>
421struct DispatchMsgPolymorphicLastIdRetriever;
422
423template <typename TElem>
424struct DispatchMsgPolymorphicLastIdRetriever<TElem, true>
425{
426 static_assert(messageHasStaticNumId<TElem>(), "TElem must define static numeric id");
427 static const std::size_t Value =
428 static_cast<std::size_t>(TElem::doGetId());
429};
430
431template <typename TElem>
432struct DispatchMsgPolymorphicLastIdRetriever<TElem, false>
433{
434 static const std::size_t Value = std::numeric_limits<std::size_t>::max();
435};
436
437template <typename TAllMessages, std::size_t TCount>
438class DispatchMsgPolymorphicIsDirectSuitable
439{
440 using LastMsg =
441 typename std::tuple_element<
442 std::tuple_size<TAllMessages>::value - 1,
443 TAllMessages
444 >::type;
445
446
447 static const std::size_t MaxId =
448 DispatchMsgPolymorphicLastIdRetriever<LastMsg, comms::isMessageBase<LastMsg>()>::Value;
449
450 static const std::size_t MaxAllowedId = (TCount * 11) / 10;
451
452public:
453 static const bool Value =
454 (MaxId <= (TCount + 10U)) || (MaxId <= MaxAllowedId);
455};
456
457template <typename TAllMessages>
458class DispatchMsgPolymorphicIsDirectSuitable<TAllMessages, 0U>
459{
460public:
461 static const bool Value = true;
462};
463
464template <typename TAllMessages>
465static constexpr bool dispatchMsgPolymorphicIsDirectSuitable()
466{
467 return
468 allMessagesHaveStaticNumId<TAllMessages>() &&
469 DispatchMsgPolymorphicIsDirectSuitable<TAllMessages, std::tuple_size<TAllMessages>::value>::Value;
470}
471
472template <typename...>
473struct DispatchMsgPolymorphicCompatibleHandlerDetector
474{
475 template <typename TMsg, typename THandler>
476 using Type = std::is_base_of<typename TMsg::Handler, THandler>;
477};
478
479template <typename TMsg, typename THandler>
480using DispatchMsgPolymorphicCompatibleHandlerDetectBoolType =
481 typename comms::util::LazyDeepConditional<
482 TMsg::hasDispatch()
483 >::template Type<
484 DispatchMsgPolymorphicCompatibleHandlerDetector,
485 comms::util::FalseType,
486 TMsg, THandler
487 >;
488
489
490template <typename TMsg, typename THandler>
491constexpr bool dispatchMsgPolymorphicIsCompatibleHandler()
492{
493 return DispatchMsgPolymorphicCompatibleHandlerDetectBoolType<TMsg, THandler>::value;
494}
495
496template <typename ...>
497class DispatchMsgPolymorphicHelper
498{
499 template <typename... TParams>
500 using EmptyTag = comms::details::tag::Tag1<>;
501
502 template <typename... TParams>
503 using DispatchInterfaceTag = comms::details::tag::Tag2<>;
504
505 template <typename... TParams>
506 using DirectTag = comms::details::tag::Tag3<>;
507
508 template <typename... TParams>
509 using StrongBinSearchTag = comms::details::tag::Tag4<>;
510
511 template <typename... TParams>
512 using WeakBinSearchTag = comms::details::tag::Tag5<>;
513
514 template <typename... TParams>
515 using IdInterfaceTag = comms::details::tag::Tag6<>;
516
517 template <typename... TParams>
518 using NoIdInterfaceTag = comms::details::tag::Tag7<>;
519
520 template <typename TAllMessages, typename...>
521 using DirectStrongTag =
522 typename comms::util::LazyShallowConditional<
523 dispatchMsgPolymorphicIsDirectSuitable<TAllMessages>()
524 >::template Type<
525 DirectTag,
526 StrongBinSearchTag
527 >;
528
529 template <typename TAllMessages, typename...>
530 using DirectStrongWeakTag =
531 typename comms::util::LazyShallowConditional<
532 allMessagesAreStrongSorted<TAllMessages>()
533 >::template Type<
534 DirectStrongTag,
535 WeakBinSearchTag,
536 TAllMessages
537 >;
538
539
540 template <typename TAllMessages, typename TMsgBase, typename THandler, typename...>
541 using Tag =
542 typename comms::util::LazyShallowConditional<
543 dispatchMsgPolymorphicIsCompatibleHandler<TMsgBase, THandler>()
544 >::template Type<
545 DispatchInterfaceTag,
546 DirectStrongWeakTag,
547 TAllMessages
548 >;
549
550 template <typename TAllMessages, typename TMsgBase, typename THandler, typename...>
551 using AdjustedTag =
552 typename comms::util::LazyShallowConditional<
553 comms::isMessageBase<TMsgBase>()
554 >::template Type<
555 EmptyTag,
556 Tag,
557 TAllMessages, TMsgBase, THandler
558 >;
559
560 template <typename TMsgBase, typename...>
561 using InterfaceDispatchTag =
562 typename comms::util::LazyShallowConditional<
563 TMsgBase::hasGetId()
564 >::template Type<
565 IdInterfaceTag,
566 NoIdInterfaceTag
567 >;
568
569 template <typename TMsgBase, typename THandler, typename...>
570 using PolymorphicCheckDispatchTag =
571 typename comms::util::LazyShallowConditional<
572 dispatchMsgPolymorphicIsCompatibleHandler<TMsgBase, THandler>()
573 >::template Type<
574 NoIdInterfaceTag,
575 InterfaceDispatchTag,
576 TMsgBase
577 >;
578
579public:
580 template <typename TAllMessages, typename TMsgBase, typename THandler>
581 static auto dispatch(TMsgBase& msg, THandler& handler) ->
582 MessageInterfaceDispatchRetType<
583 typename std::decay<decltype(handler)>::type>
584 {
585
586 static_assert(allMessagesAreWeakSorted<TAllMessages>() || (!allMessagesHaveStaticNumId<TAllMessages>()),
587 "Message types must be sorted by their ID");
588
589 static_assert(comms::isMessage<TMsgBase>(),
590 "TMsgBase is expected to be message interface class");
591
592 static_assert(TMsgBase::hasMsgIdType(), "Message interface class must define its id type");
593
594 using MsgType = typename std::decay<decltype(msg)>::type;
595 using HandlerType = typename std::decay<decltype(handler)>::type;
596 using IdRetrieveTag =
597 typename comms::util::LazyShallowConditional<
598 comms::isMessageBase<MsgType>()
599 >::template Type<
600 EmptyTag,
601 PolymorphicCheckDispatchTag,
602 MsgType, HandlerType
603 >;
604
605 return dispatchInternal<TAllMessages>(msg, handler, IdRetrieveTag());
606 }
607
608 template <typename TAllMessages, typename TId, typename TMsgBase, typename THandler>
609 static auto dispatch(TId&& id, TMsgBase& msg, THandler& handler) ->
610 MessageInterfaceDispatchRetType<
611 typename std::decay<decltype(handler)>::type>
612 {
613 static_assert(allMessagesAreWeakSorted<TAllMessages>() || (!allMessagesHaveStaticNumId<TAllMessages>()),
614 "Message types must be sorted by their ID");
615
616 static_assert(comms::isMessage<TMsgBase>(),
617 "TMsgBase is expected to be message interface class");
618
619 static_assert(TMsgBase::hasMsgIdType(), "Message interface class must define its id type");
620
621 using MsgType = typename std::decay<decltype(msg)>::type;
622 using HandlerType = typename std::decay<decltype(handler)>::type;
623 return
624 dispatchInternal<TAllMessages>(
625 static_cast<typename MsgType::MsgIdParamType>(id),
626 msg,
627 handler,
628 AdjustedTag<TAllMessages, MsgType, HandlerType>());
629 }
630
631 template <typename TAllMessages, typename TId, typename TMsgBase, typename THandler>
632 static auto dispatch(TId&& id, std::size_t offset, TMsgBase& msg, THandler& handler) ->
633 MessageInterfaceDispatchRetType<
634 typename std::decay<decltype(handler)>::type>
635 {
636 static_assert(allMessagesAreWeakSorted<TAllMessages>() || (!allMessagesHaveStaticNumId<TAllMessages>()),
637 "Message types must be sorted by their ID");
638
639 static_assert(comms::isMessage<TMsgBase>(),
640 "TMsgBase is expected to be message interface class");
641
642 static_assert(TMsgBase::hasMsgIdType(), "Message interface class must define its id type");
643
644 using MsgType = typename std::decay<decltype(msg)>::type;
645 using HandlerType = typename std::decay<decltype(handler)>::type;
646 return
647 dispatchInternal<TAllMessages>(
648 static_cast<typename MsgType::MsgIdParamType>(id),
649 offset,
650 msg,
651 handler,
652 AdjustedTag<TAllMessages, MsgType, HandlerType>());
653 }
654
655private:
656 template <typename TAllMessages, typename TMsgBase, typename THandler, typename... TParams>
657 static auto dispatchInternal(TMsgBase& msg, THandler& handler, EmptyTag<TParams...>) ->
658 decltype(handler.handle(msg))
659 {
660 return handler.handle(msg);
661 }
662
663 template <typename TAllMessages, typename TMsgBase, typename THandler, typename... TParams>
664 static auto dispatchInternal(TMsgBase& msg, THandler& handler, IdInterfaceTag<TParams...>) ->
665 MessageInterfaceDispatchRetType<
666 typename std::decay<decltype(handler)>::type>
667 {
668 typename TMsgBase::MsgIdParamType id = msg.getId();
669 return dispatch<TAllMessages>(id, msg, handler);
670 }
671
672 template <typename TAllMessages, typename TMsgBase, typename THandler, typename... TParams>
673 static auto dispatchInternal(TMsgBase& msg, THandler& handler, NoIdInterfaceTag<TParams...>) ->
674 MessageInterfaceDispatchRetType<
675 typename std::decay<decltype(handler)>::type>
676 {
677 static_assert(TMsgBase::hasDispatch(), "The message must provide polymorphic dispatch");
678 static_assert(std::is_base_of<typename TMsgBase::Handler, THandler>::value,
679 "Incompatible handlers");
680
681 using RetType = MessageInterfaceDispatchRetType<THandler>;
682 return static_cast<RetType>(msg.dispatch(handler));
683 }
684
685 template <typename TAllMessages, typename TId, typename TMsgBase, typename THandler, typename... TParams>
686 static auto dispatchInternal(TId&& id, TMsgBase& msg, THandler& handler, EmptyTag<TParams...>) ->
687 decltype(handler.handle(msg))
688 {
689 static_cast<void>(id);
690 return handler.handle(msg);
691 }
692
693 template <typename TAllMessages, typename TId, typename TMsgBase, typename THandler, typename... TParams>
694 static auto dispatchInternal(TId&& id, TMsgBase& msg, THandler& handler, DispatchInterfaceTag<TParams...>) ->
695 MessageInterfaceDispatchRetType<
696 typename std::decay<decltype(handler)>::type>
697 {
698 static_cast<void>(id);
699 return dispatchInternal<TAllMessages>(msg, handler, NoIdInterfaceTag<>());
700 }
701
702 template <typename TAllMessages, typename TId, typename TMsgBase, typename THandler, typename... TParams>
703 static auto dispatchInternal(TId&& id, TMsgBase& msg, THandler& handler, DirectTag<TParams...>) ->
704 MessageInterfaceDispatchRetType<
705 typename std::decay<decltype(handler)>::type>
706 {
707 using MsgType = typename std::decay<decltype(msg)>::type;
708 using HandlerType = typename std::decay<decltype(handler)>::type;
709
710 return DispatchMsgDirectPolymorphicHelper<TAllMessages, MsgType, HandlerType>::
711 dispatch(std::forward<TId>(id), msg, handler);
712 }
713
714 template <typename TAllMessages, typename TId, typename TMsgBase, typename THandler, typename... TParams>
715 static auto dispatchInternal(TId&& id, TMsgBase& msg, THandler& handler, StrongBinSearchTag<TParams...>) ->
716 MessageInterfaceDispatchRetType<
717 typename std::decay<decltype(handler)>::type>
718 {
719 using MsgType = typename std::decay<decltype(msg)>::type;
720 using HandlerType = typename std::decay<decltype(handler)>::type;
721
722 return DispatchMsgBinSearchStrongPolymorphicHelper<TAllMessages, MsgType, HandlerType>::
723 dispatch(std::forward<TId>(id), msg, handler);
724 }
725
726 template <typename TAllMessages, typename TId, typename TMsgBase, typename THandler, typename... TParams>
727 static auto dispatchInternal(TId&& id, TMsgBase& msg, THandler& handler, WeakBinSearchTag<TParams...>) ->
728 MessageInterfaceDispatchRetType<
729 typename std::decay<decltype(handler)>::type>
730 {
731 return dispatchInternal<TAllMessages>(std::forward<TId>(id), 0U, msg, handler, WeakBinSearchTag<>());
732 }
733
734 template <typename TAllMessages, typename TId, typename TMsgBase, typename THandler, typename... TParams>
735 static auto dispatchInternal(TId&& id, std::size_t offset, TMsgBase& msg, THandler& handler, DispatchInterfaceTag<TParams...>) ->
736 MessageInterfaceDispatchRetType<
737 typename std::decay<decltype(handler)>::type>
738 {
739 static_cast<void>(id);
740 static_cast<void>(offset);
741 static_assert(std::is_base_of<typename TMsgBase::Handler, THandler>::value,
742 "Incompatible handlers");
743
744 using RetType = MessageInterfaceDispatchRetType<THandler>;
745 return static_cast<RetType>(msg.dispatch(handler));
746 }
747
748 template <typename TAllMessages, typename TId, typename TMsgBase, typename THandler, typename... TParams>
749 static auto dispatchInternal(TId&& id, std::size_t offset, TMsgBase& msg, THandler& handler, EmptyTag<TParams...>) ->
750 decltype(handler.handle(msg))
751 {
752 static_cast<void>(id);
753 static_cast<void>(offset);
754 return handler.handle(msg);
755 }
756
757 template <typename TAllMessages, typename TId, typename TMsgBase, typename THandler, typename... TParams>
758 static auto dispatchInternal(TId&& id, std::size_t offset, TMsgBase& msg, THandler& handler, DirectTag<TParams...>) ->
759 MessageInterfaceDispatchRetType<
760 typename std::decay<decltype(handler)>::type>
761 {
762 if (offset != 0U) {
763 using RetType = MessageInterfaceDispatchRetType<THandler>;
764 return static_cast<RetType>(handler.handle(msg));
765 }
766
767 return dispatchInternal<TAllMessages>(std::forward<TId>(id), msg, handler, DirectTag<>());
768 }
769
770 template <typename TAllMessages, typename TId, typename TMsgBase, typename THandler, typename... TParams>
771 static auto dispatchInternal(TId&& id, std::size_t offset, TMsgBase& msg, THandler& handler, StrongBinSearchTag<TParams...>) ->
772 MessageInterfaceDispatchRetType<
773 typename std::decay<decltype(handler)>::type>
774 {
775 if (offset != 0U) {
776 using RetType = MessageInterfaceDispatchRetType<THandler>;
777 return static_cast<RetType>(handler.handle(msg));
778 }
779
780 return dispatchInternal<TAllMessages>(std::forward<TId>(id), msg, handler, StrongBinSearchTag<>());
781 }
782
783 template <typename TAllMessages, typename TId, typename TMsgBase, typename THandler, typename... TParams>
784 static auto dispatchInternal(TId&& id, std::size_t offset, TMsgBase& msg, THandler& handler, WeakBinSearchTag<TParams...>) ->
785 MessageInterfaceDispatchRetType<
786 typename std::decay<decltype(handler)>::type>
787 {
788 using MsgType = typename std::decay<decltype(msg)>::type;
789 using HandlerType = typename std::decay<decltype(handler)>::type;
790
791 return DispatchMsgBinSearchWeakPolymorphicHelper<TAllMessages, MsgType, HandlerType>::
792 dispatch(std::forward<TId>(id), offset, msg, handler);
793 }
794};
795
796// ------------------------------------------------
797
798template <typename THandler>
799class PolymorphicTypeDirectDispatchMethod
800{
801public:
802 PolymorphicTypeDirectDispatchMethod(const PolymorphicTypeDirectDispatchMethod&) = delete;
803 PolymorphicTypeDirectDispatchMethod& operator=(const PolymorphicTypeDirectDispatchMethod&) = delete;
804
805 virtual void dispatch(THandler& handler) const
806 {
807 dispatchImpl(handler);
808 }
809
810protected:
811 PolymorphicTypeDirectDispatchMethod() = default;
812 ~PolymorphicTypeDirectDispatchMethod() = default;
813
814 virtual void dispatchImpl(THandler& handler) const = 0;
815};
816
817template <typename THandler, typename TMessage>
818class PolymorphicTypeDirectDispatchMethodImpl : public
819 PolymorphicTypeDirectDispatchMethod<THandler>
820{
821public:
822 PolymorphicTypeDirectDispatchMethodImpl() = default;
823 PolymorphicTypeDirectDispatchMethodImpl(const PolymorphicTypeDirectDispatchMethodImpl&) = delete;
824 PolymorphicTypeDirectDispatchMethodImpl& operator=(const PolymorphicTypeDirectDispatchMethodImpl&) = delete;
825
826protected:
827 virtual void dispatchImpl(THandler& handler) const
828#ifndef COMMS_COMPILER_GCC47
829 override final
830#endif
831 {
832 return handler.template handle<TMessage>();
833 }
834};
835
836template <typename TMsgIdType, typename THandler>
837class PolymorphicTypeBinSearchDispatchMethod
838{
839public:
840 PolymorphicTypeBinSearchDispatchMethod(const PolymorphicTypeBinSearchDispatchMethod&) = delete;
841 PolymorphicTypeBinSearchDispatchMethod& operator=(const PolymorphicTypeBinSearchDispatchMethod&) = delete;
842
843 virtual TMsgIdType getId() const
844 {
845 return getIdImpl();
846 }
847
848 virtual void dispatch(THandler& handler) const
849 {
850 return dispatchImpl(handler);
851 }
852
853protected:
854 PolymorphicTypeBinSearchDispatchMethod() = default;
855 ~PolymorphicTypeBinSearchDispatchMethod() = default;
856
857 virtual TMsgIdType getIdImpl() const = 0;
858 virtual void dispatchImpl(THandler& handler) const = 0;
859};
860
861template <typename TMsgIdType, typename THandler, typename TMessage>
862class PolymorphicTypeBinSearchDispatchMethodImpl : public
863 PolymorphicTypeBinSearchDispatchMethod<TMsgIdType, THandler>
864{
865 using Base = PolymorphicTypeBinSearchDispatchMethod<TMsgIdType, THandler>;
866public:
867 PolymorphicTypeBinSearchDispatchMethodImpl() = default;
868 PolymorphicTypeBinSearchDispatchMethodImpl(const PolymorphicTypeBinSearchDispatchMethodImpl&) = delete;
869 PolymorphicTypeBinSearchDispatchMethodImpl& operator=(const PolymorphicTypeBinSearchDispatchMethodImpl&) = delete;
870
871 static TMsgIdType doGetId()
872 {
873 return dispatchMsgGetMsgId<TMessage>();
874 }
875
876protected:
877 virtual TMsgIdType getIdImpl() const
878#ifndef COMMS_COMPILER_GCC47
879 override final
880#endif
881 {
882 return doGetId();
883 }
884
885 virtual void dispatchImpl(THandler& handler) const
886#ifndef COMMS_COMPILER_GCC47
887 override final
888#endif
889 {
890 return handler.template handle<TMessage>();
891 }
892};
893
894template <typename THandler, std::size_t TSize>
895using PolymorphicTypeDirectDispatchMsgRegistry =
896 std::array<const PolymorphicTypeDirectDispatchMethod<THandler>*, TSize>;
897
898template <typename TMsgIdType, typename THandler, std::size_t TSize>
899using PolymorphicTypeBinSearchDispatchMsgRegistry =
900 std::array<const PolymorphicTypeBinSearchDispatchMethod<TMsgIdType, THandler>*, TSize>;
901
902template <typename THandler>
903class PolymorphicTypeDirectDispatchRegistryFiller
904{
905public:
906 using DispatchMethod = PolymorphicTypeDirectDispatchMethod<THandler>;
907 PolymorphicTypeDirectDispatchRegistryFiller(const DispatchMethod** registry)
908 : m_registry(registry)
909 {
910 }
911
912 template <typename TMessage>
913 void operator()()
914 {
915 static_assert(comms::isMessageBase<TMessage>(), "Must be actual message");
916 static_assert(messageHasStaticNumId<TMessage>(), "Message must define static ID");
917 static const PolymorphicTypeDirectDispatchMethodImpl<THandler, TMessage> Method{};
918 m_registry[static_cast<std::size_t>(TMessage::doGetId())] = &Method;
919 }
920private:
921 const DispatchMethod** m_registry;
922};
923
924template <typename THandler, std::size_t TSize>
925PolymorphicTypeDirectDispatchRegistryFiller<THandler>
926polymorphicTypeDirectDispatchMakeRegistryFiller(
927 PolymorphicTypeDirectDispatchMsgRegistry<THandler, TSize>& registry)
928{
929 return PolymorphicTypeDirectDispatchRegistryFiller<THandler>(&registry[0]);
930}
931
932template <typename TRegistry, typename TAllMessages>
933class PolymorphicTypeDirectDispatchRegistryInitializer
934{
935public:
936 PolymorphicTypeDirectDispatchRegistryInitializer() = delete;
937 PolymorphicTypeDirectDispatchRegistryInitializer(const PolymorphicTypeDirectDispatchRegistryInitializer&) = delete;
938 explicit PolymorphicTypeDirectDispatchRegistryInitializer(TRegistry& registry)
939 {
940 std::fill(registry.begin(), registry.end(), nullptr);
941 comms::util::tupleForEachType<TAllMessages>(polymorphicTypeDirectDispatchMakeRegistryFiller(registry));
942 }
943};
944
945template <typename TMsgIdType, typename THandler>
946class PolymorphicTypeBinSearchDispatchRegistryFiller
947{
948public:
949 using DispatchMethod = PolymorphicTypeBinSearchDispatchMethod<TMsgIdType, THandler>;
950 PolymorphicTypeBinSearchDispatchRegistryFiller(const DispatchMethod** registry)
951 : m_registry(registry)
952 {
953 }
954
955 template <typename TMessage>
956 void operator()()
957 {
958 // static_assert(comms::isMessageBase<TMessage>(), "Must be actual message");
959 // static_assert(messageHasStaticNumId<TMessage>(), "Message must define static ID");
960 static const PolymorphicTypeBinSearchDispatchMethodImpl<TMsgIdType, THandler, TMessage> Method{};
961 m_registry[m_idx] = &Method;
962 ++m_idx;
963 }
964
965private:
966 const DispatchMethod** m_registry;
967 std::size_t m_idx = 0U;
968};
969
970template <typename TMsgIdType, typename THandler, std::size_t TSize>
971PolymorphicTypeBinSearchDispatchRegistryFiller<TMsgIdType, THandler>
972polymorphicTypeBinSearchDispatchMakeRegistryFiller(
973 PolymorphicTypeBinSearchDispatchMsgRegistry<TMsgIdType, THandler, TSize>& registry)
974{
975 return PolymorphicTypeBinSearchDispatchRegistryFiller<TMsgIdType, THandler>(&registry[0]);
976}
977
978template <typename TRegistry, typename TAllMessages>
979class PolymorphicTypeBinSearchDispatchRegistryInitializer
980{
981public:
982 explicit PolymorphicTypeBinSearchDispatchRegistryInitializer(TRegistry& registry)
983 {
984 std::fill(registry.begin(), registry.end(), nullptr);
985 comms::util::tupleForEachType<TAllMessages>(polymorphicTypeBinSearchDispatchMakeRegistryFiller(registry));
986 }
987};
988
989template <typename TAllMessages, typename THandler>
990class DispatchMsgTypeDirectPolymorphicHelper
991{
992public:
993 using FirstMsgType = typename std::tuple_element<0, TAllMessages>::type;
994 static_assert(FirstMsgType::hasMsgIdType(), "Message interface class must define its id type");
995 using MsgIdParamType = typename FirstMsgType::MsgIdParamType;
996 static bool dispatch(MsgIdParamType id, THandler& handler)
997 {
998 // Access initializer object to ensure it hasn't been erased by the optimizer
999 static_cast<void>(s_initializer);
1000
1001 auto regIdx = static_cast<std::size_t>(id);
1002 if ((s_registry.size() <= regIdx) ||
1003 (s_registry[regIdx] == nullptr)) {
1004 return false;
1005 }
1006
1007 s_registry[regIdx]->dispatch(handler);
1008 return true;
1009 }
1010
1011private:
1012 static const std::size_t RegistrySize =
1013 PolymorphicDirectDispatchRegSizeDetect<TAllMessages, std::tuple_size<TAllMessages>::value>::Value;
1014 using Registry = PolymorphicTypeDirectDispatchMsgRegistry<THandler, RegistrySize>;
1015 using Initializer = PolymorphicTypeDirectDispatchRegistryInitializer<Registry, TAllMessages>;
1016
1017 static Registry s_registry;
1018 static const Initializer s_initializer;
1019};
1020
1021template <typename TAllMessages, typename THandler>
1022typename DispatchMsgTypeDirectPolymorphicHelper<TAllMessages, THandler>::Registry
1023DispatchMsgTypeDirectPolymorphicHelper<TAllMessages, THandler>::s_registry;
1024
1025template <typename TAllMessages, typename THandler>
1026const typename DispatchMsgTypeDirectPolymorphicHelper<TAllMessages, THandler>::Initializer
1027DispatchMsgTypeDirectPolymorphicHelper<TAllMessages, THandler>::s_initializer(s_registry);
1028
1029template <typename TAllMessages, typename THandler>
1030class DispatchMsgTypeBinSearchPolymorphicHelperBase
1031{
1032protected:
1033 using FirstMsgType = typename std::tuple_element<0, TAllMessages>::type;
1034 static_assert(comms::isMessage<FirstMsgType>(),
1035 "The type in the tuple are expected to be proper messages");
1036 static_assert(FirstMsgType::hasMsgIdType(), "Message interface class must define its id type");
1037 using MsgIdParamType = typename FirstMsgType::MsgIdParamType;
1038
1039 static const std::size_t RegistrySize = std::tuple_size<TAllMessages>::value;
1040 using Registry = PolymorphicTypeBinSearchDispatchMsgRegistry<MsgIdParamType, THandler, RegistrySize>;
1041 using Initializer = PolymorphicTypeBinSearchDispatchRegistryInitializer<Registry, TAllMessages>;
1042
1043 static Registry s_registry;
1044 static Initializer s_initializer;
1045};
1046
1047template <typename TAllMessages, typename THandler>
1048typename DispatchMsgTypeBinSearchPolymorphicHelperBase<TAllMessages, THandler>::Registry
1049DispatchMsgTypeBinSearchPolymorphicHelperBase<TAllMessages, THandler>::s_registry;
1050
1051template <typename TAllMessages, typename THandler>
1052typename DispatchMsgTypeBinSearchPolymorphicHelperBase<TAllMessages, THandler>::Initializer
1053DispatchMsgTypeBinSearchPolymorphicHelperBase<TAllMessages, THandler>::s_initializer(s_registry);
1054
1055template <typename TAllMessages, typename THandler>
1056class DispatchMsgTypeBinSearchStrongPolymorphicHelper : public
1057 DispatchMsgTypeBinSearchPolymorphicHelperBase<TAllMessages, THandler>
1058{
1059 using Base = DispatchMsgTypeBinSearchPolymorphicHelperBase<TAllMessages, THandler>;
1060 using Registry = typename Base::Registry;
1061public:
1062 using MsgIdParamType = typename Base::MsgIdParamType;
1063 static bool dispatch(MsgIdParamType id, THandler& handler)
1064 {
1065 // Access initializer object to ensure it hasn't been erased by the optimizer
1066 static_cast<void>(Base::s_initializer);
1067
1068 auto iter =
1069 std::lower_bound(
1070 Base::s_registry.begin(), Base::s_registry.end(), id,
1071 [](typename Registry::value_type method, MsgIdParamType idParam) -> bool
1072 {
1073 COMMS_ASSERT(method != nullptr);
1074 return method->getId() < idParam;
1075 });
1076
1077 if ((iter == Base::s_registry.end()) || ((*iter)->getId() != id)) {
1078 return false;
1079 }
1080
1081 (*iter)->dispatch(handler);
1082 return true;
1083 }
1084};
1085
1086template <typename TAllMessages, typename THandler>
1087class DispatchMsgTypeBinSearchWeakPolymorphicHelper : public
1088 DispatchMsgTypeBinSearchPolymorphicHelperBase<TAllMessages, THandler>
1089{
1090 using Base = DispatchMsgTypeBinSearchPolymorphicHelperBase<TAllMessages, THandler>;
1091 using Registry = typename Base::Registry;
1092
1093public:
1094 using MsgIdParamType = typename Base::MsgIdParamType;
1095 static bool dispatch(MsgIdParamType id, std::size_t offset, THandler& handler)
1096 {
1097 // Access initializer object to ensure it hasn't been erased by the optimizer
1098 static_cast<void>(Base::s_initializer);
1099
1100 using IdType = typename std::decay<decltype(id)>::type;
1101 auto lowerIter =
1102 std::lower_bound(
1103 Base::s_registry.begin(), Base::s_registry.end(), id,
1104 [](typename Registry::value_type method, IdType idParam) -> bool
1105 {
1106 COMMS_ASSERT(method != nullptr);
1107 return static_cast<IdType>(method->getId()) < idParam;
1108 });
1109
1110 if ((lowerIter == Base::s_registry.end()) ||
1111 (static_cast<IdType>((*lowerIter)->getId()) != id)) {
1112 return false;
1113 }
1114
1115 auto upperIter =
1116 std::upper_bound(
1117 lowerIter, Base::s_registry.end(), id,
1118 [](IdType idParam, typename Registry::value_type method)
1119 {
1120 return idParam < static_cast<IdType>(method->getId());
1121 }
1122 );
1123
1124 COMMS_ASSERT(lowerIter < upperIter);
1125
1126 auto dist = static_cast<std::size_t>(upperIter - lowerIter);
1127 if (dist <= offset) {
1128 return false;
1129 }
1130
1131 auto actualIter = lowerIter + offset;
1132 (*actualIter)->dispatch(handler);
1133 return true;
1134 }
1135};
1136
1137template <typename...>
1138class DispatchMsgTypePolymorphicHelper
1139{
1140 template <typename... TParams>
1141 using EmptyTag = comms::details::tag::Tag1<>;
1142
1143 template <typename... TParams>
1144 using DirectTag = comms::details::tag::Tag2<>;
1145
1146 template <typename... TParams>
1147 using StrongBinSearchTag = comms::details::tag::Tag3<>;
1148
1149 template <typename... TParams>
1150 using WeakBinSearchTag = comms::details::tag::Tag4<>;
1151
1152 template <typename TAllMessages, typename...>
1153 using DirectStrongTag =
1154 typename comms::util::LazyShallowConditional<
1155 dispatchMsgPolymorphicIsDirectSuitable<TAllMessages>()
1156 >::template Type<
1157 DirectTag,
1158 StrongBinSearchTag
1159 >;
1160
1161 template <typename TAllMessages, typename...>
1162 using DirectStrongWeakTag =
1163 typename comms::util::LazyShallowConditional<
1164 allMessagesAreStrongSorted<TAllMessages>()
1165 >::template Type<
1166 DirectStrongTag,
1167 WeakBinSearchTag,
1168 TAllMessages
1169 >;
1170
1171
1172 template <typename TAllMessages, typename...>
1173 using Tag =
1174 typename comms::util::LazyShallowConditional<
1175 std::tuple_size<TAllMessages>::value == 0U
1176 >::template Type<
1177 EmptyTag,
1178 DirectStrongWeakTag,
1179 TAllMessages
1180 >;
1181
1182public:
1183 template <typename TAllMessages, typename TId, typename THandler>
1184 static bool dispatch(TId&& id, THandler& handler)
1185 {
1186 static_assert(allMessagesAreWeakSorted<TAllMessages>() || (!allMessagesHaveStaticNumId<TAllMessages>()),
1187 "Message types must be sorted by their ID");
1188
1189 return dispatchInternal<TAllMessages>(std::forward<TId>(id), handler, Tag<TAllMessages>());
1190 }
1191
1192 template <typename TAllMessages, typename TId, typename THandler>
1193 static bool dispatch(TId&& id, std::size_t offset, THandler& handler)
1194 {
1195 static_assert(allMessagesAreWeakSorted<TAllMessages>() || (!allMessagesHaveStaticNumId<TAllMessages>()),
1196 "Message types must be sorted by their ID");
1197
1198 return dispatchInternal<TAllMessages>(std::forward<TId>(id), offset, handler, Tag<TAllMessages>());
1199 }
1200
1201private:
1202
1203 template <typename TAllMessages, typename TId, typename THandler, typename... TParams>
1204 static bool dispatchInternal(TId&& id, THandler& handler, EmptyTag<TParams...>)
1205 {
1206 static_cast<void>(id);
1207 static_cast<void>(handler);
1208 return false;
1209 }
1210
1211 template <typename TAllMessages, typename TId, typename THandler, typename... TParams>
1212 static bool dispatchInternal(TId&& id, std::size_t offset, THandler& handler, EmptyTag<TParams...>)
1213 {
1214 static_cast<void>(id);
1215 static_cast<void>(handler);
1216 static_cast<void>(offset);
1217 return false;
1218 }
1219
1220 template <typename TAllMessages, typename TId, typename THandler, typename... TParams>
1221 static bool dispatchInternal(TId&& id, THandler& handler, DirectTag<TParams...>)
1222 {
1223 using FirstMsgType = typename std::tuple_element<0, TAllMessages>::type;
1224 static_assert(comms::isMessage<FirstMsgType>(),
1225 "The type in the tuple are expected to be proper messages");
1226 static_assert(FirstMsgType::hasMsgIdType(), "The messages must define their ID type");
1227 using MsgIdParamType = typename FirstMsgType::MsgIdParamType;
1228 using HandlerType = typename std::decay<decltype(handler)>::type;
1229 return DispatchMsgTypeDirectPolymorphicHelper<TAllMessages, HandlerType>::
1230 dispatch(static_cast<MsgIdParamType>(id), handler);
1231 }
1232
1233 template <typename TAllMessages, typename TId, typename THandler, typename... TParams>
1234 static bool dispatchInternal(TId&& id, std::size_t offset, THandler& handler, DirectTag<TParams...>)
1235 {
1236 if (offset != 0U) {
1237 return false;
1238 }
1239
1240 return dispatchInternal<TAllMessages>(std::forward<TId>(id), handler, DirectTag<>());
1241 }
1242
1243 template <typename TAllMessages, typename TId, typename THandler, typename... TParams>
1244 static bool dispatchInternal(TId&& id, THandler& handler, StrongBinSearchTag<TParams...>)
1245 {
1246 using FirstMsgType = typename std::tuple_element<0, TAllMessages>::type;
1247 static_assert(comms::isMessage<FirstMsgType>(),
1248 "The type in the tuple are expected to be proper messages");
1249 static_assert(FirstMsgType::hasMsgIdType(), "The messages must define their ID type");
1250 using MsgIdParamType = typename FirstMsgType::MsgIdParamType;
1251 using HandlerType = typename std::decay<decltype(handler)>::type;
1252 return DispatchMsgTypeBinSearchStrongPolymorphicHelper<TAllMessages, HandlerType>::
1253 dispatch(static_cast<MsgIdParamType>(id), handler);
1254 }
1255
1256 template <typename TAllMessages, typename TId, typename THandler, typename... TParams>
1257 static bool dispatchInternal(TId&& id, std::size_t offset, THandler& handler, StrongBinSearchTag<TParams...>)
1258 {
1259 if (offset != 0U) {
1260 return false;
1261 }
1262
1263 return dispatchInternal<TAllMessages>(std::forward<TId>(id), handler, StrongBinSearchTag<>());
1264 }
1265
1266 template <typename TAllMessages, typename TId, typename THandler, typename... TParams>
1267 static bool dispatchInternal(TId&& id, THandler& handler, WeakBinSearchTag<TParams...>)
1268 {
1269 return dispatchInternal<TAllMessages>(std::forward<TId>(id), 0U, handler, WeakBinSearchTag<>());
1270 }
1271
1272 template <typename TAllMessages, typename TId, typename THandler, typename... TParams>
1273 static bool dispatchInternal(TId&& id, std::size_t offset, THandler& handler, WeakBinSearchTag<TParams...>)
1274 {
1275 using FirstMsgType = typename std::tuple_element<0, TAllMessages>::type;
1276 static_assert(comms::isMessage<FirstMsgType>(),
1277 "The type in the tuple are expected to be proper messages");
1278 static_assert(FirstMsgType::hasMsgIdType(), "The messages must define their ID type");
1279 using MsgIdParamType = typename FirstMsgType::MsgIdParamType;
1280 using HandlerType = typename std::decay<decltype(handler)>::type;
1281 return DispatchMsgTypeBinSearchWeakPolymorphicHelper<TAllMessages, HandlerType>::
1282 dispatch(static_cast<MsgIdParamType>(id), offset, handler);
1283 }
1284};
1285
1286} // namespace details
1287
1288} // namespace comms
This file contains classes required for generic custom assertion functionality.
#define COMMS_ASSERT(expr)
Generic assert macro.
Definition Assert.h:170
Contains various compiler related definitions.
Provides common base class for the custom messages with default implementation.
Contains definition of Message object interface and various base classes for custom messages.
Contains various tuple type manipulation classes and functions.
comms::option::def::MsgType< TMsg > MsgType
Same as comms::option::def::MsgType.
Definition options.h:1487
comms::option::def::MsgIdType< T > MsgIdType
Same as comms::option::def::MsgIdType.
Definition options.h:1473
Main namespace for all classes / functions of COMMS library.
Replacement to some types from standard type_traits.