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;
217template <
typename TIter,
typename TVerBase,
bool TVerDependent>
218class VariantReadHelper
220 template <
typename... TParams>
221 using VersionDependentTag = comms::details::tag::Tag1<>;
223 template <
typename... TParams>
224 using NoVersionDependencyTag = comms::details::tag::Tag2<>;
226 template <
typename... TParams>
228 typename comms::util::LazyShallowConditional<
232 NoVersionDependencyTag
249 using IterType =
typename std::decay<
decltype(iter)>::type;
250 using IterCategory =
typename std::iterator_traits<IterType>::iterator_category;
251 static_assert(std::is_base_of<std::random_access_iterator_tag, IterCategory>::value,
252 "Variant field only supports read with random access iterators");
257 template <
typename TField>
260 if (m_readComplete) {
264 auto* field =
new (m_storage) TField;
265 updateMemberVersionInternal(*field, VersionTag<>());
267 auto iterTmp = m_iter;
268 auto es = field->read(iterTmp, m_len);
272 m_readComplete =
true;
287 template <
typename TField,
typename... TParams>
288 void updateMemberVersionInternal(TField& field, NoVersionDependencyTag<TParams...>)
290 static_cast<void>(field);
293 template <
typename TField,
typename... TParams>
294 void updateMemberVersionInternal(TField& field, VersionDependentTag<TParams...>)
296 field.setVersion(m_verBase.getVersion());
302 std::size_t m_len = 0;
303 void* m_storage =
nullptr;
305 bool m_readComplete =
false;
308template <
typename TIter>
309class VariantFieldWriteHelper
312 VariantFieldWriteHelper(ErrorStatus& es, TIter& iter, std::size_t len,
const void* storage)
320 template <std::
size_t TIdx,
typename TField>
323 m_es =
reinterpret_cast<const TField*
>(m_storage)->write(m_iter, m_len);
329 std::size_t m_len = 0U;
330 const void* m_storage =
nullptr;
333template <
typename TIter>
334class VariantWriteNoStatusHelper
337 VariantWriteNoStatusHelper(TIter& iter,
const void* storage)
343 template <std::
size_t TIdx,
typename TField>
346 reinterpret_cast<const TField*
>(m_storage)->writeNoStatus(m_iter);
351 const void* m_storage =
nullptr;
354template <
typename TVersionType>
355class VariantSetVersionHelper
358 VariantSetVersionHelper(TVersionType version,
bool& updated,
void* storage) :
365 template <std::
size_t TIdx,
typename TField>
368 m_updated =
reinterpret_cast<TField*
>(m_storage)->setVersion(m_version) || m_updated;
372 TVersionType m_version = TVersionType();
374 void* m_storage =
nullptr;
378class VariantCanWriteHelper
381 VariantCanWriteHelper(
bool& result,
const void* storage)
387 template <std::
size_t TIdx,
typename TField>
390 m_result =
reinterpret_cast<const TField*
>(m_storage)->canWrite();
395 const void* m_storage;
398template <
typename TFieldBase, comms::field::details::MembersVersionDependency TVersionDependency,
typename... TMembers>
399struct VariantVersionStorageBaseHelper;
401template <
typename TFieldBase,
typename... TMembers>
402struct VariantVersionStorageBaseHelper<TFieldBase,
comms::field::details::MembersVersionDependency_NotSpecified, TMembers...>
405 typename comms::util::LazyShallowConditional<
406 CommonFuncs::IsAnyFieldVersionDependentBoolType<TMembers...>::value
408 comms::field::details::VersionStorage,
409 comms::util::EmptyStruct,
410 typename TFieldBase::VersionType
414template <
typename TFieldBase,
typename... TMembers>
415struct VariantVersionStorageBaseHelper<TFieldBase,
comms::field::details::MembersVersionDependency_Independent, TMembers...>
417 using Type = comms::util::EmptyStruct<>;
420template <
typename TFieldBase,
typename... TMembers>
421struct VariantVersionStorageBaseHelper<TFieldBase,
comms::field::details::MembersVersionDependency_Dependent, TMembers...>
423 using Type = comms::field::details::VersionStorage<typename TFieldBase::VersionType>;
426template <
typename TFieldBase, comms::field::details::MembersVersionDependency TVersionDependency,
typename... TMembers>
427using VariantVersionStorageBase =
428 typename VariantVersionStorageBaseHelper<TFieldBase, TVersionDependency, TMembers...>::Type;
430template <comms::field::details::MembersVersionDependency TVersionDependency,
typename... TMembers>
431struct VariantVersionDependencyDetectHelper;
433template <
typename... TMembers>
434struct VariantVersionDependencyDetectHelper<
comms::field::details::MembersVersionDependency_NotSpecified, TMembers...>
436 static constexpr bool Value = CommonFuncs::IsAnyFieldVersionDependentBoolType<TMembers...>::value;
439template <
typename... TMembers>
440struct VariantVersionDependencyDetectHelper<
comms::field::details::MembersVersionDependency_Independent, TMembers...>
442 static constexpr bool Value =
false;
445template <
typename... TMembers>
446struct VariantVersionDependencyDetectHelper<
comms::field::details::MembersVersionDependency_Dependent, TMembers...>
448 static constexpr bool Value =
true;
454template <
typename TFieldBase, comms::field::details::MembersVersionDependency TVersionDependency,
typename TMembers>
457template <
typename TFieldBase, comms::field::details::MembersVersionDependency TVersionDependency,
typename... TMembers>
458class Variant<TFieldBase, TVersionDependency,
std::tuple<TMembers...> > :
460 public details::VariantVersionStorageBase<TFieldBase, TVersionDependency, TMembers...>
462 using BaseImpl = TFieldBase;
463 using VersionBaseImpl = details::VariantVersionStorageBase<TFieldBase, TVersionDependency, TMembers...>;
466 using Members = std::tuple<TMembers...>;
468 using VersionType =
typename BaseImpl::VersionType;
469 using CommsTag = comms::field::tag::Variant;
471 static const std::size_t MembersCount = std::tuple_size<Members>::value;
472 static_assert(0U < MembersCount,
"ValueType must be non-empty tuple");
475 Variant(
const ValueType& val) : m_storage(val) {}
476 Variant(ValueType&& val) : m_storage(
std::move(val)) {}
478 Variant(
const Variant& other)
480 if (!other.currentFieldValid()) {
484 comms::util::tupleForSelectedType<Members>(
485 other.m_memIdx, details::VariantFieldCopyConstructHelper<>(&m_storage, &other.m_storage));
487 m_memIdx = other.m_memIdx;
490 Variant(Variant&& other)
492 if (!other.currentFieldValid()) {
496 comms::util::tupleForSelectedType<Members>(
497 other.m_memIdx, details::VariantFieldMoveConstructHelper<>(&m_storage, &other.m_storage));
499 m_memIdx = other.m_memIdx;
507 Variant& operator=(
const Variant& other)
509 if (
this == &other) {
514 if (!other.currentFieldValid()) {
518 comms::util::tupleForSelectedType<Members>(
519 other.m_memIdx, details::VariantFieldCopyConstructHelper<>(&m_storage, &other.m_storage));
521 m_memIdx = other.m_memIdx;
525 Variant& operator=(Variant&& other)
527 if (
this == &other) {
533 if (!other.currentFieldValid()) {
537 comms::util::tupleForSelectedType<Members>(
538 other.m_memIdx, details::VariantFieldMoveConstructHelper<>(&m_storage, &other.m_storage));
540 m_memIdx = other.m_memIdx;
544 const ValueType& value()
const
554 const ValueType& getValue()
const
559 template <
typename T>
560 void setValue(T&& val)
562 value() = std::forward<T>(val);
565 std::size_t length()
const
567 if (!currentFieldValid()) {
571 std::size_t len = std::numeric_limits<std::size_t>::max();
572 comms::util::tupleForSelectedType<Members>(m_memIdx, details::VariantLengthCalcHelper<>(len, &m_storage));
576 static constexpr std::size_t minLength()
581 static constexpr std::size_t maxLength()
583 return CommonFuncs::FieldSelectMaxLengthIntType<TMembers...>::value;
588 if (!currentFieldValid()) {
593 comms::util::tupleForSelectedType<Members>(
594 m_memIdx, details::VariantFieldValidCheckHelper<>(val, &m_storage));
598 static constexpr bool hasNonDefaultRefresh()
600 return CommonFuncs::AnyFieldHasNonDefaultRefreshBoolType<TMembers...>::value;
605 if (!currentFieldValid()) {
610 comms::util::tupleForSelectedType<Members>(
611 m_memIdx, details::VariantFieldRefreshHelper<>(val, &m_storage));
615 template <
typename TIter>
620 comms::util::tupleForEachType<Members>(makeReadHelper(es, iter, len, &m_storage,
static_cast<VersionBaseImpl&
>(*
this)));
627 static constexpr bool hasReadNoStatus()
632 template <
typename TIter>
633 void readNoStatus(TIter& iter) =
delete;
635 bool canWrite()
const
637 if (!currentFieldValid()) {
642 comms::util::tupleForSelectedType<Members>(
643 m_memIdx, details::VariantCanWriteHelper<>(val, &m_storage));
647 template <
typename TIter>
648 ErrorStatus write(TIter& iter, std::size_t len)
const
650 if (!currentFieldValid()) {
654 auto es = ErrorStatus::NumOfErrorStatuses;
655 comms::util::tupleForSelectedType<Members>(m_memIdx, makeWriteHelper(es, iter, len, &m_storage));
659 static constexpr bool hasWriteNoStatus()
661 return comms::util::tupleTypeAccumulate<Members>(
662 true, comms::field::details::FieldHasWriteNoStatusHelper<>());
665 template <
typename TIter>
666 void writeNoStatus(TIter& iter)
const
668 if (!currentFieldValid()) {
672 comms::util::tupleForSelectedType<Members>(m_memIdx, makeWriteNoStatusHelper(iter, &m_storage));
676 std::size_t currentField()
const
681 void selectField(std::size_t idx)
683 if (idx == m_memIdx) {
688 if (!isIdxValid(idx)) {
692 comms::util::tupleForSelectedType<Members>(
693 idx, details::VariantFieldConstructHelper<>(&m_storage));
697 template <
typename TFunc>
698 void currentFieldExec(TFunc&& func)
700 if (!currentFieldValid()) {
701 static constexpr bool Invalid_field_execution =
false;
702 static_cast<void>(Invalid_field_execution);
707 comms::util::tupleForSelectedType<Members>(m_memIdx, makeExecHelper(std::forward<TFunc>(func)));
710 template <
typename TFunc>
711 void currentFieldExec(TFunc&& func)
const
713 if (!currentFieldValid()) {
714 static constexpr bool Invalid_field_execution =
false;
715 static_cast<void>(Invalid_field_execution);
720 comms::util::tupleForSelectedType<Members>(m_memIdx, makeConstExecHelper(std::forward<TFunc>(func)));
723 template <std::size_t TIdx,
typename... TArgs>
724 typename std::tuple_element<TIdx, Members>::type& initField(TArgs&&... args)
726 static_assert(isIdxValid(TIdx),
"Only valid field index can be used");
729 using FieldType =
typename std::tuple_element<TIdx, Members>::type;
730 new (&m_storage)
FieldType(std::forward<TArgs>(args)...);
732 updateVersionInternal(VersionTag<>());
733 return reinterpret_cast<FieldType&
>(m_storage);
736 template <std::
size_t TIdx>
739 static_assert(isIdxValid(TIdx),
"Only valid field index can be used");
742 using FieldType =
typename std::tuple_element<TIdx, Members>::type;
744 m_memIdx = MembersCount;
747 template <std::
size_t TIdx>
748 typename std::tuple_element<TIdx, Members>::type& accessField()
750 static_assert(isIdxValid(TIdx),
"Only valid field index can be used");
753 using FieldType =
typename std::tuple_element<TIdx, Members>::type;
754 return reinterpret_cast<FieldType&
>(m_storage);
757 template <std::
size_t TIdx>
758 const typename std::tuple_element<TIdx, Members>::type& accessField()
const
760 static_assert(isIdxValid(TIdx),
"Something is wrong");
763 using FieldType =
typename std::tuple_element<TIdx, Members>::type;
764 return reinterpret_cast<const FieldType&
>(m_storage);
767 bool currentFieldValid()
const
769 return isIdxValid(m_memIdx);
778 static constexpr bool isVersionDependent()
780 return details::VariantVersionDependencyDetectHelper<TVersionDependency, TMembers...>::Value;
783 bool setVersion(VersionType version)
785 return setVersionInternal(version, VersionTag<>());
790 return getVersionInternal(VersionTag<>());
794 template <
typename... TParams>
795 using VersionDependentTag = comms::details::tag::Tag1<>;
797 template <
typename... TParams>
798 using NoVersionDependencyTag = comms::details::tag::Tag2<>;
800 template <
typename... TParams>
801 using ForcedVersionDependencyTag = comms::details::tag::Tag3<>;
803 template <
typename... TParams>
804 using NoForcedVersionDependencyTag = comms::details::tag::Tag4<>;
806 template <
typename... TParams>
808 typename comms::util::LazyShallowConditional<
809 details::VariantVersionDependencyDetectHelper<TVersionDependency, TMembers...>::Value
812 NoVersionDependencyTag
815 template <
typename TFunc>
816 auto makeExecHelper(TFunc&& func) -> details::VariantExecHelper<decltype(std::forward<TFunc>(func))>
818 using FuncType =
decltype(std::forward<TFunc>(func));
819 return details::VariantExecHelper<FuncType>(&m_storage, std::forward<TFunc>(func));
822 template <
typename TFunc>
823 auto makeConstExecHelper(TFunc&& func)
const -> details::VariantConstExecHelper<decltype(std::forward<TFunc>(func))>
825 using FuncType =
decltype(std::forward<TFunc>(func));
826 return details::VariantConstExecHelper<FuncType>(&m_storage, std::forward<TFunc>(func));
829 template <
typename TIter,
typename TVerBase>
830 details::VariantReadHelper<TIter, TVerBase, details::VariantVersionDependencyDetectHelper<TVersionDependency, TMembers...>::Value>
839 static constexpr bool VerDependent = isVersionDependent();
841 details::VariantReadHelper<TIter, TVerBase, VerDependent>(
842 m_memIdx, es, iter, len, storage, verBase);
845 template <
typename TIter>
846 static details::VariantFieldWriteHelper<TIter> makeWriteHelper(
comms::ErrorStatus& es, TIter& iter, std::size_t len,
const void* storage)
848 return details::VariantFieldWriteHelper<TIter>(es, iter, len, storage);
851 template <
typename TIter>
852 static details::VariantWriteNoStatusHelper<TIter> makeWriteNoStatusHelper(TIter& iter,
const void* storage)
854 return details::VariantWriteNoStatusHelper<TIter>(iter, storage);
859 if (currentFieldValid()) {
860 comms::util::tupleForSelectedType<Members>(
861 m_memIdx, details::VariantFieldDestructHelper<>(&m_storage));
862 m_memIdx = MembersCount;
866 static constexpr bool isIdxValid(std::size_t idx)
868 return idx < MembersCount;
871 template <
typename... TParams>
872 bool setVersionInternal(VersionType version, NoVersionDependencyTag<TParams...>)
878 template <
typename... TParams>
879 bool setVersionInternal(VersionType version, VersionDependentTag<TParams...>)
881 VersionBaseImpl::m_version =
version;
882 bool updated =
false;
883 if (currentFieldValid()) {
884 comms::util::tupleForSelectedType<Members>(
885 m_memIdx, details::VariantSetVersionHelper<VersionType>(version, updated, &m_storage));
891 template <
typename... TParams>
892 VersionType getVersionInternal(VersionDependentTag<TParams...>)
const
894 return VersionBaseImpl::m_version;;
897 template <
typename... TParams>
898 void updateVersionInternal(NoVersionDependencyTag<TParams...>)
902 template <
typename... TParams>
903 void updateVersionInternal(VersionDependentTag<TParams...>)
905 setVersion(VersionBaseImpl::m_version);
908 alignas(8) ValueType m_storage;
909 std::size_t m_memIdx = MembersCount;
918COMMS_MSVC_WARNING_POP
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.
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:1917
comms::option::def::FieldType< TMsg > FieldType
Same as comms::option::def::FieldType.
Definition options.h:1492
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.