14#include "comms/details/tag.h"
16#include "comms/field/basic/CommonFuncs.h"
17#include "comms/field/details/FieldOpHelpers.h"
18#include "comms/field/details/MembersVersionDependency.h"
19#include "comms/field/details/VersionStorage.h"
31COMMS_MSVC_WARNING_PUSH
32COMMS_MSVC_WARNING_DISABLE(4324)
47class VariantFieldConstructHelper
50 VariantFieldConstructHelper(
void* storage) : m_storage(storage) {}
52 template <std::
size_t TIdx,
typename TField>
53 void operator()()
const
55 new (m_storage) TField;
58 void* m_storage =
nullptr;
62class VariantLengthCalcHelper
65 VariantLengthCalcHelper(std::size_t& len,
const void* storage) :
71 template <std::
size_t TIdx,
typename TField>
74 m_len =
reinterpret_cast<const TField*
>(m_storage)->length();
79 const void* m_storage;
83class VariantFieldCopyConstructHelper
86 VariantFieldCopyConstructHelper(
void* storage,
const void* other) : m_storage(storage), m_other(other) {}
88 template <std::
size_t TIdx,
typename TField>
89 void operator()()
const
91 new (m_storage) TField(*(
reinterpret_cast<const TField*
>(m_other)));
95 void* m_storage =
nullptr;
96 const void* m_other =
nullptr;
100class VariantFieldMoveConstructHelper
103 VariantFieldMoveConstructHelper(
void* storage,
void* other) : m_storage(storage), m_other(other) {}
105 template <std::
size_t TIdx,
typename TField>
106 void operator()()
const
108 new (m_storage) TField(std::move(*(
reinterpret_cast<const TField*
>(m_other))));
112 void* m_storage =
nullptr;
113 void* m_other =
nullptr;
117class VariantFieldDestructHelper
120 VariantFieldDestructHelper(
void* storage) : m_storage(storage) {}
122 template <std::
size_t TIdx,
typename TField>
123 void operator()()
const
125 reinterpret_cast<TField*
>(m_storage)->~TField();
128 void* m_storage =
nullptr;
131template <
typename...>
132class VariantFieldValidCheckHelper
135 VariantFieldValidCheckHelper(
bool& result,
const void* storage)
141 template <std::
size_t TIdx,
typename TField>
144 m_result =
reinterpret_cast<const TField*
>(m_storage)->valid();
149 const void* m_storage;
152template <
typename...>
153class VariantFieldRefreshHelper
156 VariantFieldRefreshHelper(
bool& result,
void* storage)
162 template <std::
size_t TIdx,
typename TField>
165 m_result =
reinterpret_cast<TField*
>(m_storage)->refresh();
170 void* m_storage =
nullptr;
173template <
typename TFunc>
174class VariantExecHelper
176 static_assert(std::is_lvalue_reference<TFunc>::value || std::is_rvalue_reference<TFunc>::value,
177 "Wrong type of template parameter");
179 template <
typename U>
180 VariantExecHelper(
void* storage, U&& func) : m_storage(storage), m_func(
std::forward<U>(func)) {}
182 template <std::
size_t TIdx,
typename TField>
187 m_func.operator()<TIdx>(*(
reinterpret_cast<TField*
>(m_storage)));
189 m_func.template operator()<TIdx>(*(
reinterpret_cast<TField*
>(m_storage)));
193 void* m_storage =
nullptr;
197template <
typename TFunc>
198class VariantConstExecHelper
200 static_assert(std::is_lvalue_reference<TFunc>::value || std::is_rvalue_reference<TFunc>::value,
201 "Wrong type of template parameter");
203 template <
typename U>
204 VariantConstExecHelper(
const void* storage, U&& func) : m_storage(storage), m_func(
std::forward<U>(func)) {}
206 template <std::
size_t TIdx,
typename TField>
211 m_func.operator()<TIdx>(*(
reinterpret_cast<const TField*
>(m_storage)));
213 m_func.template operator()<TIdx>(*(
reinterpret_cast<const TField*
>(m_storage)));
217 const void* m_storage =
nullptr;
221template <
typename TIter,
typename TVerBase,
bool TVerDependent>
222class VariantReadHelper
224 template <
typename... TParams>
225 using VersionDependentTag = comms::details::tag::Tag1<>;
227 template <
typename... TParams>
228 using NoVersionDependencyTag = comms::details::tag::Tag2<>;
230 template <
typename... TParams>
232 typename comms::util::LazyShallowConditional<
236 NoVersionDependencyTag
253 using IterType =
typename std::decay<
decltype(iter)>::type;
254 using IterCategory =
typename std::iterator_traits<IterType>::iterator_category;
255 static_assert(std::is_base_of<std::random_access_iterator_tag, IterCategory>::value,
256 "Variant field only supports read with random access iterators");
261 template <
typename TField>
264 if (m_readComplete) {
268 auto* field =
new (m_storage) TField;
269 updateMemberVersionInternal(*field, VersionTag<>());
271 auto iterTmp = m_iter;
272 auto es = field->read(iterTmp, m_len);
276 m_readComplete =
true;
291 template <
typename TField,
typename... TParams>
292 void updateMemberVersionInternal(TField& field, NoVersionDependencyTag<TParams...>)
294 static_cast<void>(field);
297 template <
typename TField,
typename... TParams>
298 void updateMemberVersionInternal(TField& field, VersionDependentTag<TParams...>)
300 field.setVersion(m_verBase.getVersion());
306 std::size_t m_len = 0;
307 void* m_storage =
nullptr;
309 bool m_readComplete =
false;
312template <
typename TIter>
313class VariantFieldWriteHelper
316 VariantFieldWriteHelper(ErrorStatus& es, TIter& iter, std::size_t len,
const void* storage)
324 template <std::
size_t TIdx,
typename TField>
327 m_es =
reinterpret_cast<const TField*
>(m_storage)->write(m_iter, m_len);
333 std::size_t m_len = 0U;
334 const void* m_storage =
nullptr;
337template <
typename TIter>
338class VariantWriteNoStatusHelper
341 VariantWriteNoStatusHelper(TIter& iter,
const void* storage)
347 template <std::
size_t TIdx,
typename TField>
350 reinterpret_cast<const TField*
>(m_storage)->writeNoStatus(m_iter);
355 const void* m_storage =
nullptr;
358template <
typename TVersionType>
359class VariantSetVersionHelper
362 VariantSetVersionHelper(TVersionType version,
bool& updated,
void* storage) :
369 template <std::
size_t TIdx,
typename TField>
372 m_updated =
reinterpret_cast<TField*
>(m_storage)->setVersion(m_version) || m_updated;
376 TVersionType m_version = TVersionType();
378 void* m_storage =
nullptr;
382class VariantCanWriteHelper
385 VariantCanWriteHelper(
bool& result,
const void* storage)
391 template <std::
size_t TIdx,
typename TField>
394 m_result =
reinterpret_cast<const TField*
>(m_storage)->canWrite();
399 const void* m_storage;
402template <
typename TFieldBase, comms::field::details::MembersVersionDependency TVersionDependency,
typename... TMembers>
403struct VariantVersionStorageBaseHelper;
405template <
typename TFieldBase,
typename... TMembers>
406struct VariantVersionStorageBaseHelper<TFieldBase,
comms::field::details::MembersVersionDependency_NotSpecified, TMembers...>
409 typename comms::util::LazyShallowConditional<
410 CommonFuncs::IsAnyFieldVersionDependentBoolType<TMembers...>::value
412 comms::field::details::VersionStorage,
413 comms::util::EmptyStruct,
414 typename TFieldBase::VersionType
418template <
typename TFieldBase,
typename... TMembers>
419struct VariantVersionStorageBaseHelper<TFieldBase,
comms::field::details::MembersVersionDependency_Independent, TMembers...>
421 using Type = comms::util::EmptyStruct<>;
424template <
typename TFieldBase,
typename... TMembers>
425struct VariantVersionStorageBaseHelper<TFieldBase,
comms::field::details::MembersVersionDependency_Dependent, TMembers...>
427 using Type = comms::field::details::VersionStorage<typename TFieldBase::VersionType>;
430template <
typename TFieldBase, comms::field::details::MembersVersionDependency TVersionDependency,
typename... TMembers>
431using VariantVersionStorageBase =
432 typename VariantVersionStorageBaseHelper<TFieldBase, TVersionDependency, TMembers...>::Type;
434template <comms::field::details::MembersVersionDependency TVersionDependency,
typename... TMembers>
435struct VariantVersionDependencyDetectHelper;
437template <
typename... TMembers>
438struct VariantVersionDependencyDetectHelper<
comms::field::details::MembersVersionDependency_NotSpecified, TMembers...>
440 static constexpr bool Value = CommonFuncs::IsAnyFieldVersionDependentBoolType<TMembers...>::value;
443template <
typename... TMembers>
444struct VariantVersionDependencyDetectHelper<
comms::field::details::MembersVersionDependency_Independent, TMembers...>
446 static constexpr bool Value =
false;
449template <
typename... TMembers>
450struct VariantVersionDependencyDetectHelper<
comms::field::details::MembersVersionDependency_Dependent, TMembers...>
452 static constexpr bool Value =
true;
457template <
typename TFieldBase, comms::field::details::MembersVersionDependency TVersionDependency,
typename TMembers>
460template <
typename TFieldBase, comms::field::details::MembersVersionDependency TVersionDependency,
typename... TMembers>
461class Variant<TFieldBase, TVersionDependency,
std::tuple<TMembers...> > :
463 public details::VariantVersionStorageBase<TFieldBase, TVersionDependency, TMembers...>
465 using BaseImpl = TFieldBase;
466 using VersionBaseImpl = details::VariantVersionStorageBase<TFieldBase, TVersionDependency, TMembers...>;
469 using Members = std::tuple<TMembers...>;
471 using VersionType =
typename BaseImpl::VersionType;
472 using CommsTag = comms::field::tag::Variant;
474 static const std::size_t MembersCount = std::tuple_size<Members>::value;
475 static_assert(0U < MembersCount,
"ValueType must be non-empty tuple");
478 Variant(
const ValueType& val) : m_storage(val) {}
479 Variant(ValueType&& val) : m_storage(
std::move(val)) {}
481 Variant(
const Variant& other)
483 if (!other.currentFieldValid()) {
487 comms::util::tupleForSelectedType<Members>(
488 other.m_memIdx, details::VariantFieldCopyConstructHelper<>(&m_storage, &other.m_storage));
490 m_memIdx = other.m_memIdx;
493 Variant(Variant&& other)
495 if (!other.currentFieldValid()) {
499 comms::util::tupleForSelectedType<Members>(
500 other.m_memIdx, details::VariantFieldMoveConstructHelper<>(&m_storage, &other.m_storage));
502 m_memIdx = other.m_memIdx;
510 Variant& operator=(
const Variant& other)
512 if (
this == &other) {
517 if (!other.currentFieldValid()) {
521 comms::util::tupleForSelectedType<Members>(
522 other.m_memIdx, details::VariantFieldCopyConstructHelper<>(&m_storage, &other.m_storage));
524 m_memIdx = other.m_memIdx;
528 Variant& operator=(Variant&& other)
530 if (
this == &other) {
536 if (!other.currentFieldValid()) {
540 comms::util::tupleForSelectedType<Members>(
541 other.m_memIdx, details::VariantFieldMoveConstructHelper<>(&m_storage, &other.m_storage));
543 m_memIdx = other.m_memIdx;
547 const ValueType& value()
const
557 const ValueType& getValue()
const
562 template <
typename T>
563 void setValue(T&& val)
565 value() = std::forward<T>(val);
568 std::size_t length()
const
570 if (!currentFieldValid()) {
574 std::size_t len = std::numeric_limits<std::size_t>::max();
575 comms::util::tupleForSelectedType<Members>(m_memIdx, details::VariantLengthCalcHelper<>(len, &m_storage));
579 static constexpr std::size_t minLength()
584 static constexpr std::size_t maxLength()
586 return CommonFuncs::FieldSelectMaxLengthIntType<TMembers...>::value;
591 if (!currentFieldValid()) {
596 comms::util::tupleForSelectedType<Members>(
597 m_memIdx, details::VariantFieldValidCheckHelper<>(val, &m_storage));
601 static constexpr bool hasNonDefaultRefresh()
603 return CommonFuncs::AnyFieldHasNonDefaultRefreshBoolType<TMembers...>::value;
608 if (!currentFieldValid()) {
613 comms::util::tupleForSelectedType<Members>(
614 m_memIdx, details::VariantFieldRefreshHelper<>(val, &m_storage));
618 template <
typename TIter>
623 comms::util::tupleForEachType<Members>(makeReadHelper(es, iter, len, &m_storage,
static_cast<VersionBaseImpl&
>(*
this)));
630 static constexpr bool hasReadNoStatus()
635 template <
typename TIter>
636 void readNoStatus(TIter& iter) =
delete;
638 bool canWrite()
const
640 if (!currentFieldValid()) {
645 comms::util::tupleForSelectedType<Members>(
646 m_memIdx, details::VariantCanWriteHelper<>(val, &m_storage));
650 template <
typename TIter>
651 ErrorStatus write(TIter& iter, std::size_t len)
const
653 if (!currentFieldValid()) {
657 auto es = ErrorStatus::NumOfErrorStatuses;
658 comms::util::tupleForSelectedType<Members>(m_memIdx, makeWriteHelper(es, iter, len, &m_storage));
662 static constexpr bool hasWriteNoStatus()
664 return comms::util::tupleTypeAccumulate<Members>(
665 true, comms::field::details::FieldHasWriteNoStatusHelper<>());
668 template <
typename TIter>
669 void writeNoStatus(TIter& iter)
const
671 if (!currentFieldValid()) {
675 comms::util::tupleForSelectedType<Members>(m_memIdx, makeWriteNoStatusHelper(iter, &m_storage));
678 std::size_t currentField()
const
683 void selectField(std::size_t idx)
685 if (idx == m_memIdx) {
690 if (!isIdxValid(idx)) {
694 comms::util::tupleForSelectedType<Members>(
695 idx, details::VariantFieldConstructHelper<>(&m_storage));
699 template <
typename TFunc>
700 void currentFieldExec(TFunc&& func)
702 if (!currentFieldValid()) {
703 static constexpr bool Invalid_field_execution =
false;
704 static_cast<void>(Invalid_field_execution);
709 comms::util::tupleForSelectedType<Members>(m_memIdx, makeExecHelper(std::forward<TFunc>(func)));
712 template <
typename TFunc>
713 void currentFieldExec(TFunc&& func)
const
715 if (!currentFieldValid()) {
716 static constexpr bool Invalid_field_execution =
false;
717 static_cast<void>(Invalid_field_execution);
722 comms::util::tupleForSelectedType<Members>(m_memIdx, makeConstExecHelper(std::forward<TFunc>(func)));
725 template <std::size_t TIdx,
typename... TArgs>
726 typename std::tuple_element<TIdx, Members>::type& initField(TArgs&&... args)
728 static_assert(isIdxValid(TIdx),
"Only valid field index can be used");
731 using FieldType =
typename std::tuple_element<TIdx, Members>::type;
732 new (&m_storage)
FieldType(std::forward<TArgs>(args)...);
734 updateVersionInternal(VersionTag<>());
735 return reinterpret_cast<FieldType&
>(m_storage);
738 template <std::
size_t TIdx>
741 static_assert(isIdxValid(TIdx),
"Only valid field index can be used");
744 using FieldType =
typename std::tuple_element<TIdx, Members>::type;
746 m_memIdx = MembersCount;
749 template <std::
size_t TIdx>
750 typename std::tuple_element<TIdx, Members>::type& accessField()
752 static_assert(isIdxValid(TIdx),
"Only valid field index can be used");
755 using FieldType =
typename std::tuple_element<TIdx, Members>::type;
756 return reinterpret_cast<FieldType&
>(m_storage);
759 template <std::
size_t TIdx>
760 const typename std::tuple_element<TIdx, Members>::type& accessField()
const
762 static_assert(isIdxValid(TIdx),
"Something is wrong");
765 using FieldType =
typename std::tuple_element<TIdx, Members>::type;
766 return reinterpret_cast<const FieldType&
>(m_storage);
769 bool currentFieldValid()
const
771 return isIdxValid(m_memIdx);
780 static constexpr bool isVersionDependent()
782 return details::VariantVersionDependencyDetectHelper<TVersionDependency, TMembers...>::Value;
785 bool setVersion(VersionType version)
787 return setVersionInternal(version, VersionTag<>());
792 return getVersionInternal(VersionTag<>());
796 template <
typename... TParams>
797 using VersionDependentTag = comms::details::tag::Tag1<>;
799 template <
typename... TParams>
800 using NoVersionDependencyTag = comms::details::tag::Tag2<>;
802 template <
typename... TParams>
803 using ForcedVersionDependencyTag = comms::details::tag::Tag3<>;
805 template <
typename... TParams>
806 using NoForcedVersionDependencyTag = comms::details::tag::Tag4<>;
808 template <
typename... TParams>
810 typename comms::util::LazyShallowConditional<
811 details::VariantVersionDependencyDetectHelper<TVersionDependency, TMembers...>::Value
814 NoVersionDependencyTag
817 template <
typename TFunc>
818 auto makeExecHelper(TFunc&& func) -> details::VariantExecHelper<decltype(std::forward<TFunc>(func))>
820 using FuncType =
decltype(std::forward<TFunc>(func));
821 return details::VariantExecHelper<FuncType>(&m_storage, std::forward<TFunc>(func));
824 template <
typename TFunc>
825 auto makeConstExecHelper(TFunc&& func)
const -> details::VariantConstExecHelper<decltype(std::forward<TFunc>(func))>
827 using FuncType =
decltype(std::forward<TFunc>(func));
828 return details::VariantConstExecHelper<FuncType>(&m_storage, std::forward<TFunc>(func));
831 template <
typename TIter,
typename TVerBase>
832 details::VariantReadHelper<TIter, TVerBase, details::VariantVersionDependencyDetectHelper<TVersionDependency, TMembers...>::Value>
841 static constexpr bool VerDependent = isVersionDependent();
843 details::VariantReadHelper<TIter, TVerBase, VerDependent>(
844 m_memIdx, es, iter, len, storage, verBase);
847 template <
typename TIter>
848 static details::VariantFieldWriteHelper<TIter> makeWriteHelper(
comms::ErrorStatus& es, TIter& iter, std::size_t len,
const void* storage)
850 return details::VariantFieldWriteHelper<TIter>(es, iter, len, storage);
853 template <
typename TIter>
854 static details::VariantWriteNoStatusHelper<TIter> makeWriteNoStatusHelper(TIter& iter,
const void* storage)
856 return details::VariantWriteNoStatusHelper<TIter>(iter, storage);
861 if (currentFieldValid()) {
862 comms::util::tupleForSelectedType<Members>(
863 m_memIdx, details::VariantFieldDestructHelper<>(&m_storage));
864 m_memIdx = MembersCount;
868 static constexpr bool isIdxValid(std::size_t idx)
870 return idx < MembersCount;
873 template <
typename... TParams>
874 bool setVersionInternal(VersionType version, NoVersionDependencyTag<TParams...>)
880 template <
typename... TParams>
881 bool setVersionInternal(VersionType version, VersionDependentTag<TParams...>)
883 VersionBaseImpl::m_version =
version;
884 bool updated =
false;
885 if (currentFieldValid()) {
886 comms::util::tupleForSelectedType<Members>(
887 m_memIdx, details::VariantSetVersionHelper<VersionType>(version, updated, &m_storage));
892 template <
typename... TParams>
893 VersionType getVersionInternal(VersionDependentTag<TParams...>)
const
895 return VersionBaseImpl::m_version;;
898 template <
typename... TParams>
899 void updateVersionInternal(NoVersionDependencyTag<TParams...>)
903 template <
typename... TParams>
904 void updateVersionInternal(VersionDependentTag<TParams...>)
906 setVersion(VersionBaseImpl::m_version);
909 alignas(8) ValueType m_storage;
910 std::size_t m_memIdx = MembersCount;
919COMMS_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:1930
comms::option::def::FieldType< TMsg > FieldType
Same as comms::option::def::FieldType.
Definition options.h:1505
typename TupleAsAlignedUnion< TTuple >::Type TupleAsAlignedUnionT
Alias to TupleAsAlignedUnion::Type.
Definition Tuple.h:188
Main namespace for all classes / functions of COMMS library.
ErrorStatus
Error statuses reported by the Communication module.
Definition ErrorStatus.h:19
@ 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:66
Replacement to some types from standard type_traits.