14#include "comms/details/tag.h"
17#include "comms/util/SizeToType.h"
36template <std::
size_t TMinLen, std::
size_t TMaxLen,
typename TBase>
39 using BaseImpl = TBase;
40 using BaseSerialisedType =
typename BaseImpl::SerialisedType;
44 using ValueType =
typename BaseImpl::ValueType;
46 static_assert(1U <= TMinLen,
"Minimal length must be at least 1");
47 static_assert(TMinLen < TMaxLen,
"Maximal length must be greater than minimal");
48 static_assert(TMaxLen <=
sizeof(std::uint64_t),
"Currently variable length greater than 8 bytes is not supported");
50 using SerialisedType =
51 typename comms::util::SizeToType<TMaxLen, std::is_signed<BaseSerialisedType>::value>::Type;
53 using Endian =
typename BaseImpl::Endian;
63 : BaseImpl(
std::move(val))
69 VarLength& operator=(
const VarLength&) =
default;
70 VarLength& operator=(VarLength&&) =
default;
72 std::size_t length()
const
74 return lengthInternal(HasSignTag());
77 static constexpr std::size_t minLength()
82 static constexpr std::size_t maxLength()
87 static constexpr SerialisedType toSerialised(ValueType val)
89 return static_cast<SerialisedType
>(BaseImpl::toSerialised(val));
92 static constexpr ValueType fromSerialised(SerialisedType val)
94 return BaseImpl::fromSerialised(
static_cast<BaseSerialisedType
>(val));
97 template <
typename TIter>
100 UnsignedSerialisedType val = 0;
101 std::size_t bytesCount = 0;
108 auto byte = comms::util::readData<std::uint8_t>(iter,
Endian());
109 auto byteValue =
static_cast<std::uint8_t
>(
byte & VarLengthValueBitsMask);
110 addByteToSerialisedValue(
111 byteValue, bytesCount, val,
typename BaseImpl::Endian());
115 if ((
byte & VarLengthContinueBit) == 0) {
119 if (MaxLength <= bytesCount) {
126 if (bytesCount < minLength()) {
130 auto adjustedValue = signExtUnsignedSerialised(val, bytesCount, HasSignTag());
131 BaseImpl::setValue(BaseImpl::fromSerialised(
static_cast<BaseSerialisedType
>(adjustedValue)));
135 static constexpr bool hasReadNoStatus()
140 template <
typename TIter>
141 void readNoStatus(TIter& iter) =
delete;
143 bool canWrite()
const
145 if (!BaseImpl::canWrite()) {
149 return length() <= TMaxLen;
152 template <
typename TIter>
159 if (size < length()) {
163 writeNoStatusInternal(toSerialised(BaseImpl::getValue()), iter, HasSignTag(),
Endian());
167 static constexpr bool hasWriteNoStatus()
172 template <
typename TIter>
173 void writeNoStatus(TIter& iter)
const =
delete;
177 return BaseImpl::valid() && canWrite();
181 template <
typename... TParams>
182 using UnsignedTag = comms::details::tag::Tag1<>;
184 template <
typename... TParams>
185 using SignedTag = comms::details::tag::Tag2<>;
188 typename comms::util::LazyShallowConditional<
189 std::is_signed<SerialisedType>::value
195 using UnsignedSerialisedType =
typename std::make_unsigned<SerialisedType>::type;
197 template <
typename... TParams>
198 std::size_t lengthInternal(UnsignedTag<TParams...>)
const
201 static_cast<UnsignedSerialisedType
>(toSerialised(BaseImpl::getValue()));
202 std::size_t len = 0U;
203 while (0 < serValue) {
204 serValue =
static_cast<decltype(serValue)
>(serValue >> VarLengthShift);
208 return std::max(std::size_t(minLength()), len);
211 template <
typename... TParams>
212 std::size_t lengthInternal(SignedTag<TParams...>)
const
214 auto serValue = toSerialised(BaseImpl::getValue());
217 return lengthSignedPositiveInternal();
220 return lengthSignedNegativeInternal();
223 std::size_t lengthSignedNegativeInternal()
const
225 auto serValue = toSerialised(BaseImpl::getValue());
226 std::size_t len = 0U;
227 std::uint8_t lastByte = 0U;
228 while (serValue !=
static_cast<decltype(serValue)
>(-1)) {
229 auto unsignedSerValue =
static_cast<UnsignedSerialisedType
>(serValue);
230 lastByte =
static_cast<decltype(lastByte)
>(unsignedSerValue & VarLengthValueBitsMask);
232 static_cast<decltype(unsignedSerValue)
>(unsignedSerValue >> VarLengthShift);
235 unsignedSerValue |= SignExtMask;
236 serValue =
static_cast<decltype(serValue)
>(unsignedSerValue);
239 if ((lastByte & 0x40) == 0U) {
246 return std::max(std::size_t(minLength()), len);
249 std::size_t lengthSignedPositiveInternal()
const
251 auto serValue = toSerialised(BaseImpl::getValue());
252 std::size_t len = 0U;
253 std::uint8_t lastByte = 0U;
254 while (serValue !=
static_cast<decltype(serValue)
>(0)) {
255 auto unsignedSerValue =
static_cast<UnsignedSerialisedType
>(serValue);
256 lastByte =
static_cast<decltype(lastByte)
>(unsignedSerValue & VarLengthValueBitsMask);
257 unsignedSerValue =
static_cast<decltype(unsignedSerValue)
>(unsignedSerValue >> VarLengthShift);
260 serValue =
static_cast<decltype(serValue)
>(unsignedSerValue);
263 if ((lastByte & 0x40) != 0U) {
270 return std::max(std::size_t(minLength()), len);
273 template <
typename TIter,
typename... TParams>
274 static void writeNoStatusInternal(
277 UnsignedTag<TParams...>,
281 static_cast<UnsignedSerialisedType
>(val);
282 UnsignedSerialisedType unsignedValToWrite = 0U;
283 std::size_t bytesCount = 0;
286 [&unsignedVal, &bytesCount]() ->
bool
289 ((unsignedVal == 0) && (MinLength <= bytesCount)) ||
290 (MaxLength <= bytesCount);
293 while (!isLastByte()) {
294 auto byte =
static_cast<std::uint8_t
>(unsignedVal & VarLengthValueBitsMask);
295 unsignedVal =
static_cast<decltype(unsignedVal)
>(unsignedVal >> VarLengthShift);
299 byte |= VarLengthContinueBit;
304 static_cast<decltype(unsignedValToWrite)
>(
305 static_cast<UnsignedSerialisedType
>(byte) << ((bytesCount - 1) * BitsInByte));
308 auto len = std::max(minLength(), std::min(bytesCount, maxLength()));
312 template <
typename TIter,
typename... TParams>
313 static void writeNoStatusInternal(
316 UnsignedTag<TParams...>,
320 static_cast<UnsignedSerialisedType
>(val);
321 UnsignedSerialisedType unsignedValToWrite = 0U;
322 std::size_t bytesCount = 0;
325 [&unsignedVal, &bytesCount]() ->
bool
328 ((unsignedVal == 0) && (MinLength <= bytesCount)) ||
329 (MaxLength <= bytesCount);
332 while (!isLastByte()) {
333 auto byte =
static_cast<std::uint8_t
>(unsignedVal & VarLengthValueBitsMask);
334 unsignedVal =
static_cast<decltype(unsignedVal)
>(unsignedVal >> VarLengthShift);
336 if (0 < bytesCount) {
337 byte |= VarLengthContinueBit;
342 static_cast<decltype(unsignedValToWrite)
>(
343 static_cast<UnsignedSerialisedType
>(byte) << (bytesCount * BitsInByte));
348 auto len = std::max(minLength(), std::min(bytesCount, maxLength()));
352 template <
typename TIter,
typename TEndian,
typename... TParams>
353 static void writeNoStatusInternal(
356 SignedTag<TParams...>,
359 if (
static_cast<SerialisedType
>(0) <= val) {
360 return writePositiveNoStatusInternal(val, iter, endian);
363 return writeNegativeNoStatusInternal(val, iter, endian);
366 template <
typename TIter>
367 static void writeNegativeNoStatusInternal(
372 UnsignedSerialisedType unsignedValToWrite = 0U;
373 std::size_t bytesCount = 0;
376 [&val, &bytesCount]() ->
bool
379 ((val ==
static_cast<SerialisedType
>(-1)) && (MinLength <= bytesCount)) ||
380 (MaxLength <= bytesCount);
383 while (!isLastByte()) {
384 auto unsignedVal =
static_cast<UnsignedSerialisedType
>(val);
385 auto byte =
static_cast<std::uint8_t
>(unsignedVal & VarLengthValueBitsMask);
386 unsignedVal =
static_cast<decltype(unsignedVal)
>(unsignedVal >> VarLengthShift);
388 unsignedVal |= SignExtMask;
389 val =
static_cast<decltype(val)
>(unsignedVal);
392 byte |= VarLengthContinueBit;
394 else if (((
byte & 0x40) == 0U) && (bytesCount < MaxLength)) {
396 byte |= VarLengthContinueBit;
397 unsignedValToWrite |=
398 (
static_cast<UnsignedSerialisedType
>(byte) << ((bytesCount - 1) * BitsInByte));
401 byte = VarLengthValueBitsMask;
404 unsignedValToWrite |=
405 (
static_cast<UnsignedSerialisedType
>(byte) << ((bytesCount - 1) * BitsInByte));
408 auto len = std::max(minLength(), std::min(bytesCount, maxLength()));
412 template <
typename TIter>
413 static void writePositiveNoStatusInternal(
418 UnsignedSerialisedType unsignedValToWrite = 0U;
419 std::size_t bytesCount = 0;
422 [&val, &bytesCount]() ->
bool
425 ((val ==
static_cast<SerialisedType
>(0)) && (MinLength <= bytesCount)) ||
426 (MaxLength <= bytesCount);
429 while (!isLastByte()) {
430 auto unsignedVal =
static_cast<UnsignedSerialisedType
>(val);
431 auto byte =
static_cast<std::uint8_t
>(unsignedVal & VarLengthValueBitsMask);
432 unsignedVal =
static_cast<decltype(unsignedVal)
>(unsignedVal >> VarLengthShift);
434 val =
static_cast<decltype(val)
>(unsignedVal);
437 byte |= VarLengthContinueBit;
439 else if (((
byte & 0x40) != 0U) && (bytesCount < MaxLength)) {
441 byte |= VarLengthContinueBit;
442 unsignedValToWrite |=
443 (
static_cast<UnsignedSerialisedType
>(byte) << ((bytesCount - 1) * BitsInByte));
449 unsignedValToWrite |=
450 (
static_cast<UnsignedSerialisedType
>(byte) << ((bytesCount - 1) * BitsInByte));
453 auto len = std::max(minLength(), std::min(bytesCount, maxLength()));
457 template <
typename TIter>
458 static void writeNegativeNoStatusInternal(
463 UnsignedSerialisedType unsignedValToWrite = 0U;
464 std::size_t bytesCount = 0;
467 [&val, &bytesCount]() ->
bool
470 ((val ==
static_cast<SerialisedType
>(-1)) && (MinLength <= bytesCount)) ||
471 (MaxLength <= bytesCount);
474 while (!isLastByte()) {
475 auto unsignedVal =
static_cast<UnsignedSerialisedType
>(val);
476 auto byte =
static_cast<std::uint8_t
>(unsignedVal & VarLengthValueBitsMask);
477 unsignedVal =
static_cast<decltype(unsignedVal)
>(unsignedVal >> VarLengthShift);
478 unsignedVal |= SignExtMask;
479 val =
static_cast<decltype(val)
>(unsignedVal);
481 if (0U < bytesCount) {
482 byte |= VarLengthContinueBit;
485 unsignedValToWrite |=
486 (
static_cast<UnsignedSerialisedType
>(byte) << (bytesCount * BitsInByte));
489 if (isLastByte() && ((
byte & 0x40) == 0U) && (bytesCount < MaxLength)) {
492 unsignedValToWrite |=
493 (
static_cast<UnsignedSerialisedType
>(byte) << (bytesCount * BitsInByte));
498 auto len = std::max(minLength(), std::min(bytesCount, maxLength()));
502 template <
typename TIter>
503 static void writePositiveNoStatusInternal(
508 UnsignedSerialisedType unsignedValToWrite = 0U;
509 std::size_t bytesCount = 0;
512 [&val, &bytesCount]() ->
bool
515 ((val ==
static_cast<SerialisedType
>(0)) && (MinLength <= bytesCount)) ||
516 (MaxLength <= bytesCount);
519 while (!isLastByte()) {
520 auto unsignedVal =
static_cast<UnsignedSerialisedType
>(val);
521 auto byte =
static_cast<std::uint8_t
>(unsignedVal & VarLengthValueBitsMask);
522 unsignedVal =
static_cast<decltype(unsignedVal)
>(unsignedVal >> VarLengthShift);
523 val =
static_cast<decltype(val)
>(unsignedVal);
525 if (0U < bytesCount) {
526 byte |= VarLengthContinueBit;
528 unsignedValToWrite |=
529 (
static_cast<UnsignedSerialisedType
>(byte) << (bytesCount * BitsInByte));
532 if (isLastByte() && ((
byte & 0x40) != 0U) && (bytesCount < MaxLength)) {
534 byte = VarLengthContinueBit;
536 unsignedValToWrite |=
537 (
static_cast<UnsignedSerialisedType
>(byte) << (bytesCount * BitsInByte));
543 auto len = std::max(minLength(), std::min(bytesCount, maxLength()));
547 template <
typename... TParams>
548 static constexpr SerialisedType signExtUnsignedSerialised(
549 UnsignedSerialisedType val,
551 UnsignedTag<TParams...>)
553 return static_cast<SerialisedType
>(val);
556 template <
typename... TParams>
557 static SerialisedType signExtUnsignedSerialised(
558 UnsignedSerialisedType val,
559 std::size_t bytesCount,
560 SignedTag<TParams...>)
562 UnsignedSerialisedType signBitMask =
563 static_cast<UnsignedSerialisedType
>(1U) << ((bytesCount * BitsInByte) - (bytesCount + 1));
565 if ((val & signBitMask) == 0U) {
566 return static_cast<SerialisedType
>(val);
569 UnsignedSerialisedType signExtMask =
570 static_cast<UnsignedSerialisedType
>(~(signBitMask - 1));
573 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);
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:1547
comms::option::def::Endian< TEndian > Endian
Same as comms::option::def::Endian.
Definition options.h:1473
util::traits::endian::Little Little
Empty class used in traits to indicate Little Endian.
Definition traits.h:33
util::traits::endian::Big Big
Empty class used in traits to indicate Big Endian.
Definition traits.h:30
void writeData(T value, TIter &iter, const traits::endian::Big &endian)
Same as writeBig<T, TIter>()
Definition access.h:707
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.
@ 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:30
Empty class used in traits to indicate Big Endian.
Definition access.h:44
Empty class used in traits to indicate Little Endian.
Definition access.h:47
This file contains all the classes necessary to properly define message traits.
Replacement to some types from standard type_traits.