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