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