COMMS
Template library intended to help with implementation of communication protocols.
Loading...
Searching...
No Matches
SequenceElemFixedSerLengthFieldPrefix.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>
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 SequenceElemFixedSerLengthFieldPrefix(const ValueType& val)
47 : BaseImpl(val)
48 {
49 }
50
51 explicit SequenceElemFixedSerLengthFieldPrefix(ValueType&& val)
52 : BaseImpl(std::move(val))
53 {
54 }
55
56 SequenceElemFixedSerLengthFieldPrefix(const SequenceElemFixedSerLengthFieldPrefix&) = default;
57 SequenceElemFixedSerLengthFieldPrefix(SequenceElemFixedSerLengthFieldPrefix&&) = default;
58 SequenceElemFixedSerLengthFieldPrefix& operator=(const SequenceElemFixedSerLengthFieldPrefix&) = default;
59 SequenceElemFixedSerLengthFieldPrefix& operator=(SequenceElemFixedSerLengthFieldPrefix&&) = default;
60
61 std::size_t length() const
62 {
63
64 using LenFieldLengthTag =
65 typename comms::util::LazyShallowConditional<
66 LenField::minLength() == LenField::maxLength()
67 >::template Type<
68 FixedLengthLenFieldTag,
69 VarLengthLenFieldTag
70 >;
71
72 return lengthInternal(LenFieldLengthTag());
73 }
74
75 static constexpr std::size_t minLength()
76 {
77 return LenField::minLength();
78 }
79
80 static constexpr std::size_t maxLength()
81 {
82 return basic::CommonFuncs::maxSupportedLength();
83 }
84
85 template <typename TIter>
86 ErrorStatus readElement(ElementType& elem, TIter& iter, std::size_t& len) const
87 {
88 COMMS_ASSERT(elemLen_ < MaxLengthLimit);
89
90 if (len < elemLen_) {
92 }
93
94 std::size_t elemLen = elemLen_;
95 auto es = BaseImpl::readElement(elem, iter, elemLen);
97 return TStatus;
98 }
99
100 if (es != ErrorStatus::Success) {
101 return es;
102 }
103
104 COMMS_ASSERT(elemLen <= elemLen_);
105 std::advance(iter, elemLen);
106 len -= elemLen_;
108 }
109
110 template <typename TIter>
111 void readElementNoStatus(ElementType& elem, TIter& iter) const = delete;
112
113 template <typename TIter>
114 comms::ErrorStatus read(TIter& iter, std::size_t len)
115 {
116 if (len == 0U) {
117 elemLen_ = 0U;
119 }
120
121 auto es = readLen(iter, len);
122 if (es != comms::ErrorStatus::Success) {
123 return es;
124 }
125
126 return basic::CommonFuncs::readSequence(*this, iter, len);
127 }
128
129 static constexpr bool hasReadNoStatus()
130 {
131 return false;
132 }
133
134 template <typename TIter>
135 void readNoStatus(TIter& iter) = delete;
136
137 template <typename TIter>
138 ErrorStatus readN(std::size_t count, TIter& iter, std::size_t& len)
139 {
140 if (0U < count) {
141 auto es = readLen(iter, len);
142 if (es != comms::ErrorStatus::Success) {
143 return es;
144 }
145 }
146 else {
147 elemLen_ = 0U;
148 }
149 return basic::CommonFuncs::readSequenceN(*this, count, iter, len);
150 }
151
152 template <typename TIter>
153 void readNoStatusN(std::size_t count, TIter& iter) = delete;
154
155 bool canWriteElement(const ElementType& elem) const
156 {
157 if (!BaseImpl::canWriteElement(elem)) {
158 return false;
159 }
160
161 auto elemLen = elem.length();
162 if (MaxAllowedElemLength < elemLen) {
163 return false;
164 }
165
166 LenField lenField;
167 lenField.setValue(elemLen);
168 return lenField.canWrite();
169 }
170
171 bool canWrite() const
172 {
173 if (BaseImpl::getValue().empty()) {
174 return BaseImpl::canWrite();
175 }
176
177 return BaseImpl::canWrite() && canWriteElement(BaseImpl::getValue().front());
178 }
179
180 template <typename TIter>
181 ErrorStatus write(TIter& iter, std::size_t len) const
182 {
183 if (!BaseImpl::getValue().empty()) {
184 if (!canWriteElement(BaseImpl::getValue().front())) {
186 }
187
188 auto es = writeLen(iter, len); // len is updated
189 if (es != comms::ErrorStatus::Success) {
190 return es;
191 }
192 }
193
194 return basic::CommonFuncs::writeSequence(*this, iter, len);
195 }
196
197 static constexpr bool hasWriteNoStatus()
198 {
199 return false;
200 }
201
202 template <typename TIter>
203 void writeNoStatus(TIter& iter) const = delete;
204
205 template <typename TIter>
206 ErrorStatus writeN(std::size_t count, TIter& iter, std::size_t& len) const
207 {
208 if (0U < count) {
209 COMMS_ASSERT(!BaseImpl::getValue().empty());
210 if (!canWriteElement(BaseImpl::getValue().front())) {
212 }
213
214 auto es = writeLen(iter, len); // len is updated
215 if (es != comms::ErrorStatus::Success) {
216 return es;
217 }
218 }
219
220 return basic::CommonFuncs::writeSequenceN(*this, count, iter, len);
221 }
222
223 template <typename TIter>
224 void writeNoStatusN(std::size_t count, TIter& iter) const = delete;
225
226 bool valid() const
227 {
228 return BaseImpl::valid() && canWrite();
229 }
230
231private:
232
233 template <typename... TParams>
234 using FixedLengthLenFieldTag = comms::details::tag::Tag1<>;
235
236 template <typename... TParams>
237 using VarLengthLenFieldTag = comms::details::tag::Tag2<>;
238
239 template <typename... TParams>
240 std::size_t lengthInternal(FixedLengthLenFieldTag<TParams...>) const
241 {
242 std::size_t prefixLen = 0U;
243 if (!BaseImpl::getValue().empty()) {
244 prefixLen = LenField::minLength();
245 }
246 return (prefixLen + BaseImpl::length());
247 }
248
249 template <typename... TParams>
250 std::size_t lengthInternal(VarLengthLenFieldTag<TParams...>) const
251 {
252 std::size_t prefixLen = 0U;
253 if (!BaseImpl::getValue().empty()) {
254 LenField lenField;
255 lenField.setValue(
256 std::min(BaseImpl::minElementLength(), std::size_t(MaxAllowedElemLength)));
257 prefixLen = lenField.length();
258 }
259
260 return (prefixLen + BaseImpl::length());
261 }
262
263 template <typename TIter>
264 static void advanceWriteIterator(TIter& iter, std::size_t len)
265 {
266 basic::CommonFuncs::advanceWriteIterator(iter, len);
267 }
268
269 template <typename TIter>
270 ErrorStatus readLen(TIter& iter, std::size_t& len)
271 {
272 auto fromIter = iter;
273 LenField lenField;
274 auto es = lenField.read(iter, len);
275 if (es != ErrorStatus::Success) {
276 return es;
277 }
278
279 auto diff = static_cast<std::size_t>(std::distance(fromIter, iter));
280 COMMS_ASSERT(diff <= len);
281 len -= diff;
282
283 elemLen_ = static_cast<std::size_t>(lenField.getValue());
284 if (elemLen_ == MaxLengthLimit) {
285 return TStatus;
286 }
287
289 }
290
291 template <typename TIter>
292 ErrorStatus writeLen(TIter& iter, std::size_t& len) const
293 {
294 auto elemLength = BaseImpl::minElementLength();
295 LenField lenField;
296 lenField.setValue(elemLength);
297 auto es = lenField.write(iter, len);
298 if (es != ErrorStatus::Success) {
299 return es;
300 }
301
302 len -= lenField.length();
303 return es;
304 }
305
306 template <typename TIter>
307 void writeLenNoStatus(TIter& iter) const
308 {
309 auto elemLength = BaseImpl::minElementLength();
310 LenField lenField;
311 lenField.setValue(elemLength);
312 lenField.writeNoStatus(iter);
313 }
314
315 static_assert(BaseImpl::minElementLength() == BaseImpl::maxElementLength(),
316 "Option SequenceElemFixedSerLengthFieldPrefix can be used only with fixed length "
317 "elements.");
318 static_assert(1U <= LenField::minLength(), "Invalid min length assumption");
319
320 static const std::size_t MaxLengthLimit =
321 std::numeric_limits<std::size_t>::max();
322 std::size_t elemLen_ = MaxLengthLimit;
323};
324
325} // namespace adapter
326
327} // namespace field
328
329} // namespace comms
330
331
332
333
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::SequenceElemFixedSerLengthFieldPrefix< TField, TReadErrorStatus > SequenceElemFixedSerLengthFieldPrefix
Same as comms::option::def::SequenceElemFixedSerLengthFieldPrefix.
Definition options.h:1523
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.