COMMS
Template library intended to help with implementation of communication protocols.
Loading...
Searching...
No Matches
RemLengthMemberField.h
1//
2// Copyright 2019 - 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 <cstddef>
11#include <limits>
12#include <type_traits>
13#include <iterator>
14
15#include "comms/ErrorStatus.h"
16#include "comms/field/tag.h"
18#include "comms/details/tag.h"
19
20COMMS_MSVC_WARNING_PUSH
21COMMS_MSVC_WARNING_DISABLE(4127) // Disable warning about constant conditional expressions
22
23namespace comms
24{
25
26namespace field
27{
28
29namespace adapter
30{
31
32template <std::size_t TLenFieldIdx, typename TBase>
33class RemLengthMemberField : public TBase
34{
35 using BaseImpl = TBase;
36public:
37 using ValueType = typename BaseImpl::ValueType;
38
39 static_assert(TLenFieldIdx < std::tuple_size<ValueType>::value, "Bad index");
40 using LengthFieldType = typename std::tuple_element<TLenFieldIdx, ValueType>::type;
41 using VersionType = typename BaseImpl::VersionType;
42
44 {
45 refreshLengthInternal();
46 }
47
48 static constexpr std::size_t maxLength()
49 {
50 return MaxPossibleLen;
51 }
52
53 template <std::size_t TFromIdx>
54 static constexpr std::size_t maxLengthFrom()
55 {
56 using Tag =
57 typename comms::util::LazyShallowConditional<
58 TLenFieldIdx < TFromIdx
59 >::template Type<
60 BaseRedirectTag,
61 LocalTag
62 >;
63 return maxLengthFromInternal<TFromIdx>(Tag());
64 }
65
66 template <std::size_t TUntilIdx>
67 static constexpr std::size_t maxLengthUntil()
68 {
69 using Tag =
70 typename comms::util::LazyShallowConditional<
71 TUntilIdx <= TLenFieldIdx
72 >::template Type<
73 BaseRedirectTag,
74 LocalTag
75 >;
76
77 return maxLengthUntilInternal<TUntilIdx>(Tag());
78 }
79
80 template <std::size_t TFromIdx, std::size_t TUntilIdx>
81 static constexpr std::size_t maxLengthFromUntil()
82 {
83 using Tag =
84 typename comms::util::LazyShallowConditional<
85 (TUntilIdx <= TLenFieldIdx) || (TLenFieldIdx < TFromIdx)
86 >::template Type<
87 BaseRedirectTag,
88 LocalTag
89 >;
90
91 return maxLengthFromUntilInternal<TFromIdx, TUntilIdx>(Tag());
92 }
93
94 bool refresh()
95 {
96 bool updated = BaseImpl::refresh();
97 return refreshLengthInternal() || updated;
98 }
99
100 template <typename TIter>
101 ErrorStatus read(TIter& iter, std::size_t len)
102 {
103 return readFromUntilAndUpdateLen<0, std::tuple_size<ValueType>::value>(iter, len);
104 }
105
106 template <std::size_t TFromIdx, typename TIter>
107 ErrorStatus readFrom(TIter& iter, std::size_t len)
108 {
109 return readFromUntilAndUpdateLen<TFromIdx, std::tuple_size<ValueType>::value>(iter, len);
110 }
111
112 template <std::size_t TFromIdx, typename TIter>
113 ErrorStatus readFromAndUpdateLen(TIter& iter, std::size_t& len)
114 {
115 return readFromAndUpdateLen<TFromIdx, std::tuple_size<ValueType>::value>(iter, len);
116 }
117
118 template <std::size_t TUntilIdx, typename TIter>
119 ErrorStatus readUntil(TIter& iter, std::size_t len)
120 {
121 return readFromUntilAndUpdateLen<0U, TUntilIdx>(iter, len);
122 }
123
124 template <std::size_t TUntilIdx, typename TIter>
125 ErrorStatus readUntilAndUpdateLen(TIter& iter, std::size_t& len)
126 {
127 return readFromUntilAndUpdateLen<0, TUntilIdx>(iter, len);
128 }
129
130 template <std::size_t TFromIdx, std::size_t TUntilIdx, typename TIter>
131 ErrorStatus readFromUntil(TIter& iter, std::size_t len)
132 {
133 return readFromUntilAndUpdateLen<TFromIdx, TUntilIdx>(iter, len);
134 }
135
136 template <std::size_t TFromIdx, std::size_t TUntilIdx, typename TIter>
137 ErrorStatus readFromUntilAndUpdateLen(TIter& iter, std::size_t& len)
138 {
139 using Tag =
140 typename comms::util::LazyShallowConditional<
141 (TUntilIdx <= TLenFieldIdx)
142 >::template Type<
143 BaseRedirectTag,
144 LocalTag
145 >;
146 return readFromUntilInternal<TFromIdx, TUntilIdx>(iter, len, Tag());
147 }
148
149 template <typename TIter>
150 void readNoStatus(TIter& iter) = delete;
151
152 template <std::size_t TFromIdx, typename TIter>
153 void readFromNoStatus(TIter& iter) = delete;
154
155 template <std::size_t TUntilIdx, typename TIter>
156 void readUntilNoStatus(TIter& iter) = delete;
157
158 template <std::size_t TFromIdx, std::size_t TUntilIdx, typename TIter>
159 void readFromUntilNoStatus(TIter& iter) = delete;
160
161 static constexpr bool hasNonDefaultRefresh()
162 {
163 return true;
164 }
165
166 bool setVersion(VersionType version)
167 {
168 bool updated = BaseImpl::setVersion(version);
169 return refreshLengthInternal() || updated;
170 }
171
172 bool canWrite() const
173 {
174 if (!BaseImpl::canWrite()) {
175 return false;
176 }
177
178 std::size_t expLen = BaseImpl::template lengthFrom<TLenFieldIdx + 1>();
179 if (static_cast<std::size_t>(LengthFieldType::maxValue()) < expLen) {
180 return false;
181 }
182
183 LengthFieldType lenField;
184 lenField.setValue(expLen);
185 return lenField.canWrite();
186 }
187
188 template <typename TIter>
189 comms::ErrorStatus write(TIter& iter, std::size_t len) const
190 {
191 if (!canWrite()) {
193 }
194
195 return BaseImpl::write(iter, len);
196 }
197
198 static constexpr bool hasWriteNoStatus()
199 {
200 return false;
201 }
202
203 template <typename TIter>
204 comms::ErrorStatus writeNoStatus(TIter& iter, std::size_t len) const = delete;
205
206 bool valid() const
207 {
208 return BaseImpl::valid() && canWrite();
209 }
210
211private:
212 template <typename... TParams>
213 using BaseRedirectTag = comms::details::tag::Tag1<>;
214
215 template <typename... TParams>
216 using LocalTag = comms::details::tag::Tag2<>;
217
218 template <typename... TParams>
219 using PerformOpTag = comms::details::tag::Tag3<>;
220
221 template <typename... TParams>
222 using SkipOpTag = comms::details::tag::Tag4<>;
223
224 template <std::size_t TFromIdx, typename... TParams>
225 static constexpr std::size_t maxLengthFromInternal(BaseRedirectTag<TParams...>)
226 {
227 return BaseImpl::template maxLengthFrom<TFromIdx>();
228 }
229
230 template <std::size_t TFromIdx, typename... TParams>
231 static constexpr std::size_t maxLengthFromInternal(LocalTag<TParams...>)
232 {
233 return MaxPossibleLen;
234 }
235
236 template <std::size_t TUntilIdx, typename... TParams>
237 static constexpr std::size_t maxLengthUntilInternal(BaseRedirectTag<TParams...>)
238 {
239 return BaseImpl::template maxLengthUntil<TUntilIdx>();
240 }
241
242 template <std::size_t TUntilIdx, typename... TParams>
243 static constexpr std::size_t maxLengthUntilInternal(LocalTag<TParams...>)
244 {
245 return MaxPossibleLen;
246 }
247
248 template <std::size_t TFromIdx, std::size_t TUntilIdx, typename... TParams>
249 static constexpr std::size_t maxLengthFromUntilInternal(BaseRedirectTag<TParams...>)
250 {
251 return BaseImpl::template maxLengthFromUntil<TFromIdx, TUntilIdx>();
252 }
253
254 template <std::size_t TFromIdx, std::size_t TUntilIdx, typename... TParams>
255 static constexpr std::size_t maxLengthFromUntilInternal(LocalTag<TParams...>)
256 {
257 return MaxPossibleLen;
258 }
259
260 template <std::size_t TFromIdx, std::size_t TUntilIdx, typename TIter, typename... TParams>
261 ErrorStatus readFromUntilInternal(TIter& iter, std::size_t& len, BaseRedirectTag<TParams...>)
262 {
263 return BaseImpl::template readFromUntilAndUpdateLen<TFromIdx, TUntilIdx>(iter, len);
264 }
265
266 template <std::size_t TFromIdx, typename TIter, typename... TParams>
267 ErrorStatus readEarlierFieldsInternal(TIter& iter, std::size_t& len, PerformOpTag<TParams...>)
268 {
269 return BaseImpl::template readFromUntilAndUpdateLen<TFromIdx, TLenFieldIdx>(iter, len);
270 }
271
272 template <std::size_t TFromIdx, typename TIter, typename... TParams>
273 ErrorStatus readEarlierFieldsInternal(TIter& iter, std::size_t& len, SkipOpTag<TParams...>)
274 {
275 static_cast<void>(iter);
276 static_cast<void>(len);
277 return ErrorStatus::Success;
278 }
279
280 template <typename TIter, typename... TParams>
281 ErrorStatus readRemLengthFieldInternal(TIter& iter, std::size_t& len, std::size_t& remLen, PerformOpTag<TParams...>)
282 {
283 auto& mems = BaseImpl::value();
284 auto& lenField = std::get<TLenFieldIdx>(mems);
285
286 auto beforeLenReadIter = iter;
287 auto es = lenField.read(iter, len);
288 if (es != comms::ErrorStatus::Success) {
289 return es;
290 }
291
292 auto lenFieldLen = static_cast<std::size_t>(std::distance(beforeLenReadIter, iter));
293 COMMS_ASSERT(lenFieldLen <= len);
294 len -= lenFieldLen;
295
296 remLen = static_cast<std::size_t>(lenField.getValue());
297 return ErrorStatus::Success;
298 }
299
300 template <typename TIter, typename... TParams>
301 ErrorStatus readRemLengthFieldInternal(TIter& iter, std::size_t& len, std::size_t& remLen, SkipOpTag<TParams...>)
302 {
303 static_cast<void>(iter);
304 static_cast<void>(len);
305 auto& mems = BaseImpl::value();
306 auto& lenField = std::get<TLenFieldIdx>(mems);
307 remLen = lenField.value();
308 return ErrorStatus::Success;
309 }
310
311 template <std::size_t TUntilIdx, typename... TParams>
312 void skipUntilFieldInternal(std::size_t& reqLen, PerformOpTag<TParams...>)
313 {
314 static_assert(TLenFieldIdx < TUntilIdx, "Invalid assumption");
315 auto fieldsLen = BaseImpl::template lengthFromUntil<TLenFieldIdx + 1, TUntilIdx>();
316 COMMS_ASSERT(fieldsLen <= reqLen);
317 reqLen -= fieldsLen;
318 }
319
320 template <std::size_t TUntilIdx, typename... TParams>
321 void skipUntilFieldInternal(std::size_t& reqLen, SkipOpTag<TParams...>)
322 {
323 static_cast<void>(reqLen);
324 }
325
326 template <std::size_t TFromIdx, std::size_t TUntilIdx, typename TIter, typename... TParams>
327 ErrorStatus readFromUntilInternal(TIter& iter, std::size_t& len, LocalTag<TParams...>)
328 {
329 static_assert(TLenFieldIdx < TUntilIdx, "Invalid function invocation");
330 using EarlierFieldsTag =
331 typename comms::util::LazyShallowConditional<
332 (TFromIdx < TLenFieldIdx)
333 >::template Type<
334 PerformOpTag,
335 SkipOpTag
336 >;
337
338 auto es = readEarlierFieldsInternal<TFromIdx>(iter, len, EarlierFieldsTag());
339 if (es != comms::ErrorStatus::Success) {
340 return es;
341 }
342
343 using LenTag =
344 typename comms::util::LazyShallowConditional<
345 (TFromIdx <= TLenFieldIdx)
346 >::template Type<
347 PerformOpTag,
348 SkipOpTag
349 >;
350
351 std::size_t reqLen = 0U;
352 es = readRemLengthFieldInternal(iter, len, reqLen, LenTag());
353 if (es != comms::ErrorStatus::Success) {
354 return es;
355 }
356
357 using SkipTag =
358 typename comms::util::LazyShallowConditional<
359 (TLenFieldIdx < TFromIdx)
360 >::template Type<
361 PerformOpTag,
362 SkipOpTag
363 >;
364
365 skipUntilFieldInternal<TFromIdx>(reqLen, SkipTag());
366
367 static const std::size_t NextIdx = (TFromIdx <= TLenFieldIdx) ? TLenFieldIdx + 1 : TFromIdx;
368
369 if ((std::tuple_size<ValueType>::value <= TUntilIdx) &&
370 (len < reqLen)) {
372 }
373
374 auto remLen = std::min(len, reqLen);
375 es = BaseImpl::template readFromUntilAndUpdateLen<NextIdx, TUntilIdx>(iter, remLen);
376 auto consumed = reqLen - remLen;
377 len -= consumed;
378
379 if (es != comms::ErrorStatus::Success) {
380 return es;
381 }
382
383 if (std::tuple_size<ValueType>::value <= TUntilIdx) {
384 len -= remLen;
385 std::advance(iter, remLen);
386 }
387
388 return es;
389 }
390
391 bool refreshLengthInternal()
392 {
393 auto& mems = BaseImpl::value();
394 auto& lenField = std::get<TLenFieldIdx>(mems);
395 std::size_t expLen = BaseImpl::template lengthFrom<TLenFieldIdx + 1>();
396 std::size_t actLen = static_cast<std::size_t>(lenField.getValue());
397 if (expLen == actLen) {
398 return false;
399 }
400
401 lenField.setValue(expLen);
402 return true;
403 }
404
405
406 static const std::size_t MaxPossibleLen = 0xffff;
407};
408
409} // namespace adapter
410
411} // namespace field
412
413} // namespace comms
414
415COMMS_MSVC_WARNING_POP
416
#define COMMS_ASSERT(expr)
Generic assert macro.
Definition Assert.h:170
This file contain definition of error statuses used by comms module.
Contains definition of various tag classes.
comms::option::def::RemLengthMemberField< TIdx > RemLengthMemberField
Same as comms::option::def::RemLengthMemberField.
Definition options.h:1826
comms::option::def::VersionType< T > VersionType
Same as comms::option::def::VersionType.
Definition options.h:1797
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.
Replacement to some types from standard type_traits.