12#include "comms/details/tag.h"
14#include "comms/field/basic/CommonFuncs.h"
15#include "comms/field/details/FieldOpHelpers.h"
16#include "comms/field/details/MembersVersionDependency.h"
17#include "comms/field/details/VersionStorage.h"
26COMMS_MSVC_WARNING_PUSH
27COMMS_MSVC_WARNING_DISABLE(4324)
42class VariantFieldConstructHelper
45 VariantFieldConstructHelper(
void* storage) : m_storage(storage) {}
47 template <std::
size_t TIdx,
typename TField>
48 void operator()()
const
50 new (m_storage) TField;
53 void* m_storage =
nullptr;
57class VariantLengthCalcHelper
60 VariantLengthCalcHelper(std::size_t& len,
const void* storage) :
66 template <std::
size_t TIdx,
typename TField>
69 m_len =
reinterpret_cast<const TField*
>(m_storage)->length();
74 const void* m_storage;
78class VariantFieldCopyConstructHelper
81 VariantFieldCopyConstructHelper(
void* storage,
const void* other) : m_storage(storage), m_other(other) {}
83 template <std::
size_t TIdx,
typename TField>
84 void operator()()
const
86 new (m_storage) TField(*(
reinterpret_cast<const TField*
>(m_other)));
90 void* m_storage =
nullptr;
91 const void* m_other =
nullptr;
95class VariantFieldMoveConstructHelper
98 VariantFieldMoveConstructHelper(
void* storage,
void* other) : m_storage(storage), m_other(other) {}
100 template <std::
size_t TIdx,
typename TField>
101 void operator()()
const
103 new (m_storage) TField(std::move(*(
reinterpret_cast<const TField*
>(m_other))));
107 void* m_storage =
nullptr;
108 void* m_other =
nullptr;
112class VariantFieldDestructHelper
115 VariantFieldDestructHelper(
void* storage) : m_storage(storage) {}
117 template <std::
size_t TIdx,
typename TField>
118 void operator()()
const
120 reinterpret_cast<TField*
>(m_storage)->~TField();
123 void* m_storage =
nullptr;
126template <
typename...>
127class VariantFieldValidCheckHelper
130 VariantFieldValidCheckHelper(
bool& result,
const void* storage)
136 template <std::
size_t TIdx,
typename TField>
139 m_result =
reinterpret_cast<const TField*
>(m_storage)->valid();
144 const void* m_storage;
147template <
typename...>
148class VariantFieldRefreshHelper
151 VariantFieldRefreshHelper(
bool& result,
void* storage)
157 template <std::
size_t TIdx,
typename TField>
160 m_result =
reinterpret_cast<TField*
>(m_storage)->refresh();
165 void* m_storage =
nullptr;
168template <
typename TFunc>
169class VariantExecHelper
171 static_assert(std::is_lvalue_reference<TFunc>::value || std::is_rvalue_reference<TFunc>::value,
172 "Wrong type of template parameter");
174 template <
typename U>
175 VariantExecHelper(
void* storage, U&& func) : m_storage(storage), m_func(
std::forward<U>(func)) {}
177 template <std::
size_t TIdx,
typename TField>
182 m_func.operator()<TIdx>(*(
reinterpret_cast<TField*
>(m_storage)));
184 m_func.template operator()<TIdx>(*(
reinterpret_cast<TField*
>(m_storage)));
188 void* m_storage =
nullptr;
192template <
typename TFunc>
193class VariantConstExecHelper
195 static_assert(std::is_lvalue_reference<TFunc>::value || std::is_rvalue_reference<TFunc>::value,
196 "Wrong type of template parameter");
198 template <
typename U>
199 VariantConstExecHelper(
const void* storage, U&& func) : m_storage(storage), m_func(
std::forward<U>(func)) {}
201 template <std::
size_t TIdx,
typename TField>
206 m_func.operator()<TIdx>(*(
reinterpret_cast<const TField*
>(m_storage)));
208 m_func.template operator()<TIdx>(*(
reinterpret_cast<const TField*
>(m_storage)));
212 const void* m_storage =
nullptr;
216template <
typename TIter,
typename TVerBase,
bool TVerDependent>
217class VariantReadHelper
219 template <
typename... TParams>
220 using VersionDependentTag = comms::details::tag::Tag1<>;
222 template <
typename... TParams>
223 using NoVersionDependencyTag = comms::details::tag::Tag2<>;
225 template <
typename... TParams>
227 typename comms::util::LazyShallowConditional<
231 NoVersionDependencyTag
248 using IterType =
typename std::decay<
decltype(iter)>::type;
249 using IterCategory =
typename std::iterator_traits<IterType>::iterator_category;
250 static_assert(std::is_base_of<std::random_access_iterator_tag, IterCategory>::value,
251 "Variant field only supports read with random access iterators");
256 template <
typename TField>
259 if (m_readComplete) {
263 auto* field =
new (m_storage) TField;
264 updateMemberVersionInternal(*field, VersionTag<>());
266 auto iterTmp = m_iter;
267 auto es = field->read(iterTmp, m_len);
271 m_readComplete =
true;
286 template <
typename TField,
typename... TParams>
287 void updateMemberVersionInternal(TField& field, NoVersionDependencyTag<TParams...>)
289 static_cast<void>(field);
292 template <
typename TField,
typename... TParams>
293 void updateMemberVersionInternal(TField& field, VersionDependentTag<TParams...>)
295 field.setVersion(m_verBase.getVersion());
301 std::size_t m_len = 0;
302 void* m_storage =
nullptr;
304 bool m_readComplete =
false;
307template <
typename TIter>
308class VariantFieldWriteHelper
311 VariantFieldWriteHelper(ErrorStatus& es, TIter& iter, std::size_t len,
const void* storage)
319 template <std::
size_t TIdx,
typename TField>
322 m_es =
reinterpret_cast<const TField*
>(m_storage)->write(m_iter, m_len);
328 std::size_t m_len = 0U;
329 const void* m_storage =
nullptr;
332template <
typename TIter>
333class VariantWriteNoStatusHelper
336 VariantWriteNoStatusHelper(TIter& iter,
const void* storage)
342 template <std::
size_t TIdx,
typename TField>
345 reinterpret_cast<const TField*
>(m_storage)->writeNoStatus(m_iter);
350 const void* m_storage =
nullptr;
353template <
typename TVersionType>
354class VariantSetVersionHelper
357 VariantSetVersionHelper(TVersionType version,
bool& updated,
void* storage) :
364 template <std::
size_t TIdx,
typename TField>
367 m_updated =
reinterpret_cast<TField*
>(m_storage)->setVersion(m_version) || m_updated;
371 TVersionType m_version = TVersionType();
373 void* m_storage =
nullptr;
377class VariantCanWriteHelper
380 VariantCanWriteHelper(
bool& result,
const void* storage)
386 template <std::
size_t TIdx,
typename TField>
389 m_result =
reinterpret_cast<const TField*
>(m_storage)->canWrite();
394 const void* m_storage;
397template <
typename TFieldBase, comms::field::details::MembersVersionDependency TVersionDependency,
typename... TMembers>
398struct VariantVersionStorageBaseHelper;
400template <
typename TFieldBase,
typename... TMembers>
401struct VariantVersionStorageBaseHelper<TFieldBase,
comms::field::details::MembersVersionDependency_NotSpecified, TMembers...>
404 typename comms::util::LazyShallowConditional<
405 CommonFuncs::IsAnyFieldVersionDependentBoolType<TMembers...>::value
407 comms::field::details::VersionStorage,
408 comms::util::EmptyStruct,
409 typename TFieldBase::VersionType
413template <
typename TFieldBase,
typename... TMembers>
414struct VariantVersionStorageBaseHelper<TFieldBase,
comms::field::details::MembersVersionDependency_Independent, TMembers...>
416 using Type = comms::util::EmptyStruct<>;
419template <
typename TFieldBase,
typename... TMembers>
420struct VariantVersionStorageBaseHelper<TFieldBase,
comms::field::details::MembersVersionDependency_Dependent, TMembers...>
422 using Type = comms::field::details::VersionStorage<typename TFieldBase::VersionType>;
425template <
typename TFieldBase, comms::field::details::MembersVersionDependency TVersionDependency,
typename... TMembers>
426using VariantVersionStorageBase =
427 typename VariantVersionStorageBaseHelper<TFieldBase, TVersionDependency, TMembers...>::Type;
429template <comms::field::details::MembersVersionDependency TVersionDependency,
typename... TMembers>
430struct VariantVersionDependencyDetectHelper;
432template <
typename... TMembers>
433struct VariantVersionDependencyDetectHelper<
comms::field::details::MembersVersionDependency_NotSpecified, TMembers...>
435 static constexpr bool Value = CommonFuncs::IsAnyFieldVersionDependentBoolType<TMembers...>::value;
438template <
typename... TMembers>
439struct VariantVersionDependencyDetectHelper<
comms::field::details::MembersVersionDependency_Independent, TMembers...>
441 static constexpr bool Value =
false;
444template <
typename... TMembers>
445struct VariantVersionDependencyDetectHelper<
comms::field::details::MembersVersionDependency_Dependent, TMembers...>
447 static constexpr bool Value =
true;
452template <
typename TFieldBase, comms::field::details::MembersVersionDependency TVersionDependency,
typename TMembers>
455template <
typename TFieldBase, comms::field::details::MembersVersionDependency TVersionDependency,
typename... TMembers>
456class Variant<TFieldBase, TVersionDependency,
std::tuple<TMembers...> > :
458 public details::VariantVersionStorageBase<TFieldBase, TVersionDependency, TMembers...>
460 using BaseImpl = TFieldBase;
461 using VersionBaseImpl = details::VariantVersionStorageBase<TFieldBase, TVersionDependency, TMembers...>;
464 using Members = std::tuple<TMembers...>;
466 using VersionType =
typename BaseImpl::VersionType;
467 using CommsTag = comms::field::tag::Variant;
469 static const std::size_t MembersCount = std::tuple_size<Members>::value;
470 static_assert(0U < MembersCount,
"ValueType must be non-empty tuple");
473 Variant(
const ValueType& val) : m_storage(val) {}
474 Variant(ValueType&& val) : m_storage(
std::move(val)) {}
476 Variant(
const Variant& other)
478 if (!other.currentFieldValid()) {
482 comms::util::tupleForSelectedType<Members>(
483 other.m_memIdx, details::VariantFieldCopyConstructHelper<>(&m_storage, &other.m_storage));
485 m_memIdx = other.m_memIdx;
488 Variant(Variant&& other)
490 if (!other.currentFieldValid()) {
494 comms::util::tupleForSelectedType<Members>(
495 other.m_memIdx, details::VariantFieldMoveConstructHelper<>(&m_storage, &other.m_storage));
497 m_memIdx = other.m_memIdx;
505 Variant& operator=(
const Variant& other)
507 if (
this == &other) {
512 if (!other.currentFieldValid()) {
516 comms::util::tupleForSelectedType<Members>(
517 other.m_memIdx, details::VariantFieldCopyConstructHelper<>(&m_storage, &other.m_storage));
519 m_memIdx = other.m_memIdx;
523 Variant& operator=(Variant&& other)
525 if (
this == &other) {
531 if (!other.currentFieldValid()) {
535 comms::util::tupleForSelectedType<Members>(
536 other.m_memIdx, details::VariantFieldMoveConstructHelper<>(&m_storage, &other.m_storage));
538 m_memIdx = other.m_memIdx;
542 const ValueType& value()
const
552 const ValueType& getValue()
const
557 template <
typename T>
558 void setValue(T&& val)
560 value() = std::forward<T>(val);
563 std::size_t length()
const
565 if (!currentFieldValid()) {
569 std::size_t len = std::numeric_limits<std::size_t>::max();
570 comms::util::tupleForSelectedType<Members>(m_memIdx, details::VariantLengthCalcHelper<>(len, &m_storage));
574 static constexpr std::size_t minLength()
579 static constexpr std::size_t maxLength()
581 return CommonFuncs::FieldSelectMaxLengthIntType<TMembers...>::value;
586 if (!currentFieldValid()) {
591 comms::util::tupleForSelectedType<Members>(
592 m_memIdx, details::VariantFieldValidCheckHelper<>(val, &m_storage));
596 static constexpr bool hasNonDefaultRefresh()
598 return CommonFuncs::AnyFieldHasNonDefaultRefreshBoolType<TMembers...>::value;
603 if (!currentFieldValid()) {
608 comms::util::tupleForSelectedType<Members>(
609 m_memIdx, details::VariantFieldRefreshHelper<>(val, &m_storage));
613 template <
typename TIter>
618 comms::util::tupleForEachType<Members>(makeReadHelper(es, iter, len, &m_storage,
static_cast<VersionBaseImpl&
>(*
this)));
625 static constexpr bool hasReadNoStatus()
630 template <
typename TIter>
631 void readNoStatus(TIter& iter) =
delete;
633 bool canWrite()
const
635 if (!currentFieldValid()) {
640 comms::util::tupleForSelectedType<Members>(
641 m_memIdx, details::VariantCanWriteHelper<>(val, &m_storage));
645 template <
typename TIter>
646 ErrorStatus write(TIter& iter, std::size_t len)
const
648 if (!currentFieldValid()) {
652 auto es = ErrorStatus::NumOfErrorStatuses;
653 comms::util::tupleForSelectedType<Members>(m_memIdx, makeWriteHelper(es, iter, len, &m_storage));
657 static constexpr bool hasWriteNoStatus()
659 return comms::util::tupleTypeAccumulate<Members>(
660 true, comms::field::details::FieldHasWriteNoStatusHelper<>());
663 template <
typename TIter>
664 void writeNoStatus(TIter& iter)
const
666 if (!currentFieldValid()) {
670 comms::util::tupleForSelectedType<Members>(m_memIdx, makeWriteNoStatusHelper(iter, &m_storage));
673 std::size_t currentField()
const
678 void selectField(std::size_t idx)
680 if (idx == m_memIdx) {
685 if (!isIdxValid(idx)) {
689 comms::util::tupleForSelectedType<Members>(
690 idx, details::VariantFieldConstructHelper<>(&m_storage));
694 template <
typename TFunc>
695 void currentFieldExec(TFunc&& func)
697 if (!currentFieldValid()) {
698 static constexpr bool Invalid_field_execution =
false;
699 static_cast<void>(Invalid_field_execution);
704 comms::util::tupleForSelectedType<Members>(m_memIdx, makeExecHelper(std::forward<TFunc>(func)));
707 template <
typename TFunc>
708 void currentFieldExec(TFunc&& func)
const
710 if (!currentFieldValid()) {
711 static constexpr bool Invalid_field_execution =
false;
712 static_cast<void>(Invalid_field_execution);
717 comms::util::tupleForSelectedType<Members>(m_memIdx, makeConstExecHelper(std::forward<TFunc>(func)));
720 template <std::size_t TIdx,
typename... TArgs>
721 typename std::tuple_element<TIdx, Members>::type& initField(TArgs&&... args)
723 static_assert(isIdxValid(TIdx),
"Only valid field index can be used");
726 using FieldType =
typename std::tuple_element<TIdx, Members>::type;
727 new (&m_storage)
FieldType(std::forward<TArgs>(args)...);
729 updateVersionInternal(VersionTag<>());
730 return reinterpret_cast<FieldType&
>(m_storage);
733 template <std::
size_t TIdx>
736 static_assert(isIdxValid(TIdx),
"Only valid field index can be used");
739 using FieldType =
typename std::tuple_element<TIdx, Members>::type;
741 m_memIdx = MembersCount;
744 template <std::
size_t TIdx>
745 typename std::tuple_element<TIdx, Members>::type& accessField()
747 static_assert(isIdxValid(TIdx),
"Only valid field index can be used");
750 using FieldType =
typename std::tuple_element<TIdx, Members>::type;
751 return reinterpret_cast<FieldType&
>(m_storage);
754 template <std::
size_t TIdx>
755 const typename std::tuple_element<TIdx, Members>::type& accessField()
const
757 static_assert(isIdxValid(TIdx),
"Something is wrong");
760 using FieldType =
typename std::tuple_element<TIdx, Members>::type;
761 return reinterpret_cast<const FieldType&
>(m_storage);
764 bool currentFieldValid()
const
766 return isIdxValid(m_memIdx);
775 static constexpr bool isVersionDependent()
777 return details::VariantVersionDependencyDetectHelper<TVersionDependency, TMembers...>::Value;
780 bool setVersion(VersionType version)
782 return setVersionInternal(version, VersionTag<>());
787 return getVersionInternal(VersionTag<>());
791 template <
typename... TParams>
792 using VersionDependentTag = comms::details::tag::Tag1<>;
794 template <
typename... TParams>
795 using NoVersionDependencyTag = comms::details::tag::Tag2<>;
797 template <
typename... TParams>
798 using ForcedVersionDependencyTag = comms::details::tag::Tag3<>;
800 template <
typename... TParams>
801 using NoForcedVersionDependencyTag = comms::details::tag::Tag4<>;
803 template <
typename... TParams>
805 typename comms::util::LazyShallowConditional<
806 details::VariantVersionDependencyDetectHelper<TVersionDependency, TMembers...>::Value
809 NoVersionDependencyTag
812 template <
typename TFunc>
813 auto makeExecHelper(TFunc&& func) -> details::VariantExecHelper<decltype(std::forward<TFunc>(func))>
815 using FuncType =
decltype(std::forward<TFunc>(func));
816 return details::VariantExecHelper<FuncType>(&m_storage, std::forward<TFunc>(func));
819 template <
typename TFunc>
820 auto makeConstExecHelper(TFunc&& func)
const -> details::VariantConstExecHelper<decltype(std::forward<TFunc>(func))>
822 using FuncType =
decltype(std::forward<TFunc>(func));
823 return details::VariantConstExecHelper<FuncType>(&m_storage, std::forward<TFunc>(func));
826 template <
typename TIter,
typename TVerBase>
827 details::VariantReadHelper<TIter, TVerBase, details::VariantVersionDependencyDetectHelper<TVersionDependency, TMembers...>::Value>
836 static constexpr bool VerDependent = isVersionDependent();
838 details::VariantReadHelper<TIter, TVerBase, VerDependent>(
839 m_memIdx, es, iter, len, storage, verBase);
842 template <
typename TIter>
843 static details::VariantFieldWriteHelper<TIter> makeWriteHelper(
comms::ErrorStatus& es, TIter& iter, std::size_t len,
const void* storage)
845 return details::VariantFieldWriteHelper<TIter>(es, iter, len, storage);
848 template <
typename TIter>
849 static details::VariantWriteNoStatusHelper<TIter> makeWriteNoStatusHelper(TIter& iter,
const void* storage)
851 return details::VariantWriteNoStatusHelper<TIter>(iter, storage);
856 if (currentFieldValid()) {
857 comms::util::tupleForSelectedType<Members>(
858 m_memIdx, details::VariantFieldDestructHelper<>(&m_storage));
859 m_memIdx = MembersCount;
863 static constexpr bool isIdxValid(std::size_t idx)
865 return idx < MembersCount;
868 template <
typename... TParams>
869 bool setVersionInternal(VersionType version, NoVersionDependencyTag<TParams...>)
875 template <
typename... TParams>
876 bool setVersionInternal(VersionType version, VersionDependentTag<TParams...>)
878 VersionBaseImpl::m_version =
version;
879 bool updated =
false;
880 if (currentFieldValid()) {
881 comms::util::tupleForSelectedType<Members>(
882 m_memIdx, details::VariantSetVersionHelper<VersionType>(version, updated, &m_storage));
887 template <
typename... TParams>
888 VersionType getVersionInternal(VersionDependentTag<TParams...>)
const
890 return VersionBaseImpl::m_version;;
893 template <
typename... TParams>
894 void updateVersionInternal(NoVersionDependencyTag<TParams...>)
898 template <
typename... TParams>
899 void updateVersionInternal(VersionDependentTag<TParams...>)
901 setVersion(VersionBaseImpl::m_version);
904 alignas(8) ValueType m_storage;
905 std::size_t m_memIdx = MembersCount;
914COMMS_MSVC_WARNING_POP
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.
This file contain definition of error statuses used by comms module.
Contains various tuple type manipulation classes and functions.
Contains definition of various tag classes.
comms::option::def::VersionType< T > VersionType
Same as comms::option::def::VersionType.
Definition options.h:1928
comms::option::def::FieldType< TMsg > FieldType
Same as comms::option::def::FieldType.
Definition options.h:1503
typename TupleAsAlignedUnion< TTuple >::Type TupleAsAlignedUnionT
Alias to TupleAsAlignedUnion::Type.
Definition Tuple.h:185
Main namespace for all classes / functions of COMMS library.
ErrorStatus
Error statuses reported by the Communication module.
Definition ErrorStatus.h:17
@ Success
Used to indicate successful outcome of the operation.
@ NumOfErrorStatuses
Number of supported error statuses, must be last.
constexpr unsigned version()
Version of the COMMS library as single numeric value.
Definition version.h:64
Replacement to some types from standard type_traits.