COMMS
Template library intended to help with implementation of communication protocols.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Variant.h
Go to the documentation of this file.
1//
2// Copyright 2017 - 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
10
11#pragma once
12
13#include "comms/details/macro_common.h"
14#include "comms/details/variant_access.h"
15#include "comms/ErrorStatus.h"
16#include "comms/field/basic/Variant.h"
17#include "comms/field/details/AdaptBasicField.h"
18#include "comms/options.h"
19#include "comms/util/Tuple.h"
20
21namespace comms
22{
23
24namespace field
25{
26
73template <typename TFieldBase, typename TMembers, typename... TOptions>
74class Variant : public
75 details::AdaptBasicFieldT<
76 basic::Variant<
77 TFieldBase,
78 details::OptionsParser<TOptions...>::ForcedMembersVersionDependency,
79 TMembers
80 >,
81 TOptions...>
82{
83 using BaseImpl =
84 details::AdaptBasicFieldT<
85 basic::Variant<
86 TFieldBase,
87 details::OptionsParser<TOptions...>::ForcedMembersVersionDependency,
88 TMembers
89 >,
90 TOptions...>;
91
93 "TMembers is expected to be a tuple of std::tuple<...>");
94
95 static_assert(
96 1U <= std::tuple_size<TMembers>::value,
97 "Number of members is expected to be at least 1.");
98
99public:
101 using FieldBase = TFieldBase;
102
104 using Endian = typename BaseImpl::Endian;
105
107 using VersionType = typename BaseImpl::VersionType;
108
110 using ParsedOptions = details::OptionsParser<TOptions...>;
111
113 using CommsTag = typename BaseImpl::CommsTag;
114
118 using ValueType = typename BaseImpl::ValueType;
119
123 using Members = typename BaseImpl::Members;
124
128 using FieldType = typename ParsedOptions::FieldType;
129
132 Variant() = default;
133
135 explicit Variant(const ValueType& val)
136 : BaseImpl(val)
137 {
138 }
139
141 explicit Variant(ValueType&& val)
142 : BaseImpl(std::move(val))
143 {
144 }
145
148 static constexpr bool hasFailOnInvalid()
149 {
150 return ParsedOptions::HasFailOnInvalid;
151 }
152
155 static constexpr bool hasIgnoreInvalid()
156 {
157 return ParsedOptions::HasIgnoreInvalid;
158 }
159
162 static constexpr bool hasEmptySerialization()
163 {
164 return ParsedOptions::HasEmptySerialization;
165 }
166
169 static constexpr bool hasFieldType()
170 {
171 return ParsedOptions::HasFieldType;
172 }
173
176 static constexpr bool hasFixedValue()
177 {
178 return ParsedOptions::HasFixedValue;
179 }
180
183 static constexpr bool hasName()
184 {
185 return ParsedOptions::HasName;
186 }
187
191 {
192 return BaseImpl::value();
193 }
194
197 const ValueType& value() const
198 {
199 return BaseImpl::value();
200 }
201
204 const ValueType& getValue() const
205 {
206 return BaseImpl::getValue();
207 }
208
211 template <typename U>
212 void setValue(U&& val)
213 {
214 BaseImpl::setValue(std::forward<U>(val));
215 }
216
222 std::size_t length() const
223 {
224 return BaseImpl::length();
225 }
226
229 static constexpr std::size_t minLength()
230 {
231 return BaseImpl::minLength();
232 }
233
236 static constexpr std::size_t maxLength()
237 {
238 return BaseImpl::maxLength();
239 }
240
248 template <typename TIter>
249 ErrorStatus read(TIter& iter, std::size_t size)
250 {
251 return BaseImpl::read(iter, size);
252 }
253
256 static constexpr bool hasReadNoStatus()
257 {
258 return false;
259 }
260
262 template <typename TIter>
263 void readNoStatus(TIter& iter) = delete;
264
266 bool canWrite() const
267 {
268 return BaseImpl::canWrite();
269 }
270
279 template <typename TIter>
280 ErrorStatus write(TIter& iter, std::size_t size) const
281 {
282 return BaseImpl::write(iter, size);
283 }
284
287 static constexpr bool hasWriteNoStatus()
288 {
289 return BaseImpl::hasWriteNoStatus();
290 }
291
297 template <typename TIter>
298 void writeNoStatus(TIter& iter) const
299 {
300 BaseImpl::writeNoStatus(iter);
301 }
302
305 bool valid() const
306 {
307 return BaseImpl::valid();
308 }
309
314 bool refresh()
315 {
316 return BaseImpl::refresh();
317 }
318
322 std::size_t currentField() const
323 {
324 return BaseImpl::currentField();
325 }
326
334 void selectField(std::size_t idx)
335 {
336 BaseImpl::selectField(idx);
337 }
338
374 template <typename TFunc>
375 void currentFieldExec(TFunc&& func)
376 {
377 BaseImpl::currentFieldExec(std::forward<TFunc>(func));
378 }
379
397 template <typename TFunc>
398 void currentFieldExec(TFunc&& func) const
399 {
400 BaseImpl::currentFieldExec(std::forward<TFunc>(func));
401 }
402
416 template <std::size_t TIdx, typename... TArgs>
417 typename std::tuple_element<TIdx, Members>::type& initField(TArgs&&... args)
418 {
419 return BaseImpl::template initField<TIdx>(std::forward<TArgs>(args)...);
420 }
421
429 template <std::size_t TIdx>
431 {
432 BaseImpl::template deinitField<TIdx>();
433 }
434
440 template <std::size_t TIdx>
441 typename std::tuple_element<TIdx, Members>::type& accessField()
442 {
443 return BaseImpl::template accessField<TIdx>();
444 }
445
451 template <std::size_t TIdx>
452 const typename std::tuple_element<TIdx, Members>::type& accessField() const
453 {
454 return BaseImpl::template accessField<TIdx>();
455 }
456
460 bool currentFieldValid() const
461 {
462 return BaseImpl::currentFieldValid();
463 }
464
467 void reset()
468 {
469 BaseImpl::reset();
470 }
471
473 static constexpr bool isVersionDependent()
474 {
475 return ParsedOptions::HasCustomVersionUpdate || BaseImpl::isVersionDependent();
476 }
477
479 static constexpr bool hasNonDefaultRefresh()
480 {
481 return BaseImpl::hasNonDefaultRefresh();
482 }
483
488 {
489 return BaseImpl::getVersion();
490 }
491
495 {
496 return BaseImpl::setVersion(version);
497 }
498
499protected:
500 using BaseImpl::readData;
501 using BaseImpl::writeData;
502
503private:
504 static_assert(!ParsedOptions::HasSerOffset,
505 "comms::option::def::NumValueSerOffset option is not applicable to Variant field");
506 static_assert(!ParsedOptions::HasFixedLengthLimit,
507 "comms::option::def::FixedLength option is not applicable to Variant field");
508 static_assert(!ParsedOptions::HasFixedBitLengthLimit,
509 "comms::option::def::FixedBitLength option is not applicable to Variant field");
510 static_assert(!ParsedOptions::HasVarLengthLimits,
511 "comms::option::def::VarLength option is not applicable to Variant field");
512 static_assert(!ParsedOptions::HasAvailableLengthLimit,
513 "comms::option::def::AvailableLengthLimit option is not applicable to Variant field");
514 static_assert(!ParsedOptions::HasSequenceElemLengthForcing,
515 "comms::option::def::SequenceElemLengthForcingEnabled option is not applicable to Variant field");
516 static_assert(!ParsedOptions::HasSequenceSizeForcing,
517 "comms::option::def::SequenceSizeForcingEnabled option is not applicable to Variant field");
518 static_assert(!ParsedOptions::HasSequenceLengthForcing,
519 "comms::option::def::SequenceLengthForcingEnabled option is not applicable to Variant field");
520 static_assert(!ParsedOptions::HasSequenceFixedSize,
521 "comms::option::def::SequenceFixedSize option is not applicable to Variant field");
522 static_assert(!ParsedOptions::HasSequenceFixedSizeUseFixedSizeStorage,
523 "comms::option::app::SequenceFixedSizeUseFixedSizeStorage option is not applicable to Variant field");
524 static_assert(!ParsedOptions::HasSequenceSizeFieldPrefix,
525 "comms::option::def::SequenceSizeFieldPrefix option is not applicable to Variant field");
526 static_assert(!ParsedOptions::HasSequenceSerLengthFieldPrefix,
527 "comms::option::def::SequenceSerLengthFieldPrefix option is not applicable to Variant field");
528 static_assert(!ParsedOptions::HasSequenceElemSerLengthFieldPrefix,
529 "comms::option::def::SequenceElemSerLengthFieldPrefix option is not applicable to Variant field");
530 static_assert(!ParsedOptions::HasSequenceElemFixedSerLengthFieldPrefix,
531 "comms::option::def::SequenceElemFixedSerLengthFieldPrefix option is not applicable to Variant field");
532 static_assert(!ParsedOptions::HasSequenceTrailingFieldSuffix,
533 "comms::option::def::SequenceTrailingFieldSuffix option is not applicable to Variant field");
534 static_assert(!ParsedOptions::HasSequenceTerminationFieldSuffix,
535 "comms::option::def::SequenceTerminationFieldSuffix option is not applicable to Variant field");
536 static_assert(!ParsedOptions::HasFixedSizeStorage,
537 "comms::option::app::FixedSizeStorage option is not applicable to Variant field");
538 static_assert(!ParsedOptions::HasCustomStorageType,
539 "comms::option::app::CustomStorageType option is not applicable to Variant field");
540 static_assert(!ParsedOptions::HasScalingRatio,
541 "comms::option::def::ScalingRatio option is not applicable to Variant field");
542 static_assert(!ParsedOptions::HasUnits,
543 "comms::option::def::Units option is not applicable to Variant field");
544 static_assert(!ParsedOptions::HasOrigDataView,
545 "comms::option::app::OrigDataView option is not applicable to Variant field");
546 static_assert(!ParsedOptions::HasMultiRangeValidation,
547 "comms::option::def::ValidNumValueRange (or similar) option is not applicable to Variant field");
548 static_assert(!ParsedOptions::HasVersionsRange,
549 "comms::option::def::ExistsBetweenVersions (or similar) option is not applicable to Variant field");
550 static_assert(!ParsedOptions::HasInvalidByDefault,
551 "comms::option::def::InvalidByDefault option is not applicable to Variant field");
552 static_assert(!ParsedOptions::HasMissingOnReadFail,
553 "comms::option::def::MissingOnReadFail option is not applicable to Variant field");
554 static_assert(!ParsedOptions::HasMissingOnInvalid,
555 "comms::option::def::MissingOnInvalid option is not applicable to Variant field");
556};
557
558namespace details
559{
560
561template <typename TVar>
562class VariantEqualityCompHelper
563{
564public:
565 VariantEqualityCompHelper(const TVar& other, bool& result)
566 : m_other(other),
567 m_result(result)
568 {}
569
570 template <std::size_t TIdx, typename TField>
571 void operator()(const TField& field)
572 {
573 m_result = (field == m_other.template accessField<TIdx>());
574 }
575
576private:
577 const TVar& m_other;
578 bool& m_result;
579
580};
581
582template <typename TVar>
583VariantEqualityCompHelper<TVar> makeVariantEqualityCompHelper(TVar& other, bool& result)
584{
585 return VariantEqualityCompHelper<TVar>(other, result);
586}
587
588template <typename TVar>
589class VariantLessCompHelper
590{
591public:
592 VariantLessCompHelper(const TVar& other, bool& result)
593 : m_other(other),
594 m_result(result)
595 {}
596
597 template <std::size_t TIdx, typename TField>
598 void operator()(const TField& field)
599 {
600 m_result = (field < m_other.template accessField<TIdx>());
601 }
602
603private:
604 const TVar& m_other;
605 bool& m_result;
606};
607
608template <typename TVar>
609VariantLessCompHelper<TVar> makeVariantLessCompHelper(TVar& other, bool& result)
610{
611 return VariantLessCompHelper<TVar>(other, result);
612}
613
614} // namespace details
615
621template <typename TFieldBase, typename TMembers, typename... TOptions>
625{
626 if (&field1 == &field2) {
627 return true;
628 }
629
630 if (field1.currentFieldValid() != field2.currentFieldValid()) {
631 return false;
632 }
633
634 if (!field1.currentFieldValid()) {
635 return true;
636 }
637
638 if (field1.currentField() != field2.currentField()) {
639 return false;
640 }
641
642 bool result = false;
643 field1.currentFieldExec(details::makeVariantEqualityCompHelper(field2, result));
644 return result;
645}
646
652template <typename TFieldBase, typename TMembers, typename... TOptions>
656{
657 return !(field1 == field2);
658}
659
664template <typename TFieldBase, typename TMembers, typename... TOptions>
668{
669 if (!field1.currentFieldValid()) {
670 return (!field2.currentFieldValid());
671 }
672
673 if (!field2.currentFieldValid()) {
674 return false;
675 }
676
677 if (field1.currentField() < field2.currentField()) {
678 return true;
679 }
680
681 if (field1.currentField() != field2.currentField()) {
682 return false;
683 }
684
685 if (&field1 == &field2) {
686 return false;
687 }
688
689 bool result = false;
690 field1.currentFieldExec(details::makeVariantLessCompHelper(field2, result));
691 return result;
692}
693
699template <typename T>
700constexpr bool isVariant()
701{
702 return std::is_same<typename T::CommsTag, tag::Variant>::value;
703}
704
708template <typename TFieldBase, typename TMembers, typename... TOptions>
709inline
710Variant<TFieldBase, TMembers, TOptions...>&
712{
713 return field;
714}
715
719template <typename TFieldBase, typename TMembers, typename... TOptions>
720inline
721const Variant<TFieldBase, TMembers, TOptions...>&
723{
724 return field;
725}
726
763#define COMMS_VARIANT_MEMBERS_ACCESS(...) \
764 COMMS_EXPAND(COMMS_DEFINE_FIELD_ENUM(__VA_ARGS__)) \
765 COMMS_AS_VARIANT_FUNC { \
766 auto& var = comms::field::toFieldBase(*this); \
767 using Var = typename std::decay<decltype(var)>::type; \
768 static_assert(std::tuple_size<typename Var::Members>::value == FieldIdx_numOfValues, \
769 "Invalid number of names for variant field"); \
770 return var; \
771 }\
772 COMMS_AS_VARIANT_CONST_FUNC { \
773 auto& var = comms::field::toFieldBase(*this); \
774 using Var = typename std::decay<decltype(var)>::type; \
775 static_assert(std::tuple_size<typename Var::Members>::value == FieldIdx_numOfValues, \
776 "Invalid number of names for variant field"); \
777 return var; \
778 } \
779 COMMS_DO_VARIANT_MEM_ACC_FUNC(asVariant(), __VA_ARGS__)
780
781
792#define COMMS_VARIANT_MEMBERS_ACCESS_NOTEMPLATE(...) \
793 COMMS_EXPAND(COMMS_DEFINE_FIELD_ENUM(__VA_ARGS__)) \
794 COMMS_DO_VARIANT_MEM_ACC_FUNC_NOTEMPLATE(__VA_ARGS__)
795
946#define COMMS_VARIANT_MEMBERS_NAMES(...) \
947 COMMS_EXPAND(COMMS_VARIANT_MEMBERS_ACCESS(__VA_ARGS__)) \
948 COMMS_EXPAND(COMMS_DO_FIELD_TYPEDEF(typename Base::Members, Field_, FieldIdx_, __VA_ARGS__))
949
950
951} // namespace field
952
953} // namespace comms
954
955
This file contain definition of error statuses used by comms module.
Contains various tuple type manipulation classes and functions.
Defines a "variant" field, that can contain any of the provided ones.
Definition Variant.h:82
bool setVersion(VersionType version)
Default implementation of version update.
Definition Variant.h:494
typename ParsedOptions::FieldType FieldType
Type of actual extending field specified via comms::option::def::FieldType.
Definition Variant.h:128
static constexpr bool hasNonDefaultRefresh()
Compile time check if this class has non-default refresh functionality.
Definition Variant.h:479
void deinitField()
Destruct previously initialised (via initField()) contained field.
Definition Variant.h:430
void currentFieldExec(TFunc &&func) const
Execute provided function object with current field as parameter (const variant).
Definition Variant.h:398
void readNoStatus(TIter &iter)=delete
Read operation without error check and status report is not supported.
const std::tuple_element< TIdx, Members >::type & accessField() const
Access already constructed field at specifed index (known at compile time).
Definition Variant.h:452
TFieldBase FieldBase
Base class provided in the first template parameter.
Definition Variant.h:101
const Variant< TFieldBase, TMembers, TOptions... > & toFieldBase(const Variant< TFieldBase, TMembers, TOptions... > &field)
Upcast type of the field definition to its parent comms::field::Variant type in order to have access ...
Definition Variant.h:722
std::tuple_element< TIdx, Members >::type & accessField()
Access already constructed field at specifed index (known at compile time).
Definition Variant.h:441
std::size_t currentField() const
Get index of the current field (within the Members tuple).
Definition Variant.h:322
bool canWrite() const
Check of whether the field has a consistent value for writing.
Definition Variant.h:266
void selectField(std::size_t idx)
Select type of the variant field.
Definition Variant.h:334
ErrorStatus write(TIter &iter, std::size_t size) const
Write current field value to output data sequence.
Definition Variant.h:280
bool refresh()
Refresh the field's value.
Definition Variant.h:314
bool valid() const
Check validity of all the contained field.
Definition Variant.h:305
static constexpr bool hasWriteNoStatus()
Compile time check of whether the field has proper writeNoStatus() member function.
Definition Variant.h:287
static constexpr bool isVersionDependent()
Compile time check if this class is version dependent.
Definition Variant.h:473
static constexpr bool hasFixedValue()
Compile time inquiry of whether comms::option::def::FixedValue option has been used.
Definition Variant.h:176
static constexpr bool hasFailOnInvalid()
Compile time inquiry of whether comms::option::def::FailOnInvalid option has been used.
Definition Variant.h:148
void currentFieldExec(TFunc &&func)
Execute provided function object with current field as parameter.
Definition Variant.h:375
typename BaseImpl::CommsTag CommsTag
Tag indicating type of the field.
Definition Variant.h:113
std::size_t length() const
Get length required to serialise contained fields.
Definition Variant.h:222
Variant(const ValueType &val)
Constructor.
Definition Variant.h:135
static constexpr bool hasEmptySerialization()
Compile time inquiry of whether comms::option::def::EmptySerialization option has been used.
Definition Variant.h:162
void setValue(U &&val)
Set value.
Definition Variant.h:212
typename BaseImpl::Endian Endian
Endian used for serialisation.
Definition Variant.h:104
Variant()=default
Default constructor.
static constexpr std::size_t maxLength()
Get maximal length that is required to serialise all possible contained fields.
Definition Variant.h:236
details::OptionsParser< TOptions... > ParsedOptions
All the options provided to this class bundled into struct.
Definition Variant.h:110
typename BaseImpl::VersionType VersionType
Version type.
Definition Variant.h:107
ValueType & value()
Get access to the internal storage buffer.
Definition Variant.h:190
static constexpr bool hasReadNoStatus()
Compile time check of whether the field has proper readNoStatus() member function.
Definition Variant.h:256
bool operator<(const Variant< TFieldBase, TMembers, TOptions... > &field1, const Variant< TFieldBase, TMembers, TOptions... > &field2)
Order comparison operator.
Definition Variant.h:665
void writeNoStatus(TIter &iter) const
Write current field value to output data sequence without error check and status report.
Definition Variant.h:298
std::tuple_element< TIdx, Members >::type & initField(TArgs &&... args)
Construct and initialise specified contained field in the internal buffer.
Definition Variant.h:417
constexpr bool isVariant()
Compile time check function of whether a provided type is any variant of comms::field::Variant.
Definition Variant.h:700
typename BaseImpl::Members Members
All the supported types.
Definition Variant.h:123
void reset()
Invalidate current state.
Definition Variant.h:467
const ValueType & getValue() const
Get value.
Definition Variant.h:204
Variant(ValueType &&val)
Constructor.
Definition Variant.h:141
const ValueType & value() const
Get access to the internal storage buffer.
Definition Variant.h:197
static constexpr bool hasFieldType()
Compile time inquiry of whether comms::option::def::FieldType option has been used.
Definition Variant.h:169
bool operator!=(const Variant< TFieldBase, TMembers, TOptions... > &field1, const Variant< TFieldBase, TMembers, TOptions... > &field2)
Non-equality comparison operator.
Definition Variant.h:653
static constexpr std::size_t minLength()
Get minimal length that is required to serialise all possible contained fields.
Definition Variant.h:229
bool operator==(const Variant< TFieldBase, TMembers, TOptions... > &field1, const Variant< TFieldBase, TMembers, TOptions... > &field2)
Equality comparison operator.
Definition Variant.h:622
static constexpr bool hasName()
Compile time inquiry of whether comms::option::def::HasName option has been used.
Definition Variant.h:183
typename BaseImpl::ValueType ValueType
Value type.
Definition Variant.h:118
VersionType getVersion() const
Get version of the field.
Definition Variant.h:487
bool currentFieldValid() const
Check whether the field contains a valid instance of other field.
Definition Variant.h:460
static constexpr bool hasIgnoreInvalid()
Compile time inquiry of whether comms::option::def::IgnoreInvalid option has been used.
Definition Variant.h:155
ErrorStatus read(TIter &iter, std::size_t size)
Read field value from input data sequence.
Definition Variant.h:249
Variant< TFieldBase, TMembers, TOptions... > & toFieldBase(Variant< TFieldBase, TMembers, TOptions... > &field)
Upcast type of the field definition to its parent comms::field::Variant type in order to have access ...
Definition Variant.h:711
Main namespace for all classes / functions of COMMS library.
ErrorStatus
Error statuses reported by the Communication module.
Definition ErrorStatus.h:17
constexpr unsigned version()
Version of the COMMS library as single numeric value.
Definition version.h:64
STL namespace.
Contains definition of all the options used by the COMMS library.
Check whether provided type is a variant of std::tuple.
Definition Tuple.h:36