12#include "comms/details/tag.h"
15#include "comms/util/SizeToType.h"
32template <std::
size_t TMinLen, std::
size_t TMaxLen,
typename TBase>
35 using BaseImpl = TBase;
36 using BaseSerialisedType =
typename BaseImpl::SerialisedType;
40 using ValueType =
typename BaseImpl::ValueType;
42 static_assert(1U <= TMinLen,
"Minimal length must be at least 1");
43 static_assert(TMinLen < TMaxLen,
"Maximal length must be greater than minimal");
44 static_assert(TMaxLen <=
sizeof(std::uint64_t),
"Currently variable length greater than 8 bytes is not supported");
46 using SerialisedType =
47 typename comms::util::SizeToType<TMaxLen, std::is_signed<BaseSerialisedType>::value>::Type;
49 using Endian =
typename BaseImpl::Endian;
59 : BaseImpl(
std::move(val))
65 VarLength& operator=(
const VarLength&) =
default;
66 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);
269 template <
typename TIter,
typename... TParams>
270 static void writeNoStatusInternal(
273 UnsignedTag<TParams...>,
277 static_cast<UnsignedSerialisedType
>(val);
278 UnsignedSerialisedType unsignedValToWrite = 0U;
279 std::size_t bytesCount = 0;
282 [&unsignedVal, &bytesCount]() ->
bool
285 ((unsignedVal == 0) && (MinLength <= bytesCount)) ||
286 (MaxLength <= bytesCount);
289 while (!isLastByte()) {
290 auto byte =
static_cast<std::uint8_t
>(unsignedVal & VarLengthValueBitsMask);
291 unsignedVal =
static_cast<decltype(unsignedVal)
>(unsignedVal >> VarLengthShift);
295 byte |= VarLengthContinueBit;
300 static_cast<decltype(unsignedValToWrite)
>(
301 static_cast<UnsignedSerialisedType
>(byte) << ((bytesCount - 1) * BitsInByte));
304 auto len = std::max(minLength(), std::min(bytesCount, maxLength()));
308 template <
typename TIter,
typename... TParams>
309 static void writeNoStatusInternal(
312 UnsignedTag<TParams...>,
316 static_cast<UnsignedSerialisedType
>(val);
317 UnsignedSerialisedType unsignedValToWrite = 0U;
318 std::size_t bytesCount = 0;
321 [&unsignedVal, &bytesCount]() ->
bool
324 ((unsignedVal == 0) && (MinLength <= bytesCount)) ||
325 (MaxLength <= bytesCount);
328 while (!isLastByte()) {
329 auto byte =
static_cast<std::uint8_t
>(unsignedVal & VarLengthValueBitsMask);
330 unsignedVal =
static_cast<decltype(unsignedVal)
>(unsignedVal >> VarLengthShift);
332 if (0 < bytesCount) {
333 byte |= VarLengthContinueBit;
338 static_cast<decltype(unsignedValToWrite)
>(
339 static_cast<UnsignedSerialisedType
>(byte) << (bytesCount * BitsInByte));
344 auto len = std::max(minLength(), std::min(bytesCount, maxLength()));
348 template <
typename TIter,
typename TEndian,
typename... TParams>
349 static void writeNoStatusInternal(
352 SignedTag<TParams...>,
355 if (
static_cast<SerialisedType
>(0) <= val) {
356 return writePositiveNoStatusInternal(val, iter, endian);
359 return writeNegativeNoStatusInternal(val, iter, endian);
362 template <
typename TIter>
363 static void writeNegativeNoStatusInternal(
368 UnsignedSerialisedType unsignedValToWrite = 0U;
369 std::size_t bytesCount = 0;
372 [&val, &bytesCount]() ->
bool
375 ((val ==
static_cast<SerialisedType
>(-1)) && (MinLength <= bytesCount)) ||
376 (MaxLength <= bytesCount);
379 while (!isLastByte()) {
380 auto unsignedVal =
static_cast<UnsignedSerialisedType
>(val);
381 auto byte =
static_cast<std::uint8_t
>(unsignedVal & VarLengthValueBitsMask);
382 unsignedVal =
static_cast<decltype(unsignedVal)
>(unsignedVal >> VarLengthShift);
384 unsignedVal |= SignExtMask;
385 val =
static_cast<decltype(val)
>(unsignedVal);
388 byte |= VarLengthContinueBit;
390 else if (((
byte & 0x40) == 0U) && (bytesCount < MaxLength)) {
392 byte |= VarLengthContinueBit;
393 unsignedValToWrite |=
394 (
static_cast<UnsignedSerialisedType
>(byte) << ((bytesCount - 1) * BitsInByte));
397 byte = VarLengthValueBitsMask;
400 unsignedValToWrite |=
401 (
static_cast<UnsignedSerialisedType
>(byte) << ((bytesCount - 1) * BitsInByte));
404 auto len = std::max(minLength(), std::min(bytesCount, maxLength()));
408 template <
typename TIter>
409 static void writePositiveNoStatusInternal(
414 UnsignedSerialisedType unsignedValToWrite = 0U;
415 std::size_t bytesCount = 0;
418 [&val, &bytesCount]() ->
bool
421 ((val ==
static_cast<SerialisedType
>(0)) && (MinLength <= bytesCount)) ||
422 (MaxLength <= bytesCount);
425 while (!isLastByte()) {
426 auto unsignedVal =
static_cast<UnsignedSerialisedType
>(val);
427 auto byte =
static_cast<std::uint8_t
>(unsignedVal & VarLengthValueBitsMask);
428 unsignedVal =
static_cast<decltype(unsignedVal)
>(unsignedVal >> VarLengthShift);
430 val =
static_cast<decltype(val)
>(unsignedVal);
433 byte |= VarLengthContinueBit;
435 else if (((
byte & 0x40) != 0U) && (bytesCount < MaxLength)) {
437 byte |= VarLengthContinueBit;
438 unsignedValToWrite |=
439 (
static_cast<UnsignedSerialisedType
>(byte) << ((bytesCount - 1) * BitsInByte));
445 unsignedValToWrite |=
446 (
static_cast<UnsignedSerialisedType
>(byte) << ((bytesCount - 1) * BitsInByte));
449 auto len = std::max(minLength(), std::min(bytesCount, maxLength()));
453 template <
typename TIter>
454 static void writeNegativeNoStatusInternal(
459 UnsignedSerialisedType unsignedValToWrite = 0U;
460 std::size_t bytesCount = 0;
463 [&val, &bytesCount]() ->
bool
466 ((val ==
static_cast<SerialisedType
>(-1)) && (MinLength <= bytesCount)) ||
467 (MaxLength <= bytesCount);
470 while (!isLastByte()) {
471 auto unsignedVal =
static_cast<UnsignedSerialisedType
>(val);
472 auto byte =
static_cast<std::uint8_t
>(unsignedVal & VarLengthValueBitsMask);
473 unsignedVal =
static_cast<decltype(unsignedVal)
>(unsignedVal >> VarLengthShift);
474 unsignedVal |= SignExtMask;
475 val =
static_cast<decltype(val)
>(unsignedVal);
477 if (0U < bytesCount) {
478 byte |= VarLengthContinueBit;
481 unsignedValToWrite |=
482 (
static_cast<UnsignedSerialisedType
>(byte) << (bytesCount * BitsInByte));
485 if (isLastByte() && ((
byte & 0x40) == 0U) && (bytesCount < MaxLength)) {
488 unsignedValToWrite |=
489 (
static_cast<UnsignedSerialisedType
>(byte) << (bytesCount * BitsInByte));
494 auto len = std::max(minLength(), std::min(bytesCount, maxLength()));
498 template <
typename TIter>
499 static void writePositiveNoStatusInternal(
504 UnsignedSerialisedType unsignedValToWrite = 0U;
505 std::size_t bytesCount = 0;
508 [&val, &bytesCount]() ->
bool
511 ((val ==
static_cast<SerialisedType
>(0)) && (MinLength <= bytesCount)) ||
512 (MaxLength <= bytesCount);
515 while (!isLastByte()) {
516 auto unsignedVal =
static_cast<UnsignedSerialisedType
>(val);
517 auto byte =
static_cast<std::uint8_t
>(unsignedVal & VarLengthValueBitsMask);
518 unsignedVal =
static_cast<decltype(unsignedVal)
>(unsignedVal >> VarLengthShift);
519 val =
static_cast<decltype(val)
>(unsignedVal);
521 if (0U < bytesCount) {
522 byte |= VarLengthContinueBit;
524 unsignedValToWrite |=
525 (
static_cast<UnsignedSerialisedType
>(byte) << (bytesCount * BitsInByte));
528 if (isLastByte() && ((
byte & 0x40) != 0U) && (bytesCount < MaxLength)) {
530 byte = VarLengthContinueBit;
532 unsignedValToWrite |=
533 (
static_cast<UnsignedSerialisedType
>(byte) << (bytesCount * BitsInByte));
539 auto len = std::max(minLength(), std::min(bytesCount, maxLength()));
543 template <
typename... TParams>
544 static constexpr SerialisedType signExtUnsignedSerialised(
545 UnsignedSerialisedType val,
547 UnsignedTag<TParams...>)
549 return static_cast<SerialisedType
>(val);
552 template <
typename... TParams>
553 static SerialisedType signExtUnsignedSerialised(
554 UnsignedSerialisedType val,
555 std::size_t bytesCount,
556 SignedTag<TParams...>)
558 UnsignedSerialisedType signBitMask =
559 static_cast<UnsignedSerialisedType
>(1U) << ((bytesCount * BitsInByte) - (bytesCount + 1));
561 if ((val & signBitMask) == 0U) {
562 return static_cast<SerialisedType
>(val);
565 UnsignedSerialisedType signExtMask =
566 static_cast<UnsignedSerialisedType
>(~(signBitMask - 1));
569 return static_cast<SerialisedType
>(val);
572 static void addByteToSerialisedValue(
574 std::size_t byteCount,
575 UnsignedSerialisedType& val,
578 static_cast<void>(byteCount);
580 val =
static_cast<UnsignedSerialisedType
>(val << VarLengthShift);
581 val =
static_cast<UnsignedSerialisedType
>(val | byte);
584 static void addByteToSerialisedValue(
586 std::size_t byteCount,
587 UnsignedSerialisedType& val,
592 byteCount * VarLengthShift;
593 val =
static_cast<UnsignedSerialisedType
>((
static_cast<UnsignedSerialisedType
>(byte) << shift) | val);
596 static const std::size_t MinLength = TMinLen;
597 static const std::size_t MaxLength = TMaxLen;
598 static const std::size_t VarLengthShift = 7;
599 static const std::uint8_t VarLengthValueBitsMask =
600 (
static_cast<std::uint8_t
>(1U) << VarLengthShift) - 1;
601 static const std::uint8_t VarLengthContinueBit =
602 static_cast<std::uint8_t
>(~(VarLengthValueBitsMask));
603 static const std::size_t BitsInByte =
604 std::numeric_limits<std::uint8_t>::digits;
605 static const std::size_t SerLengthInBits =
606 BitsInByte *
sizeof(SerialisedType);
607 static const auto SignExtMask =
608 static_cast<UnsignedSerialisedType
>(
609 std::numeric_limits<UnsignedSerialisedType>::max() << (SerLengthInBits - VarLengthShift));
611 static_assert(0 < MinLength,
"MinLength is expected to be greater than 0");
612 static_assert(MinLength <= MaxLength,
613 "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:168
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:1545
comms::option::def::Endian< TEndian > Endian
Same as comms::option::def::Endian.
Definition options.h:1471
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:28
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
This file contains all the classes necessary to properly define message traits.
Replacement to some types from standard type_traits.