COMMS
Template library intended to help with implementation of communication protocols.
Loading...
Searching...
No Matches
String.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"
14#include "comms/details/tag.h"
15#include "comms/ErrorStatus.h"
16#include "comms/field/basic/CommonFuncs.h"
17#include "comms/field/tag.h"
18#include "comms/util/access.h"
19#include "comms/util/assign.h"
20#include "comms/util/detect.h"
21#include "comms/util/MaxSizeOf.h"
25
26#include <algorithm>
27#include <cstddef>
28#include <iterator>
29#include <type_traits>
30#include <utility>
31
32COMMS_MSVC_WARNING_PUSH
33COMMS_MSVC_WARNING_DISABLE(4100)
34
35namespace comms
36{
37
38namespace field
39{
40
41namespace basic
42{
43
44namespace details
45{
46
47template <typename TStorage>
48struct StringMaxLengthRetrieveHelper
49{
50 static const std::size_t Value = CommonFuncs::maxSupportedLength();
51};
52
53template <std::size_t TSize>
54struct StringMaxLengthRetrieveHelper<comms::util::StaticString<TSize> >
55{
56 static const std::size_t Value = TSize - 1;
57};
58
59} // namespace details
60
61template <typename TFieldBase, typename TStorage>
62class String : public TFieldBase
63{
64 using BaseImpl = TFieldBase;
65public:
66 using Endian = typename BaseImpl::Endian;
67
68 using ValueType = TStorage;
69 using ElementType = typename TStorage::value_type;
70 using CommsTag = comms::field::tag::String;
71
72 static_assert(std::is_integral<ElementType>::value, "String of characters only supported");
73 static_assert(sizeof(ElementType) == sizeof(char), "Single byte charactes only supported");
74
75 String() = default;
76
77 explicit String(const ValueType& val)
78 : m_value(val)
79 {
80 }
81
82 explicit String(ValueType&& val)
83 : m_value(std::move(val))
84 {
85 }
86
87 String(const String&) = default;
88 String(String&&) = default;
89 String& operator=(const String&) = default;
90 String& operator=(String&&) = default;
91 ~String() noexcept = default;
92
93 const ValueType& value() const
94 {
95 return m_value;
96 }
97
98 ValueType& value()
99 {
100 return m_value;
101 }
102
103 const ValueType& getValue() const
104 {
105 return value();
106 }
107
108 template <typename T>
109 void setValue(T&& val)
110 {
111 value() = std::forward<T>(val);
112 }
113
114 ValueType& createBack()
115 {
116 m_value.push_back(ValueType());
117 return m_value.back();
118 }
119
120 void clear()
121 {
122 static_assert(comms::util::detect::hasClearFunc<ValueType>(),
123 "The string type must have clear() member function");
124 m_value.clear();
125 }
126
127 constexpr std::size_t length() const
128 {
129 return m_value.size() * sizeof(ElementType);
130 }
131
132 static constexpr std::size_t minLength()
133 {
134 return 0U;
135 }
136
137 static constexpr std::size_t maxLength()
138 {
139 return
140 details::StringMaxLengthRetrieveHelper<TStorage>::Value *
141 sizeof(ElementType);
142 }
143
144 static constexpr bool valid()
145 {
146 return true;
147 }
148
149 static constexpr std::size_t minElementLength()
150 {
151 return sizeof(ElementType);
152 }
153
154 static constexpr std::size_t maxElementLength()
155 {
156 return minElementLength();
157 }
158
159 static constexpr std::size_t elementLength(const ElementType& elem)
160 {
161 return sizeof(typename std::decay<decltype(elem)>::type);
162 }
163
164 template <typename TIter>
165 static ErrorStatus readElement(ElementType& elem, TIter& iter, std::size_t& len)
166 {
167 if (len < sizeof(ElementType)) {
168 return ErrorStatus::NotEnoughData;
169 }
170
171 elem = comms::util::readData<ElementType>(iter, Endian());
172 len -= sizeof(ElementType);
173 return ErrorStatus::Success;
174 }
175
176 template <typename TIter>
177 static void readElementNoStatus(ElementType& elem, TIter& iter)
178 {
179 elem = comms::util::readData<ElementType>(iter, Endian());
180 }
181
182 template <typename TIter>
183 ErrorStatus read(TIter& iter, std::size_t len)
184 {
185 using IterType = typename std::decay<decltype(iter)>::type;
186 using IterCategory =
187 typename std::iterator_traits<IterType>::iterator_category;
188 static_assert(std::is_base_of<std::random_access_iterator_tag, IterCategory>::value,
189 "Iterator for reading is expected to be random access one");
190
191 using ConstPointer = typename ValueType::const_pointer;
192 auto* str = reinterpret_cast<ConstPointer>(&(*iter));
193 auto endStr = str;
194 std::advance(endStr, std::min(len, comms::util::maxSizeOf(m_value)));
195 comms::util::assign(m_value, str, endStr);
196 std::advance(iter, len);
197 return ErrorStatus::Success;
198 }
199
200 static constexpr bool hasReadNoStatus()
201 {
202 return false;
203 }
204
205 template <typename TIter>
206 void readNoStatus(TIter& iter) = delete;
207
208 template <typename TIter>
209 ErrorStatus readN(std::size_t count, TIter& iter, std::size_t& len)
210 {
211 if (len < count) {
213 }
214
215 return read(iter, count);
216 }
217
218 template <typename TIter>
219 void readNoStatusN(std::size_t count, TIter& iter)
220 {
221 read(iter, count);
222 }
223
224 template <typename TIter>
225 static ErrorStatus writeElement(const ElementType& elem, TIter& iter, std::size_t& len)
226 {
227 if (len < sizeof(ElementType)) {
228 return ErrorStatus::BufferOverflow;
229 }
230
231 comms::util::writeData(elem, iter, Endian());
232 len -= sizeof(ElementType);
233 return ErrorStatus::Success;
234 }
235
236 template <typename TIter>
237 static void writeElementNoStatus(const ElementType& elem, TIter& iter)
238 {
239 comms::util::writeData(elem, iter, Endian());
240 }
241
242 template <typename TIter>
243 ErrorStatus write(TIter& iter, std::size_t len) const
244 {
245 if (len < length()) {
247 }
248
249 writeNoStatus(iter);
251 }
252
253 template <typename TIter>
254 void writeNoStatus(TIter& iter) const
255 {
256 std::copy_n(m_value.begin(), m_value.size(), iter);
257 doAdvance(iter, m_value.size());
258 }
259
260 template <typename TIter>
261 ErrorStatus writeN(std::size_t count, TIter& iter, std::size_t& len) const
262 {
263 count = std::min(count, m_value.size());
264
265 if (len < count) {
267 }
268
269 writeNoStatusN(count, iter);
271 }
272
273 template <typename TIter>
274 void writeNoStatusN(std::size_t count, TIter& iter) const
275 {
276 count = std::min(count, m_value.size());
277 std::copy_n(m_value.begin(), count, iter);
278 doAdvance(iter, count);
279 }
280
281private:
282 template<typename... TParams>
283 using AdvancableTag = comms::details::tag::Tag1<>;
284
285 template<typename... TParams>
286 using NotAdvancableTag = comms::details::tag::Tag2<>;
287
288 template <typename TIter>
289 static void doAdvance(TIter& iter, std::size_t len)
290 {
291 using IterType = typename std::decay<decltype(iter)>::type;
292 using IterCategory = typename std::iterator_traits<IterType>::iterator_category;
293 static const bool InputIter =
294 std::is_base_of<std::input_iterator_tag, IterCategory>::value;
295 using Tag =
296 typename comms::util::LazyShallowConditional<
297 InputIter
298 >::template Type<
299 AdvancableTag,
300 NotAdvancableTag
301 >;
302 doAdvance(iter, len, Tag());
303 }
304
305 template <typename TIter, typename... TParams>
306 static void doAdvance(TIter& iter, std::size_t len, AdvancableTag<TParams...>)
307 {
308 std::advance(iter, len);
309 }
310
311 template <typename TIter, typename... TParams>
312 static void doAdvance(TIter&, std::size_t, NotAdvancableTag<TParams...>)
313 {
314 }
315
316 ValueType m_value;
317};
318
319} // namespace basic
320
321} // namespace field
322
323} // namespace comms
324
325COMMS_MSVC_WARNING_POP
This file contains classes required for generic custom assertion functionality.
Contains various compiler related definitions.
This file contain definition of error statuses used by comms module.
Contains comms::util::StaticString class.
Contains comms::util::StaticVector class.
Contains functions for raw data access / (de)serialization.
Provides helper assign() function to allow easy assignment of values to collections or views.
Contains definition of various tag classes.
comms::option::def::Endian< TEndian > Endian
Same as comms::option::def::Endian.
Definition options.h:1473
void writeData(T value, TIter &iter, const traits::endian::Big &endian)
Same as writeBig<T, TIter>()
Definition access.h:707
void assign(T &obj, TIter from, TIter to)
Assigns a new value to provided object.
Definition assign.h:41
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.