COMMS
Template library intended to help with implementation of communication protocols.
Loading...
Searching...
No Matches
SequenceElemSerLengthFieldPrefix.h
1//
2// Copyright 2017 - 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/ErrorStatus.h"
14#include "comms/details/tag.h"
15#include "comms/ErrorStatus.h"
16#include "comms/field/basic/CommonFuncs.h"
18
19#include <algorithm>
20#include <cstddef>
21#include <iterator>
22#include <type_traits>
23#include <utility>
24
25namespace comms
26{
27
28namespace field
29{
30
31namespace adapter
32{
33
34template <typename TLenField, comms::ErrorStatus TStatus, typename TBase>
35class SequenceElemSerLengthFieldPrefix : public TBase
36{
37 using BaseImpl = TBase;
38 using LenField = TLenField;
39 static const std::size_t MaxAllowedElemLength =
40 static_cast<std::size_t>(LenField::maxValue());
41
42 static_assert(!LenField::isVersionDependent(),
43 "Prefix fields must not be version dependent");
44
45public:
46 using ValueType = typename BaseImpl::ValueType;
47 using ElementType = typename BaseImpl::ElementType;
48
50
51 explicit SequenceElemSerLengthFieldPrefix(const ValueType& val)
52 : BaseImpl(val)
53 {
54 }
55
56 explicit SequenceElemSerLengthFieldPrefix(ValueType&& val)
57 : BaseImpl(std::move(val))
58 {
59 }
60
61 SequenceElemSerLengthFieldPrefix(const SequenceElemSerLengthFieldPrefix&) = default;
62 SequenceElemSerLengthFieldPrefix(SequenceElemSerLengthFieldPrefix&&) = default;
63 SequenceElemSerLengthFieldPrefix& operator=(const SequenceElemSerLengthFieldPrefix&) = default;
64 SequenceElemSerLengthFieldPrefix& operator=(SequenceElemSerLengthFieldPrefix&&) = default;
65
66 std::size_t length() const
67 {
68 using ElemLengthTag =
69 typename comms::util::LazyShallowConditional<
70 BaseImpl::minElementLength() == BaseImpl::maxElementLength()
71 >::template Type<
72 FixedLengthElemTag,
73 VarLengthElemTag
74 >;
75 return lengthInternal(LenFieldLengthTag<>(), ElemLengthTag());
76 }
77
78 std::size_t elementLength(const ElementType& elem) const
79 {
80 return elementLengthInternal(elem, LenFieldLengthTag<>());
81 }
82
83 static constexpr std::size_t minLength()
84 {
85 return LenField::minLength();
86 }
87
88 static constexpr std::size_t maxLength()
89 {
90 return basic::CommonFuncs::maxSupportedLength();
91 }
92
93 static constexpr std::size_t minElementLength()
94 {
95 return LenField::minLength() + BaseImpl::minElementLength();
96 }
97
98 static constexpr std::size_t maxElementLength()
99 {
100 return LenField::maxLength() + BaseImpl::maxElementLength();
101 }
102
103 template <typename TIter>
104 ErrorStatus readElement(ElementType& elem, TIter& iter, std::size_t& len) const
105 {
106 auto fromIter = iter;
107 LenField lenField;
108 auto es = lenField.read(iter, len);
109 if (es != ErrorStatus::Success) {
110 return es;
111 }
112
113 auto diff = static_cast<std::size_t>(std::distance(fromIter, iter));
114 COMMS_ASSERT(diff <= len);
115 len -= diff;
116 if (len < lenField.getValue()) {
118 }
119
120 const auto reqLen = static_cast<std::size_t>(lenField.getValue());
121 std::size_t elemLen = reqLen;
122 es = BaseImpl::readElement(elem, iter, elemLen);
123 if (es == ErrorStatus::NotEnoughData) {
124 return TStatus;
125 }
126
127 if (es != ErrorStatus::Success) {
128 return es;
129 }
130
131 COMMS_ASSERT(elemLen <= reqLen);
132 std::advance(iter, elemLen);
133 len -= reqLen;
135 }
136
137 template <typename TIter>
138 void readElementNoStatus(ElementType& elem, TIter& iter) const = delete;
139
140 template <typename TIter>
141 comms::ErrorStatus read(TIter& iter, std::size_t len)
142 {
143 return basic::CommonFuncs::readSequence(*this, iter, len);
144 }
145
146 static constexpr bool hasReadNoStatus()
147 {
148 return false;
149 }
150
151 template <typename TIter>
152 void readNoStatus(TIter& iter) = delete;
153
154 template <typename TIter>
155 ErrorStatus readN(std::size_t count, TIter& iter, std::size_t& len)
156 {
157 return basic::CommonFuncs::readSequenceN(*this, count, iter, len);
158 }
159
160 template <typename TIter>
161 void readNoStatusN(std::size_t count, TIter& iter) = delete;
162
163 bool canWriteElement(const ElementType& elem) const
164 {
165 if (!BaseImpl::canWriteElement(elem)) {
166 return false;
167 }
168
169 auto elemLen = elementLength(elem);
170 if (MaxAllowedElemLength < elemLen) {
171 return false;
172 }
173
174 LenField lenField;
175 lenField.setValue(elemLen);
176 return lenField.canWrite();
177 }
178
179 template <typename TIter>
180 ErrorStatus writeElement(const ElementType& elem, TIter& iter, std::size_t& len) const
181 {
182 if (!canWriteElement(elem)) {
184 }
185
186 auto elemLength = BaseImpl::elementLength(elem);
187 LenField lenField;
188 lenField.setValue(elemLength);
189 auto es = lenField.write(iter, len);
190 if (es != ErrorStatus::Success) {
191 return es;
192 }
193
194 len -= lenField.length();
195 return BaseImpl::writeElement(elem, iter, len);
196 }
197
198 template <typename TIter>
199 static void writeElementNoStatus(const ElementType& elem, TIter& iter) = delete;
200
201 bool canWrite() const
202 {
203 return basic::CommonFuncs::canWriteSequence(*this);
204 }
205
206 template <typename TIter>
207 ErrorStatus write(TIter& iter, std::size_t len) const
208 {
209 return basic::CommonFuncs::writeSequence(*this, iter, len);
210 }
211
212 static constexpr bool hasWriteNoStatus()
213 {
214 return false;
215 }
216
217 template <typename TIter>
218 void writeNoStatus(TIter& iter) const = delete;
219
220 template <typename TIter>
221 ErrorStatus writeN(std::size_t count, TIter& iter, std::size_t& len) const
222 {
223 return basic::CommonFuncs::writeSequenceN(*this, count, iter, len);
224 }
225
226 template <typename TIter>
227 void writeNoStatusN(std::size_t count, TIter& iter) const = delete;
228
229 bool valid() const
230 {
231 if (!BaseImpl::valid()) {
232 return false;
233 }
234
235 auto& vec = BaseImpl::getValue();
236 for (auto& elem : vec) {
237 auto elemLen = BaseImpl::elementLength(elem);
238 if (MaxAllowedElemLength < elemLen) {
239 return false;
240 }
241 }
242 return true;
243 }
244
245private:
246
247 template <typename... TParams>
248 using FixedLengthLenFieldTag = comms::details::tag::Tag1<>;
249
250 template <typename... TParams>
251 using VarLengthLenFieldTag = comms::details::tag::Tag2<>;
252
253 template <typename... TParams>
254 using FixedLengthElemTag = comms::details::tag::Tag3<>;
255
256 template <typename... TParams>
257 using VarLengthElemTag = comms::details::tag::Tag4<>;
258
259 template <typename...>
260 using LenFieldLengthTag =
261 typename comms::util::LazyShallowConditional<
262 LenField::minLength() == LenField::maxLength()
263 >::template Type<
264 FixedLengthLenFieldTag,
265 VarLengthLenFieldTag
266 >;
267
268 template<typename... TParams>
269 std::size_t lengthInternal(FixedLengthLenFieldTag<TParams...>, FixedLengthElemTag<TParams...>) const
270 {
271 return (LenField::minLength() + BaseImpl::minElementLength()) * BaseImpl::getValue().size();
272 }
273
274 template<typename... TParams>
275 std::size_t lengthInternal(FixedLengthLenFieldTag<TParams...>, VarLengthElemTag<TParams...>) const
276 {
277 return lengthInternalIterative();
278 }
279
280 template <typename... TParams>
281 std::size_t lengthInternal(VarLengthLenFieldTag<TParams...>, FixedLengthElemTag<TParams...>) const
282 {
283 auto origElemLen = BaseImpl::minElementLength();
284 auto elemLen = std::min(origElemLen, std::size_t(MaxAllowedElemLength));
285 LenField lenField;
286 lenField.setValue(elemLen);
287 return (lenField.length() + origElemLen) * BaseImpl::getValue().size();
288 }
289
290 template <typename... TParams>
291 std::size_t lengthInternal(VarLengthLenFieldTag<TParams...>, VarLengthElemTag<TParams...>) const
292 {
293 return lengthInternalIterative();
294 }
295
296 std::size_t lengthInternalIterative() const
297 {
298 std::size_t result = 0U;
299 for (auto& elem : BaseImpl::getValue()) {
300 result += elementLength(elem);
301 }
302 return result;
303 }
304
305 template<typename... TParams>
306 std::size_t elementLengthInternal(const ElementType& elem, FixedLengthLenFieldTag<TParams...>) const
307 {
308 return LenField::minLength() + BaseImpl::elementLength(elem);
309 }
310
311 template <typename... TParams>
312 std::size_t elementLengthInternal(const ElementType& elem, VarLengthLenFieldTag<TParams...>) const
313 {
314 LenField lenField;
315 auto origElemLength = BaseImpl::elementLength(elem);
316 auto elemLength = std::min(origElemLength, std::size_t(MaxAllowedElemLength));
317 lenField.setValue(elemLength);
318 return lenField.length() + origElemLength;
319 }
320
321 template <typename TIter>
322 static void advanceWriteIterator(TIter& iter, std::size_t len)
323 {
324 using IterType = typename std::decay<decltype(iter)>::type;
325 using ByteType = typename std::iterator_traits<IterType>::value_type;
326 while (len > 0U) {
327 *iter = ByteType();
328 ++iter;
329 --len;
330 }
331 }
332};
333
334} // namespace adapter
335
336} // namespace field
337
338} // namespace comms
339
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.
comms::option::def::SequenceElemSerLengthFieldPrefix< TField, TReadErrorStatus > SequenceElemSerLengthFieldPrefix
Same as comms::option::def::SequenceElemSerLengthFieldPrefix.
Definition options.h:1574
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.