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