COMMS
Template library intended to help with implementation of communication protocols.
Loading...
Searching...
No Matches
SequenceFixedSize.h
1//
2// Copyright 2015 - 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"
17#include "comms/util/detect.h"
19
20#include <algorithm>
21#include <cstddef>
22#include <cstdint>
23#include <type_traits>
24#include <utility>
25
26namespace comms
27{
28
29namespace field
30{
31
32namespace adapter
33{
34
35template <typename TBase>
36class SequenceFixedSizeBase : public TBase
37{
38 using BaseImpl = TBase;
39
40public:
41 using ValueType = typename BaseImpl::ValueType;
42 using ElementType = typename BaseImpl::ElementType;
43
44 explicit SequenceFixedSizeBase(std::size_t maxSize)
45 : m_fixedSize(maxSize)
46 {
47 }
48
49 SequenceFixedSizeBase(std::size_t maxSize, const ValueType& val)
50 : BaseImpl(val),
51 m_fixedSize(maxSize)
52 {
53 }
54
55 SequenceFixedSizeBase(std::size_t maxSize, ValueType&& val)
56 : BaseImpl(std::move(val)),
57 m_fixedSize(maxSize)
58 {
59 }
60
61 SequenceFixedSizeBase(const SequenceFixedSizeBase&) = default;
62 SequenceFixedSizeBase(SequenceFixedSizeBase&&) = default;
63 SequenceFixedSizeBase& operator=(const SequenceFixedSizeBase&) = default;
64 SequenceFixedSizeBase& operator=(SequenceFixedSizeBase&&) = default;
65
66 std::size_t length() const
67 {
68 auto currSize = BaseImpl::getValue().size();
69 if (currSize == m_fixedSize) {
70 return BaseImpl::length();
71 }
72
73 if (currSize < m_fixedSize) {
74 auto remSize = m_fixedSize - currSize;
75 auto dummyElem = ElementType();
76 return BaseImpl::length() + (remSize * BaseImpl::elementLength(dummyElem));
77 }
78
79 using Tag =
80 typename comms::util::LazyShallowConditional<
81 std::is_integral<ElementType>::value && (sizeof(ElementType) == sizeof(std::uint8_t))
82 >::template Type<
83 HasRawDataTag,
84 HasFieldsTag
85 >;
86
87 return recalcLen(Tag());
88 }
89
90 template <typename TIter>
91 comms::ErrorStatus read(TIter& iter, std::size_t len)
92 {
93 return BaseImpl::readN(m_fixedSize, iter, len);
94 }
95
96 template <typename TIter>
97 void readNoStatus(TIter& iter)
98 {
99 return BaseImpl::readNoStatusN(m_fixedSize, iter);
100 }
101
102 template <typename TIter>
103 comms::ErrorStatus write(TIter& iter, std::size_t len) const
104 {
105 auto writeCount = std::min(BaseImpl::getValue().size(), m_fixedSize);
106 auto es = BaseImpl::writeN(writeCount, iter, len);
107 if (es != comms::ErrorStatus::Success) {
108 return es;
109 }
110
111 auto remCount = m_fixedSize - writeCount;
112 if (remCount == 0) {
113 return es;
114 }
115
116 auto dummyElem = ElementType();
117 while (0 < remCount) {
118 es = BaseImpl::writeElement(dummyElem, iter, len);
119 if (es != ErrorStatus::Success) {
120 break;
121 }
122
123 --remCount;
124 }
125
126 return es;
127 }
128
129 template <typename TIter>
130 void writeNoStatus(TIter& iter) const
131 {
132 auto writeCount = std::min(BaseImpl::getValue().size(), m_fixedSize);
133 BaseImpl::writeNoStatusN(writeCount, iter);
134
135 auto remCount = m_fixedSize - writeCount;
136 if (remCount == 0) {
137 return;
138 }
139
140 auto dummyElem = ElementType();
141 while (0 < remCount) {
142 BaseImpl::writeElementNoStatus(dummyElem, iter);
143 --remCount;
144 }
145 }
146
147 bool valid() const
148 {
149 return BaseImpl::valid() && (BaseImpl::getValue().size() <= m_fixedSize);
150 }
151
152 bool refresh()
153 {
154 if (!BaseImpl::refresh()) {
155 return false;
156 }
157
158 using Tag =
159 typename comms::util::LazyShallowConditional<
160 comms::util::detect::hasResizeFunc<ElementType>()
161 >::template Type<
162 HasResizeTag,
163 NoResizeTag
164 >;
165
166 return doRefresh(Tag());
167 }
168
169private:
170 template <typename... TParams>
171 using HasRawDataTag = comms::details::tag::Tag1<>;
172
173 template <typename... TParams>
174 using HasFieldsTag = comms::details::tag::Tag2<>;
175
176 template <typename... TParams>
177 using HasFixedLengthElemsTag = comms::details::tag::Tag3<>;
178
179 template <typename... TParams>
180 using HasVarLengthElemsTag = comms::details::tag::Tag4<>;
181
182 template <typename... TParams>
183 using HasResizeTag = comms::details::tag::Tag5<>;
184
185 template <typename... TParams>
186 using NoResizeTag = comms::details::tag::Tag6<>;
187
188 template <typename... TParams>
189 std::size_t recalcLen(HasFieldsTag<TParams...>) const
190 {
191 using Tag =
192 typename comms::util::LazyShallowConditional<
193 ElementType::minLength() == ElementType::maxLength()
194 >::template Type<
195 HasFixedLengthElemsTag,
196 HasVarLengthElemsTag
197 >;
198 return recalcLen(Tag());
199 }
200
201 template <typename... TParams>
202 std::size_t recalcLen(HasRawDataTag<TParams...>) const
203 {
204 return m_fixedSize;
205 }
206
207 template <typename... TParams>
208 std::size_t recalcLen(HasFixedLengthElemsTag<TParams...>) const
209 {
210 return m_fixedSize * ElementType::minLength();
211 }
212
213 template <typename... TParams>
214 std::size_t recalcLen(HasVarLengthElemsTag<TParams...>) const
215 {
216 std::size_t result = 0U;
217 auto count = m_fixedSize;
218 for (auto& elem : BaseImpl::getValue()) {
219 if (count == 0U) {
220 break;
221 }
222
223 result += BaseImpl::elementLength(elem);
224 --count;
225 }
226 return result;
227 }
228
229 template <typename... TParams>
230 bool doRefresh(HasResizeTag<TParams...>)
231 {
232 if (BaseImpl::getValue().size() == m_fixedSize) {
233 return false;
234 }
235
236 BaseImpl::value().resize(m_fixedSize);
237 return true;
238 }
239
240 template <typename... TParams>
241 static constexpr bool doRefresh(NoResizeTag<TParams...>)
242 {
243 return false;
244 }
245
246 std::size_t m_fixedSize = 0;
247};
248
249template <std::size_t TSize, typename TBase>
250class SequenceFixedSize : public SequenceFixedSizeBase<TBase>
251{
252 using BaseImpl = SequenceFixedSizeBase<TBase>;
253
254public:
255 using ValueType = typename BaseImpl::ValueType;
256 using ElementType = typename BaseImpl::ElementType;
257
258 explicit SequenceFixedSize()
259 : BaseImpl(TSize)
260 {
261 }
262
263 explicit SequenceFixedSize(const ValueType& val)
264 : BaseImpl(TSize, val)
265 {
266 }
267
268 SequenceFixedSize(ValueType&& val)
269 : BaseImpl(TSize, std::move(val))
270 {
271 }
272
273 SequenceFixedSize(const SequenceFixedSize&) = default;
274 SequenceFixedSize(SequenceFixedSize&&) = default;
275 SequenceFixedSize& operator=(const SequenceFixedSize&) = default;
276 SequenceFixedSize& operator=(SequenceFixedSize&&) = default;
277
278 static constexpr std::size_t minLength()
279 {
280 return BaseImpl::minLength() + BaseImpl::minElementLength() * TSize;
281 }
282
283 static constexpr std::size_t maxLength()
284 {
285 return BaseImpl::minLength() + BaseImpl::maxElementLength() * TSize;
286 }
287};
288
289} // namespace adapter
290
291} // namespace field
292
293} // namespace comms
294
This file contains classes required for generic custom assertion functionality.
This file contain definition of error statuses used by comms module.
comms::option::def::SequenceFixedSize< TSize > SequenceFixedSize
Same as comms::option::def::SequenceFixedSize.
Definition options.h:1607
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.
STL namespace.
Replacement to some types from standard type_traits.
Various compile-time detection functions of whether specific member functions and/or types exist.