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