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;
69 std::size_t length()
const
71 return lengthInternal(HasSignTag());
74 static constexpr std::size_t minLength()
79 static constexpr std::size_t maxLength()
84 static constexpr SerialisedType toSerialised(ValueType val)
86 return static_cast<SerialisedType
>(BaseImpl::toSerialised(val));
89 static constexpr ValueType fromSerialised(SerialisedType val)
91 return BaseImpl::fromSerialised(
static_cast<BaseSerialisedType
>(val));
94 template <
typename TIter>
97 UnsignedSerialisedType val = 0;
98 std::size_t bytesCount = 0;
105 auto byte = comms::util::readData<std::uint8_t>(iter,
Endian());
106 auto byteValue =
static_cast<std::uint8_t
>(
byte & VarLengthValueBitsMask);
107 addByteToSerialisedValue(
108 byteValue, bytesCount, val,
typename BaseImpl::Endian());
112 if ((
byte & VarLengthContinueBit) == 0) {
116 if (MaxLength <= bytesCount) {
123 if (bytesCount < minLength()) {
127 auto adjustedValue = signExtUnsignedSerialised(val, bytesCount, HasSignTag());
128 BaseImpl::setValue(BaseImpl::fromSerialised(
static_cast<BaseSerialisedType
>(adjustedValue)));
132 static constexpr bool hasReadNoStatus()
137 template <
typename TIter>
138 void readNoStatus(TIter& iter) =
delete;
140 bool canWrite()
const
142 if (!BaseImpl::canWrite()) {
146 return length() <= TMaxLen;
149 template <
typename TIter>
156 if (size < length()) {
160 writeNoStatusInternal(toSerialised(BaseImpl::getValue()), iter, HasSignTag(),
Endian());
164 static constexpr bool hasWriteNoStatus()
169 template <
typename TIter>
170 void writeNoStatus(TIter& iter)
const =
delete;
174 return BaseImpl::valid() && canWrite();
178 template <
typename... TParams>
179 using UnsignedTag = comms::details::tag::Tag1<>;
181 template <
typename... TParams>
182 using SignedTag = comms::details::tag::Tag2<>;
185 typename comms::util::LazyShallowConditional<
186 std::is_signed<SerialisedType>::value
192 using UnsignedSerialisedType =
typename std::make_unsigned<SerialisedType>::type;
194 template <
typename... TParams>
195 std::size_t lengthInternal(UnsignedTag<TParams...>)
const
198 static_cast<UnsignedSerialisedType
>(toSerialised(BaseImpl::getValue()));
199 std::size_t len = 0U;
200 while (0 < serValue) {
201 serValue =
static_cast<decltype(serValue)
>(serValue >> VarLengthShift);
205 return std::max(std::size_t(minLength()), len);
208 template <
typename... TParams>
209 std::size_t lengthInternal(SignedTag<TParams...>)
const
211 auto serValue = toSerialised(BaseImpl::getValue());
214 return lengthSignedPositiveInternal();
217 return lengthSignedNegativeInternal();
220 std::size_t lengthSignedNegativeInternal()
const
222 auto serValue = toSerialised(BaseImpl::getValue());
223 std::size_t len = 0U;
224 std::uint8_t lastByte = 0U;
225 while (serValue !=
static_cast<decltype(serValue)
>(-1)) {
226 auto unsignedSerValue =
static_cast<UnsignedSerialisedType
>(serValue);
227 lastByte =
static_cast<decltype(lastByte)
>(unsignedSerValue & VarLengthValueBitsMask);
229 static_cast<decltype(unsignedSerValue)
>(unsignedSerValue >> VarLengthShift);
232 unsignedSerValue |= SignExtMask;
233 serValue =
static_cast<decltype(serValue)
>(unsignedSerValue);
236 if ((lastByte & 0x40) == 0U) {
243 return std::max(std::size_t(minLength()), len);
246 std::size_t lengthSignedPositiveInternal()
const
248 auto serValue = toSerialised(BaseImpl::getValue());
249 std::size_t len = 0U;
250 std::uint8_t lastByte = 0U;
251 while (serValue !=
static_cast<decltype(serValue)
>(0)) {
252 auto unsignedSerValue =
static_cast<UnsignedSerialisedType
>(serValue);
253 lastByte =
static_cast<decltype(lastByte)
>(unsignedSerValue & VarLengthValueBitsMask);
254 unsignedSerValue =
static_cast<decltype(unsignedSerValue)
>(unsignedSerValue >> VarLengthShift);
257 serValue =
static_cast<decltype(serValue)
>(unsignedSerValue);
260 if ((lastByte & 0x40) != 0U) {
267 return std::max(std::size_t(minLength()), len);
271 template <
typename TIter,
typename... TParams>
272 static void writeNoStatusInternal(
275 UnsignedTag<TParams...>,
279 static_cast<UnsignedSerialisedType
>(val);
280 UnsignedSerialisedType unsignedValToWrite = 0U;
281 std::size_t bytesCount = 0;
284 [&unsignedVal, &bytesCount]() ->
bool
287 ((unsignedVal == 0) && (MinLength <= bytesCount)) ||
288 (MaxLength <= bytesCount);
291 while (!isLastByte()) {
292 auto byte =
static_cast<std::uint8_t
>(unsignedVal & VarLengthValueBitsMask);
293 unsignedVal =
static_cast<decltype(unsignedVal)
>(unsignedVal >> VarLengthShift);
297 byte |= VarLengthContinueBit;
302 static_cast<decltype(unsignedValToWrite)
>(
303 static_cast<UnsignedSerialisedType
>(byte) << ((bytesCount - 1) * BitsInByte));
306 auto len = std::max(minLength(), std::min(bytesCount, maxLength()));
310 template <
typename TIter,
typename... TParams>
311 static void writeNoStatusInternal(
314 UnsignedTag<TParams...>,
318 static_cast<UnsignedSerialisedType
>(val);
319 UnsignedSerialisedType unsignedValToWrite = 0U;
320 std::size_t bytesCount = 0;
323 [&unsignedVal, &bytesCount]() ->
bool
326 ((unsignedVal == 0) && (MinLength <= bytesCount)) ||
327 (MaxLength <= bytesCount);
330 while (!isLastByte()) {
331 auto byte =
static_cast<std::uint8_t
>(unsignedVal & VarLengthValueBitsMask);
332 unsignedVal =
static_cast<decltype(unsignedVal)
>(unsignedVal >> VarLengthShift);
334 if (0 < bytesCount) {
335 byte |= VarLengthContinueBit;
340 static_cast<decltype(unsignedValToWrite)
>(
341 static_cast<UnsignedSerialisedType
>(byte) << (bytesCount * BitsInByte));
346 auto len = std::max(minLength(), std::min(bytesCount, maxLength()));
350 template <
typename TIter,
typename TEndian,
typename... TParams>
351 static void writeNoStatusInternal(
354 SignedTag<TParams...>,
357 if (
static_cast<SerialisedType
>(0) <= val) {
358 return writePositiveNoStatusInternal(val, iter, endian);
361 return writeNegativeNoStatusInternal(val, iter, endian);
364 template <
typename TIter>
365 static void writeNegativeNoStatusInternal(
370 UnsignedSerialisedType unsignedValToWrite = 0U;
371 std::size_t bytesCount = 0;
374 [&val, &bytesCount]() ->
bool
377 ((val ==
static_cast<SerialisedType
>(-1)) && (MinLength <= bytesCount)) ||
378 (MaxLength <= bytesCount);
381 while (!isLastByte()) {
382 auto unsignedVal =
static_cast<UnsignedSerialisedType
>(val);
383 auto byte =
static_cast<std::uint8_t
>(unsignedVal & VarLengthValueBitsMask);
384 unsignedVal =
static_cast<decltype(unsignedVal)
>(unsignedVal >> VarLengthShift);
386 unsignedVal |= SignExtMask;
387 val =
static_cast<decltype(val)
>(unsignedVal);
390 byte |= VarLengthContinueBit;
392 else if (((
byte & 0x40) == 0U) && (bytesCount < MaxLength)) {
394 byte |= VarLengthContinueBit;
395 unsignedValToWrite |=
396 (
static_cast<UnsignedSerialisedType
>(byte) << ((bytesCount - 1) * BitsInByte));
399 byte = VarLengthValueBitsMask;
402 unsignedValToWrite |=
403 (
static_cast<UnsignedSerialisedType
>(byte) << ((bytesCount - 1) * BitsInByte));
406 auto len = std::max(minLength(), std::min(bytesCount, maxLength()));
410 template <
typename TIter>
411 static void writePositiveNoStatusInternal(
416 UnsignedSerialisedType unsignedValToWrite = 0U;
417 std::size_t bytesCount = 0;
420 [&val, &bytesCount]() ->
bool
423 ((val ==
static_cast<SerialisedType
>(0)) && (MinLength <= bytesCount)) ||
424 (MaxLength <= bytesCount);
427 while (!isLastByte()) {
428 auto unsignedVal =
static_cast<UnsignedSerialisedType
>(val);
429 auto byte =
static_cast<std::uint8_t
>(unsignedVal & VarLengthValueBitsMask);
430 unsignedVal =
static_cast<decltype(unsignedVal)
>(unsignedVal >> VarLengthShift);
432 val =
static_cast<decltype(val)
>(unsignedVal);
435 byte |= VarLengthContinueBit;
437 else if (((
byte & 0x40) != 0U) && (bytesCount < MaxLength)) {
439 byte |= VarLengthContinueBit;
440 unsignedValToWrite |=
441 (
static_cast<UnsignedSerialisedType
>(byte) << ((bytesCount - 1) * BitsInByte));
447 unsignedValToWrite |=
448 (
static_cast<UnsignedSerialisedType
>(byte) << ((bytesCount - 1) * BitsInByte));
451 auto len = std::max(minLength(), std::min(bytesCount, maxLength()));
455 template <
typename TIter>
456 static void writeNegativeNoStatusInternal(
461 UnsignedSerialisedType unsignedValToWrite = 0U;
462 std::size_t bytesCount = 0;
465 [&val, &bytesCount]() ->
bool
468 ((val ==
static_cast<SerialisedType
>(-1)) && (MinLength <= bytesCount)) ||
469 (MaxLength <= bytesCount);
472 while (!isLastByte()) {
473 auto unsignedVal =
static_cast<UnsignedSerialisedType
>(val);
474 auto byte =
static_cast<std::uint8_t
>(unsignedVal & VarLengthValueBitsMask);
475 unsignedVal =
static_cast<decltype(unsignedVal)
>(unsignedVal >> VarLengthShift);
476 unsignedVal |= SignExtMask;
477 val =
static_cast<decltype(val)
>(unsignedVal);
479 if (0U < bytesCount) {
480 byte |= VarLengthContinueBit;
483 unsignedValToWrite |=
484 (
static_cast<UnsignedSerialisedType
>(byte) << (bytesCount * BitsInByte));
488 if (isLastByte() && ((
byte & 0x40) == 0U) && (bytesCount < MaxLength)) {
491 unsignedValToWrite |=
492 (
static_cast<UnsignedSerialisedType
>(byte) << (bytesCount * BitsInByte));
497 auto len = std::max(minLength(), std::min(bytesCount, maxLength()));
501 template <
typename TIter>
502 static void writePositiveNoStatusInternal(
507 UnsignedSerialisedType unsignedValToWrite = 0U;
508 std::size_t bytesCount = 0;
511 [&val, &bytesCount]() ->
bool
514 ((val ==
static_cast<SerialisedType
>(0)) && (MinLength <= bytesCount)) ||
515 (MaxLength <= bytesCount);
518 while (!isLastByte()) {
519 auto unsignedVal =
static_cast<UnsignedSerialisedType
>(val);
520 auto byte =
static_cast<std::uint8_t
>(unsignedVal & VarLengthValueBitsMask);
521 unsignedVal =
static_cast<decltype(unsignedVal)
>(unsignedVal >> VarLengthShift);
522 val =
static_cast<decltype(val)
>(unsignedVal);
524 if (0U < bytesCount) {
525 byte |= VarLengthContinueBit;
527 unsignedValToWrite |=
528 (
static_cast<UnsignedSerialisedType
>(byte) << (bytesCount * BitsInByte));
531 if (isLastByte() && ((
byte & 0x40) != 0U) && (bytesCount < MaxLength)) {
533 byte = VarLengthContinueBit;
535 unsignedValToWrite |=
536 (
static_cast<UnsignedSerialisedType
>(byte) << (bytesCount * BitsInByte));
542 auto len = std::max(minLength(), std::min(bytesCount, maxLength()));
546 template <
typename... TParams>
547 static constexpr SerialisedType signExtUnsignedSerialised(
548 UnsignedSerialisedType val,
550 UnsignedTag<TParams...>)
552 return static_cast<SerialisedType
>(val);
555 template <
typename... TParams>
556 static SerialisedType signExtUnsignedSerialised(
557 UnsignedSerialisedType val,
558 std::size_t bytesCount,
559 SignedTag<TParams...>)
561 UnsignedSerialisedType signBitMask =
562 static_cast<UnsignedSerialisedType
>(1U) << ((bytesCount * BitsInByte) - (bytesCount + 1));
564 if ((val & signBitMask) == 0U) {
565 return static_cast<SerialisedType
>(val);
568 UnsignedSerialisedType signExtMask =
569 static_cast<UnsignedSerialisedType
>(~(signBitMask - 1));
572 return static_cast<SerialisedType
>(val);
576 static void addByteToSerialisedValue(
578 std::size_t byteCount,
579 UnsignedSerialisedType& val,
582 static_cast<void>(byteCount);
584 val =
static_cast<UnsignedSerialisedType
>(val << VarLengthShift);
585 val =
static_cast<UnsignedSerialisedType
>(val | byte);
588 static void addByteToSerialisedValue(
590 std::size_t byteCount,
591 UnsignedSerialisedType& val,
596 byteCount * VarLengthShift;
597 val =
static_cast<UnsignedSerialisedType
>((
static_cast<UnsignedSerialisedType
>(byte) << shift) | val);
601 static const std::size_t MinLength = TMinLen;
602 static const std::size_t MaxLength = TMaxLen;
603 static const std::size_t VarLengthShift = 7;
604 static const std::uint8_t VarLengthValueBitsMask =
605 (
static_cast<std::uint8_t
>(1U) << VarLengthShift) - 1;
606 static const std::uint8_t VarLengthContinueBit =
607 static_cast<std::uint8_t
>(~(VarLengthValueBitsMask));
608 static const std::size_t BitsInByte =
609 std::numeric_limits<std::uint8_t>::digits;
610 static const std::size_t SerLengthInBits =
611 BitsInByte *
sizeof(SerialisedType);
612 static const auto SignExtMask =
613 static_cast<UnsignedSerialisedType
>(
614 std::numeric_limits<UnsignedSerialisedType>::max() << (SerLengthInBits - VarLengthShift));
616 static_assert(0 < MinLength,
"MinLength is expected to be greater than 0");
617 static_assert(MinLength <= MaxLength,
618 "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:1534
comms::option::def::Endian< TEndian > Endian
Same as comms::option::def::Endian.
Definition options.h:1460
util::traits::endian::Little Little
Empty class used in traits to indicate Little Endian.
Definition traits.h:32
util::traits::endian::Big Big
Empty class used in traits to indicate Big Endian.
Definition traits.h:29
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
This file contains all the classes necessary to properly define message traits.
Replacement to some types from standard type_traits.