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