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