15#include "comms/util/SizeToType.h"
19#include "comms/details/tag.h"
31template <std::
size_t TMinLen, std::
size_t TMaxLen,
typename TBase>
34 using BaseImpl = TBase;
35 using BaseSerialisedType =
typename BaseImpl::SerialisedType;
39 using ValueType =
typename BaseImpl::ValueType;
41 static_assert(1U <= TMinLen,
"Minimal length must be at least 1");
42 static_assert(TMinLen < TMaxLen,
"Maximal length must be greater than minimal");
43 static_assert(TMaxLen <=
sizeof(std::uint64_t),
"Currently variable length greater than 8 bytes is not supported");
45 using SerialisedType =
46 typename comms::util::SizeToType<TMaxLen, std::is_signed<BaseSerialisedType>::value>::Type;
48 using Endian =
typename BaseImpl::Endian;
58 : BaseImpl(
std::move(val))
64 VarLength& operator=(
const VarLength&) =
default;
65 VarLength& operator=(VarLength&&) =
default;
68 std::size_t length()
const
70 return lengthInternal(HasSignTag());
73 static constexpr std::size_t minLength()
78 static constexpr std::size_t maxLength()
83 static constexpr SerialisedType toSerialised(ValueType val)
85 return static_cast<SerialisedType
>(BaseImpl::toSerialised(val));
88 static constexpr ValueType fromSerialised(SerialisedType val)
90 return BaseImpl::fromSerialised(
static_cast<BaseSerialisedType
>(val));
93 template <
typename TIter>
96 UnsignedSerialisedType val = 0;
97 std::size_t bytesCount = 0;
104 auto byte = comms::util::readData<std::uint8_t>(iter,
Endian());
105 auto byteValue =
static_cast<std::uint8_t
>(
byte & VarLengthValueBitsMask);
106 addByteToSerialisedValue(
107 byteValue, bytesCount, val,
typename BaseImpl::Endian());
111 if ((
byte & VarLengthContinueBit) == 0) {
115 if (MaxLength <= bytesCount) {
122 if (bytesCount < minLength()) {
126 auto adjustedValue = signExtUnsignedSerialised(val, bytesCount, HasSignTag());
127 BaseImpl::setValue(BaseImpl::fromSerialised(
static_cast<BaseSerialisedType
>(adjustedValue)));
131 static constexpr bool hasReadNoStatus()
136 template <
typename TIter>
137 void readNoStatus(TIter& iter) =
delete;
139 bool canWrite()
const
141 if (!BaseImpl::canWrite()) {
145 return length() <= TMaxLen;
148 template <
typename TIter>
155 if (size < length()) {
159 writeNoStatusInternal(toSerialised(BaseImpl::getValue()), iter, HasSignTag(),
Endian());
163 static constexpr bool hasWriteNoStatus()
168 template <
typename TIter>
169 void writeNoStatus(TIter& iter)
const =
delete;
173 return BaseImpl::valid() && canWrite();
177 template <
typename... TParams>
178 using UnsignedTag = comms::details::tag::Tag1<>;
180 template <
typename... TParams>
181 using SignedTag = comms::details::tag::Tag2<>;
184 typename comms::util::LazyShallowConditional<
185 std::is_signed<SerialisedType>::value
191 using UnsignedSerialisedType =
typename std::make_unsigned<SerialisedType>::type;
193 template <
typename... TParams>
194 std::size_t lengthInternal(UnsignedTag<TParams...>)
const
197 static_cast<UnsignedSerialisedType
>(toSerialised(BaseImpl::getValue()));
198 std::size_t len = 0U;
199 while (0 < serValue) {
200 serValue =
static_cast<decltype(serValue)
>(serValue >> VarLengthShift);
204 return std::max(std::size_t(minLength()), len);
207 template <
typename... TParams>
208 std::size_t lengthInternal(SignedTag<TParams...>)
const
210 auto serValue = toSerialised(BaseImpl::getValue());
213 return lengthSignedPositiveInternal();
216 return lengthSignedNegativeInternal();
219 std::size_t lengthSignedNegativeInternal()
const
221 auto serValue = toSerialised(BaseImpl::getValue());
222 std::size_t len = 0U;
223 std::uint8_t lastByte = 0U;
224 while (serValue !=
static_cast<decltype(serValue)
>(-1)) {
225 auto unsignedSerValue =
static_cast<UnsignedSerialisedType
>(serValue);
226 lastByte =
static_cast<decltype(lastByte)
>(unsignedSerValue & VarLengthValueBitsMask);
228 static_cast<decltype(unsignedSerValue)
>(unsignedSerValue >> VarLengthShift);
231 unsignedSerValue |= SignExtMask;
232 serValue =
static_cast<decltype(serValue)
>(unsignedSerValue);
235 if ((lastByte & 0x40) == 0U) {
242 return std::max(std::size_t(minLength()), len);
245 std::size_t lengthSignedPositiveInternal()
const
247 auto serValue = toSerialised(BaseImpl::getValue());
248 std::size_t len = 0U;
249 std::uint8_t lastByte = 0U;
250 while (serValue !=
static_cast<decltype(serValue)
>(0)) {
251 auto unsignedSerValue =
static_cast<UnsignedSerialisedType
>(serValue);
252 lastByte =
static_cast<decltype(lastByte)
>(unsignedSerValue & VarLengthValueBitsMask);
253 unsignedSerValue =
static_cast<decltype(unsignedSerValue)
>(unsignedSerValue >> VarLengthShift);
256 serValue =
static_cast<decltype(serValue)
>(unsignedSerValue);
259 if ((lastByte & 0x40) != 0U) {
266 return std::max(std::size_t(minLength()), len);
270 template <
typename TIter,
typename... TParams>
271 static void writeNoStatusInternal(
274 UnsignedTag<TParams...>,
278 static_cast<UnsignedSerialisedType
>(val);
279 UnsignedSerialisedType unsignedValToWrite = 0U;
280 std::size_t bytesCount = 0;
283 [&unsignedVal, &bytesCount]() ->
bool
286 ((unsignedVal == 0) && (MinLength <= bytesCount)) ||
287 (MaxLength <= bytesCount);
290 while (!isLastByte()) {
291 auto byte =
static_cast<std::uint8_t
>(unsignedVal & VarLengthValueBitsMask);
292 unsignedVal =
static_cast<decltype(unsignedVal)
>(unsignedVal >> VarLengthShift);
296 byte |= VarLengthContinueBit;
301 static_cast<decltype(unsignedValToWrite)
>(
302 static_cast<UnsignedSerialisedType
>(byte) << ((bytesCount - 1) * BitsInByte));
305 auto len = std::max(minLength(), std::min(bytesCount, maxLength()));
309 template <
typename TIter,
typename... TParams>
310 static void writeNoStatusInternal(
313 UnsignedTag<TParams...>,
317 static_cast<UnsignedSerialisedType
>(val);
318 UnsignedSerialisedType unsignedValToWrite = 0U;
319 std::size_t bytesCount = 0;
322 [&unsignedVal, &bytesCount]() ->
bool
325 ((unsignedVal == 0) && (MinLength <= bytesCount)) ||
326 (MaxLength <= bytesCount);
329 while (!isLastByte()) {
330 auto byte =
static_cast<std::uint8_t
>(unsignedVal & VarLengthValueBitsMask);
331 unsignedVal =
static_cast<decltype(unsignedVal)
>(unsignedVal >> VarLengthShift);
333 if (0 < bytesCount) {
334 byte |= VarLengthContinueBit;
339 static_cast<decltype(unsignedValToWrite)
>(
340 static_cast<UnsignedSerialisedType
>(byte) << (bytesCount * BitsInByte));
345 auto len = std::max(minLength(), std::min(bytesCount, maxLength()));
349 template <
typename TIter,
typename TEndian,
typename... TParams>
350 static void writeNoStatusInternal(
353 SignedTag<TParams...>,
356 if (
static_cast<SerialisedType
>(0) <= val) {
357 return writePositiveNoStatusInternal(val, iter, endian);
360 return writeNegativeNoStatusInternal(val, iter, endian);
363 template <
typename TIter>
364 static void writeNegativeNoStatusInternal(
369 UnsignedSerialisedType unsignedValToWrite = 0U;
370 std::size_t bytesCount = 0;
373 [&val, &bytesCount]() ->
bool
376 ((val ==
static_cast<SerialisedType
>(-1)) && (MinLength <= bytesCount)) ||
377 (MaxLength <= bytesCount);
380 while (!isLastByte()) {
381 auto unsignedVal =
static_cast<UnsignedSerialisedType
>(val);
382 auto byte =
static_cast<std::uint8_t
>(unsignedVal & VarLengthValueBitsMask);
383 unsignedVal =
static_cast<decltype(unsignedVal)
>(unsignedVal >> VarLengthShift);
385 unsignedVal |= SignExtMask;
386 val =
static_cast<decltype(val)
>(unsignedVal);
389 byte |= VarLengthContinueBit;
391 else if (((
byte & 0x40) == 0U) && (bytesCount < MaxLength)) {
393 byte |= VarLengthContinueBit;
394 unsignedValToWrite |=
395 (
static_cast<UnsignedSerialisedType
>(byte) << ((bytesCount - 1) * BitsInByte));
398 byte = VarLengthValueBitsMask;
401 unsignedValToWrite |=
402 (
static_cast<UnsignedSerialisedType
>(byte) << ((bytesCount - 1) * BitsInByte));
405 auto len = std::max(minLength(), std::min(bytesCount, maxLength()));
409 template <
typename TIter>
410 static void writePositiveNoStatusInternal(
415 UnsignedSerialisedType unsignedValToWrite = 0U;
416 std::size_t bytesCount = 0;
419 [&val, &bytesCount]() ->
bool
422 ((val ==
static_cast<SerialisedType
>(0)) && (MinLength <= bytesCount)) ||
423 (MaxLength <= bytesCount);
426 while (!isLastByte()) {
427 auto unsignedVal =
static_cast<UnsignedSerialisedType
>(val);
428 auto byte =
static_cast<std::uint8_t
>(unsignedVal & VarLengthValueBitsMask);
429 unsignedVal =
static_cast<decltype(unsignedVal)
>(unsignedVal >> VarLengthShift);
431 val =
static_cast<decltype(val)
>(unsignedVal);
434 byte |= VarLengthContinueBit;
436 else if (((
byte & 0x40) != 0U) && (bytesCount < MaxLength)) {
438 byte |= VarLengthContinueBit;
439 unsignedValToWrite |=
440 (
static_cast<UnsignedSerialisedType
>(byte) << ((bytesCount - 1) * BitsInByte));
446 unsignedValToWrite |=
447 (
static_cast<UnsignedSerialisedType
>(byte) << ((bytesCount - 1) * BitsInByte));
450 auto len = std::max(minLength(), std::min(bytesCount, maxLength()));
454 template <
typename TIter>
455 static void writeNegativeNoStatusInternal(
460 UnsignedSerialisedType unsignedValToWrite = 0U;
461 std::size_t bytesCount = 0;
464 [&val, &bytesCount]() ->
bool
467 ((val ==
static_cast<SerialisedType
>(-1)) && (MinLength <= bytesCount)) ||
468 (MaxLength <= bytesCount);
471 while (!isLastByte()) {
472 auto unsignedVal =
static_cast<UnsignedSerialisedType
>(val);
473 auto byte =
static_cast<std::uint8_t
>(unsignedVal & VarLengthValueBitsMask);
474 unsignedVal =
static_cast<decltype(unsignedVal)
>(unsignedVal >> VarLengthShift);
475 unsignedVal |= SignExtMask;
476 val =
static_cast<decltype(val)
>(unsignedVal);
478 if (0U < bytesCount) {
479 byte |= VarLengthContinueBit;
482 unsignedValToWrite |=
483 (
static_cast<UnsignedSerialisedType
>(byte) << (bytesCount * BitsInByte));
487 if (isLastByte() && ((
byte & 0x40) == 0U) && (bytesCount < MaxLength)) {
490 unsignedValToWrite |=
491 (
static_cast<UnsignedSerialisedType
>(byte) << (bytesCount * BitsInByte));
496 auto len = std::max(minLength(), std::min(bytesCount, maxLength()));
500 template <
typename TIter>
501 static void writePositiveNoStatusInternal(
506 UnsignedSerialisedType unsignedValToWrite = 0U;
507 std::size_t bytesCount = 0;
510 [&val, &bytesCount]() ->
bool
513 ((val ==
static_cast<SerialisedType
>(0)) && (MinLength <= bytesCount)) ||
514 (MaxLength <= bytesCount);
517 while (!isLastByte()) {
518 auto unsignedVal =
static_cast<UnsignedSerialisedType
>(val);
519 auto byte =
static_cast<std::uint8_t
>(unsignedVal & VarLengthValueBitsMask);
520 unsignedVal =
static_cast<decltype(unsignedVal)
>(unsignedVal >> VarLengthShift);
521 val =
static_cast<decltype(val)
>(unsignedVal);
523 if (0U < bytesCount) {
524 byte |= VarLengthContinueBit;
526 unsignedValToWrite |=
527 (
static_cast<UnsignedSerialisedType
>(byte) << (bytesCount * BitsInByte));
530 if (isLastByte() && ((
byte & 0x40) != 0U) && (bytesCount < MaxLength)) {
532 byte = VarLengthContinueBit;
534 unsignedValToWrite |=
535 (
static_cast<UnsignedSerialisedType
>(byte) << (bytesCount * BitsInByte));
541 auto len = std::max(minLength(), std::min(bytesCount, maxLength()));
545 template <
typename... TParams>
546 static constexpr SerialisedType signExtUnsignedSerialised(
547 UnsignedSerialisedType val,
549 UnsignedTag<TParams...>)
551 return static_cast<SerialisedType
>(val);
554 template <
typename... TParams>
555 static SerialisedType signExtUnsignedSerialised(
556 UnsignedSerialisedType val,
557 std::size_t bytesCount,
558 SignedTag<TParams...>)
560 UnsignedSerialisedType signBitMask =
561 static_cast<UnsignedSerialisedType
>(1U) << ((bytesCount * BitsInByte) - (bytesCount + 1));
563 if ((val & signBitMask) == 0U) {
564 return static_cast<SerialisedType
>(val);
567 UnsignedSerialisedType signExtMask =
568 static_cast<UnsignedSerialisedType
>(~(signBitMask - 1));
571 return static_cast<SerialisedType
>(val);
575 static void addByteToSerialisedValue(
577 std::size_t byteCount,
578 UnsignedSerialisedType& val,
581 static_cast<void>(byteCount);
583 val =
static_cast<UnsignedSerialisedType
>(val << VarLengthShift);
584 val =
static_cast<UnsignedSerialisedType
>(val | byte);
587 static void addByteToSerialisedValue(
589 std::size_t byteCount,
590 UnsignedSerialisedType& val,
595 byteCount * VarLengthShift;
596 val =
static_cast<UnsignedSerialisedType
>((
static_cast<UnsignedSerialisedType
>(byte) << shift) | val);
600 static const std::size_t MinLength = TMinLen;
601 static const std::size_t MaxLength = TMaxLen;
602 static const std::size_t VarLengthShift = 7;
603 static const std::uint8_t VarLengthValueBitsMask =
604 (
static_cast<std::uint8_t
>(1U) << VarLengthShift) - 1;
605 static const std::uint8_t VarLengthContinueBit =
606 static_cast<std::uint8_t
>(~(VarLengthValueBitsMask));
607 static const std::size_t BitsInByte =
608 std::numeric_limits<std::uint8_t>::digits;
609 static const std::size_t SerLengthInBits =
610 BitsInByte *
sizeof(SerialisedType);
611 static const auto SignExtMask =
612 static_cast<UnsignedSerialisedType
>(
613 std::numeric_limits<UnsignedSerialisedType>::max() << (SerLengthInBits - VarLengthShift));
615 static_assert(0 < MinLength,
"MinLength is expected to be greater than 0");
616 static_assert(MinLength <= MaxLength,
617 "MinLength is expected to be no greater than MaxLength");
This file contains classes required for generic custom assertion functionality.
#define COMMS_ASSERT(expr)
Generic assert macro.
Definition Assert.h:170
This file contain definition of error statuses used by comms module.
Contains functions for raw data access / (de)serialization.
Contains definition of various casts.
comms::option::def::VarLength< TMin, TMax > VarLength
Same as comms::option::def::VarLength.
Definition options.h:1496
comms::option::def::Endian< TEndian > Endian
Same as comms::option::def::Endian.
Definition options.h:1438
util::traits::endian::Little Little
Empty class used in traits to indicate Little Endian.
Definition traits.h:31
util::traits::endian::Big Big
Empty class used in traits to indicate Big Endian.
Definition traits.h:28
void writeData(T value, TIter &iter, const traits::endian::Big &endian)
Same as writeBig<T, TIter>()
Definition access.h:706
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.
@ InvalidMsgData
Used to indicate that a message has invalid data.
details::ValueAssignWrapper< T > cast_assign(T &value)
Helper function to assign value with static_cast to appropriate type.
Definition cast.h:29
Empty class used in traits to indicate Big Endian.
Definition access.h:43
Empty class used in traits to indicate Little Endian.
Definition access.h:46
Replacement to some types from standard type_traits.