COMMS
Template library intended to help with implementation of communication protocols.
Loading...
Searching...
No Matches
AvailableLength.h
1//
2// Copyright 2021 - 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/cast.h"
14#include "comms/details/tag.h"
15#include "comms/ErrorStatus.h"
16#include "comms/util/SizeToType.h"
17#include "comms/util/access.h"
19
20#include <algorithm>
21#include <cstddef>
22#include <cstdint>
23#include <iterator>
24#include <limits>
25#include <utility>
26
27namespace comms
28{
29
30namespace field
31{
32
33namespace adapter
34{
35
36template <typename TBase>
37class AvailableLength : public TBase
38{
39 using BaseImpl = TBase;
40 using BaseSerialisedType = typename BaseImpl::SerialisedType;
41
42public:
43
44 using ValueType = typename BaseImpl::ValueType;
45 using SerialisedType = typename BaseImpl::SerialisedType;
46
47 using Endian = typename BaseImpl::Endian;
48
49 AvailableLength() = default;
50
51 explicit AvailableLength(const ValueType& val)
52 : BaseImpl(val)
53 {
54 }
55
56 explicit AvailableLength(ValueType&& val)
57 : BaseImpl(std::move(val))
58 {
59 }
60
61 AvailableLength(const AvailableLength&) = default;
62 AvailableLength(AvailableLength&&) = default;
63 AvailableLength& operator=(const AvailableLength&) = default;
64 AvailableLength& operator=(AvailableLength&&) = default;
65
66 void setForcedLength(int len)
67 {
68 m_forcedLength = len;
69 }
70
71 int getForcedLength() const
72 {
73 return m_forcedLength;
74 }
75
76 std::size_t length() const
77 {
78 if (m_forcedLength == 0) {
79 return BaseImpl::length();
80 }
81
82 if (0 < m_forcedLength) {
83 return std::min(BaseImpl::length(), static_cast<std::size_t>(m_forcedLength));
84 }
85
86 auto serValue = toSerialised(BaseImpl::getValue());
87 for (std::size_t len = 1U; len < sizeof(SerialisedType); ++len) {
88 if (fitsLength(serValue, len)) {
89 return len;
90 }
91 }
92
93 return BaseImpl::length();
94 }
95
96 static constexpr std::size_t minLength()
97 {
98 return 1U;
99 }
100
101 static constexpr std::size_t maxLength()
102 {
103 return BaseImpl::maxLength();
104 }
105
106 static constexpr SerialisedType toSerialised(ValueType val)
107 {
108 return static_cast<SerialisedType>(BaseImpl::toSerialised(val));
109 }
110
111 static constexpr ValueType fromSerialised(SerialisedType val)
112 {
113 return BaseImpl::fromSerialised(static_cast<BaseSerialisedType>(val));
114 }
115
116 template <typename TIter>
117 comms::ErrorStatus read(TIter& iter, std::size_t size)
118 {
119 if (size == 0U) {
121 }
122
123 auto fromIter = iter;
124 auto unsignedSerialized = util::readData<UnsignedSerialisedType>(iter, std::min(size, BaseImpl::maxLength()), Endian());
125 auto len = static_cast<std::size_t>(std::distance(fromIter, iter));
126 BaseImpl::setValue(fromSerialised(signExtUnsignedSerialised(unsignedSerialized, len, HasSignTag())));
128 }
129
130 static constexpr bool hasReadNoStatus()
131 {
132 return false;
133 }
134
135 template <typename TIter>
136 void readNoStatus(TIter& iter) = delete;
137
138 template <typename TIter>
139 comms::ErrorStatus write(TIter& iter, std::size_t size) const
140 {
141 if (m_forcedLength == 0) {
142 return BaseImpl::write(iter, size);
143 }
144
145 if (!BaseImpl::canWrite()) {
147 }
148
149 auto fieldLen = length();
150 if (size < fieldLen) {
152 }
153
154 auto serValue = toSerialised(BaseImpl::getValue());
155 if (0 < m_forcedLength) {
156 comms::util::writeData(serValue, fieldLen, iter, Endian());
158 }
159
160 // variable length, based on value
161 std::size_t len = 1U;
162 for (; len < sizeof(serValue); ++len) {
163 if (!fitsLength(serValue, len)) {
164 continue;
165 }
166
167 comms::util::writeData(serValue, len, iter, Endian());
169 }
170
171 return BaseImpl::write(iter, size);
172 }
173
174 static constexpr bool hasWriteNoStatus()
175 {
176 return false;
177 }
178
179 template <typename TIter>
180 void writeNoStatus(TIter& iter) const = delete;
181
182private:
183 template <typename... TParams>
184 using UnsignedTag = comms::details::tag::Tag1<>;
185
186 template <typename... TParams>
187 using SignedTag = comms::details::tag::Tag2<>;
188
189 using HasSignTag =
190 typename comms::util::LazyShallowConditional<
191 std::is_signed<SerialisedType>::value
192 >::template Type<
193 SignedTag,
194 UnsignedTag
195 >;
196
197 using UnsignedSerialisedType = typename std::make_unsigned<SerialisedType>::type;
198
199 template <typename... TParams>
200 static constexpr SerialisedType signExtUnsignedSerialised(
201 UnsignedSerialisedType val,
202 std::size_t,
203 UnsignedTag<TParams...>)
204 {
205 return static_cast<SerialisedType>(val);
206 }
207
208 template <typename... TParams>
209 static SerialisedType signExtUnsignedSerialised(
210 UnsignedSerialisedType val,
211 std::size_t bytesCount,
212 SignedTag<TParams...>)
213 {
214 UnsignedSerialisedType signBitMask =
215 static_cast<UnsignedSerialisedType>(1U) << ((bytesCount * BitsInByte) - (bytesCount + 1));
216
217 if ((val & signBitMask) == 0U) {
218 return static_cast<SerialisedType>(val);
219 }
220
221 UnsignedSerialisedType signExtMask =
222 static_cast<UnsignedSerialisedType>(~(signBitMask - 1));
223
224 val |= signExtMask;
225 return static_cast<SerialisedType>(val);
226 }
227
228 template <typename... TParams>
229 static SerialisedType getMinLimitedValue(std::size_t len, UnsignedTag<TParams...>)
230 {
231 static_cast<void>(len);
232 return static_cast<SerialisedType>(0);
233 }
234
235 template <typename... TParams>
236 static SerialisedType getMinLimitedValue(std::size_t len, SignedTag<TParams...>)
237 {
238 COMMS_ASSERT(len < sizeof(UnsignedSerialisedType));
239 auto mask =
240 ((static_cast<UnsignedSerialisedType>(1U) << ((len * BitsInByte) - 1)) - 1U);
241
242 return static_cast<SerialisedType>(~static_cast<UnsignedSerialisedType>(mask));
243 }
244
245 template <typename... TParams>
246 static SerialisedType getMaxLimitedValue(std::size_t len, UnsignedTag<TParams...>)
247 {
248 COMMS_ASSERT(len < sizeof(UnsignedSerialisedType));
249 auto value =
250 ((static_cast<UnsignedSerialisedType>(1U) << (len * BitsInByte)) - 1U);
251 return static_cast<SerialisedType>(value);
252 }
253
254 template <typename... TParams>
255 static SerialisedType getMaxLimitedValue(std::size_t len, SignedTag<TParams...>)
256 {
257 COMMS_ASSERT(len < sizeof(UnsignedSerialisedType));
258 auto value =
259 ((static_cast<UnsignedSerialisedType>(1U) << ((len * BitsInByte) - 1)) - 1U);
260 return static_cast<SerialisedType>(value);
261 }
262
263 static bool fitsLength(SerialisedType val, std::size_t len)
264 {
265 if (sizeof(val) <= len) {
266 return true;
267 }
268
269 auto minValue = getMinLimitedValue(len, HasSignTag());
270 auto maxValue = getMaxLimitedValue(len, HasSignTag());
271 return ((minValue <= val) && (val <= maxValue));
272 }
273
274 static const std::size_t BitsInByte =
275 std::numeric_limits<std::uint8_t>::digits;
276
277 int m_forcedLength = -1;
278};
279
280} // namespace adapter
281
282} // namespace field
283
284} // namespace comms
285
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::Endian< TEndian > Endian
Same as comms::option::def::Endian.
Definition options.h:1473
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.
STL namespace.
Replacement to some types from standard type_traits.