COMMS
Template library intended to help with implementation of communication protocols.
Loading...
Searching...
No Matches
FixedLength.h
1//
2// Copyright 2015 - 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
8#pragma once
9
10#include "comms/Assert.h"
11#include "comms/details/tag.h"
12#include "comms/ErrorStatus.h"
13#include "comms/util/SizeToType.h"
15
16#include <type_traits>
17#include <limits>
18
19namespace comms
20{
21
22namespace field
23{
24
25namespace adapter
26{
27
28namespace details
29{
30
31template <std::size_t TLen>
32struct UnsignedValueMaskWrap
33{
34 static const std::uintmax_t Value =
35 static_cast<std::uintmax_t>(
36 (static_cast<std::uintmax_t>(1U) << (TLen * std::numeric_limits<std::uint8_t>::digits)) - 1U);
37};
38
39template <>
40struct UnsignedValueMaskWrap<sizeof(std::uintmax_t)>
41{
42 static const std::uintmax_t Value = std::numeric_limits<std::uintmax_t>::max();
43};
44
45} // namespace details
46
47template <std::size_t TLen, bool TSignExtend, typename TBase>
48class FixedLength : public TBase
49{
50 using BaseImpl = TBase;
51 using BaseSerialisedType = typename BaseImpl::SerialisedType;
52public:
53
54 using ValueType = typename BaseImpl::ValueType;
55
56 static_assert(TLen <= sizeof(BaseSerialisedType),
57 "The provided length limit is too big");
58
59 using SerialisedType =
61 (TLen < sizeof(BaseSerialisedType))
62 >::template Type<
63 typename comms::util::SizeToType<TLen, std::is_signed<BaseSerialisedType>::value>::Type,
64 BaseSerialisedType
65 >;
66
67 using Endian = typename BaseImpl::Endian;
68
69 FixedLength() = default;
70
71 explicit FixedLength(const ValueType& val)
72 : BaseImpl(val)
73 {
74 }
75
76 FixedLength(const FixedLength&) = default;
77 FixedLength(FixedLength&&) = default;
78 FixedLength& operator=(const FixedLength&) = default;
79 FixedLength& operator=(FixedLength&&) = default;
80
81 static constexpr std::size_t length()
82 {
83 return Length;
84 }
85
86 static constexpr std::size_t minLength()
87 {
88 return length();
89 }
90
91 static constexpr std::size_t maxLength()
92 {
93 return length();
94 }
95
96 static constexpr SerialisedType toSerialised(ValueType val)
97 {
98 return adjustToSerialised(BaseImpl::toSerialised(val), ConversionTag<>());
99 }
100
101 static constexpr ValueType fromSerialised(SerialisedType val)
102 {
103 return BaseImpl::fromSerialised(adjustFromSerialised(val, ConversionTag<>()));
104 }
105
106 template <typename TIter>
107 comms::ErrorStatus read(TIter& iter, std::size_t size)
108 {
109 if (size < length()) {
111 }
112
113 readNoStatus(iter);
115 }
116
117 template <typename TIter>
118 void readNoStatus(TIter& iter)
119 {
120 auto serialisedValue =
121 comms::util::readData<SerialisedType, Length>(iter, Endian());
122 BaseImpl::setValue(fromSerialised(serialisedValue));
123 }
124
125 template <typename TIter>
126 comms::ErrorStatus write(TIter& iter, std::size_t size) const
127 {
128 if (size < length()) {
130 }
131
132 writeNoStatus(iter);
134 }
135
136 template <typename TIter>
137 void writeNoStatus(TIter& iter) const
138 {
139 BaseImpl::template writeData<Length>(toSerialised(BaseImpl::getValue()), iter);
140 }
141
142private:
143
144 template <typename... TParams>
145 using JustCastTag = comms::details::tag::Tag1<>;
146
147 template <typename... TParams>
148 using SignExtendTag = comms::details::tag::Tag2<>;
149
150 template <typename... TParams>
151 using UnsignedTag = comms::details::tag::Tag3<>;
152
153 template <typename... TParams>
154 using SignedTag = comms::details::tag::Tag4<>;
155
156 template <typename...>
157 using ConversionTag =
158 typename comms::util::LazyShallowConditional<
159 (TLen < sizeof(SerialisedType))
160 >::template Type<
161 SignExtendTag,
162 JustCastTag
163 >;
164
165 template <typename...>
166 using HasSignTag =
167 typename comms::util::LazyShallowConditional<
168 std::is_signed<SerialisedType>::value && TSignExtend
169 >::template Type<
170 SignedTag,
171 UnsignedTag
172 >;
173
174 using UnsignedSerialisedType = typename std::make_unsigned<SerialisedType>::type;
175
176 template <typename... TParams>
177 static constexpr SerialisedType adjustToSerialised(BaseSerialisedType val, JustCastTag<TParams...>)
178 {
179 return static_cast<SerialisedType>(val);
180 }
181
182 template <typename... TParams>
183 static SerialisedType adjustToSerialised(BaseSerialisedType val, SignExtendTag<TParams...>)
184 {
185 auto valueTmp =
186 static_cast<UnsignedSerialisedType>(val) & UnsignedValueMask;
187
188 return signExtUnsignedSerialised(valueTmp, HasSignTag<>());
189 }
190
191 template <typename... TParams>
192 static constexpr BaseSerialisedType adjustFromSerialised(SerialisedType val, JustCastTag<TParams...>)
193 {
194 return castToBaseSerializedType(val, HasSignTag<>());
195 }
196
197 template <typename... TParams>
198 static BaseSerialisedType adjustFromSerialised(SerialisedType val, SignExtendTag<TParams...>)
199 {
200 auto valueTmp = static_cast<UnsignedSerialisedType>(val) & UnsignedValueMask;
201 return castToBaseSerializedType(signExtUnsignedSerialised(valueTmp, HasSignTag<>()), HasSignTag<>());
202 }
203
204 template <typename... TParams>
205 static constexpr SerialisedType signExtUnsignedSerialised(UnsignedSerialisedType val, UnsignedTag<TParams...>)
206 {
207 return static_cast<SerialisedType>(val);
208 }
209
210 template <typename... TParams>
211 static SerialisedType signExtUnsignedSerialised(UnsignedSerialisedType val, SignedTag<TParams...>)
212 {
213 static const UnsignedSerialisedType SignExtMask = ~(UnsignedValueMask);
214 static const UnsignedSerialisedType SignMask =
215 static_cast<UnsignedSerialisedType>(1U) << (BitLength - 1);
216
217 if ((val & SignMask) != 0) {
218 val |= SignExtMask;
219 }
220 return static_cast<SerialisedType>(val);
221 }
222
223 template <typename... TParams>
224 static constexpr BaseSerialisedType castToBaseSerializedType(SerialisedType val, UnsignedTag<TParams...>)
225 {
226 return static_cast<BaseSerialisedType>(static_cast<UnsignedSerialisedType>(val));
227 }
228
229 template <typename... TParams>
230 static constexpr BaseSerialisedType castToBaseSerializedType(SerialisedType val, SignedTag<TParams...>)
231 {
232 return static_cast<BaseSerialisedType>(val);
233 }
234
235 static const std::size_t Length = TLen;
236 static const std::size_t BitsInByte = std::numeric_limits<std::uint8_t>::digits;
237 static const std::size_t BitLength = Length * BitsInByte;
238
239 static const UnsignedSerialisedType UnsignedValueMask =
240 static_cast<UnsignedSerialisedType>(details::UnsignedValueMaskWrap<Length>::Value);
241
242 static_assert(0 < Length, "Length is expected to be greater than 0");
243};
244
245} // namespace adapter
246
247} // namespace field
248
249} // namespace comms
250
This file contains classes required for generic custom assertion functionality.
This file contain definition of error statuses used by comms module.
comms::option::def::FixedLength< TLen, TSignExtend > FixedLength
Same as comms::option::def::FixedLength.
Definition options.h:1535
comms::option::def::Endian< TEndian > Endian
Same as comms::option::def::Endian.
Definition options.h:1471
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.
STL namespace.
Replacement to std::conditional.
Definition type_traits.h:29
Replacement to some types from standard type_traits.