OGLplus  (0.59.0) a C++ wrapper for rendering APIs

string_backend.hpp
Go to the documentation of this file.
1 
9 #ifndef EAGINE_SERIALIZE_STRING_BACKEND_HPP
10 #define EAGINE_SERIALIZE_STRING_BACKEND_HPP
11 
12 #include "read_backend.hpp"
13 #include "write_backend.hpp"
14 #include <cstdio>
15 
16 #ifdef __clang__
17 EAGINE_DIAG_PUSH()
18 EAGINE_DIAG_OFF(format-nonliteral)
19 #endif
20 
21 namespace eagine {
22 //------------------------------------------------------------------------------
27  : public serializer_backend_id<
28  common_serializer_backend<string_serializer_backend>,
29  EAGINE_ID_V(String)> {
32  EAGINE_ID_V(String)>;
33 
34 public:
35  using base::base;
36  using base::remaining_size;
37  using base::sink;
40 
41  template <typename T>
42  auto do_write(span<const T> values, span_size_t& done) -> result {
43  done = 0;
44  result errors{};
45  for(auto& val : values) {
46  errors |= _write_one(val, type_identity<T>{});
47  errors |= sink(';');
48  if(errors) {
49  break;
50  }
51  ++done;
52  }
53 
54  return errors;
55  }
56 
57  auto enum_as_string() -> bool final {
58  return true;
59  }
60 
61  auto begin() -> result final {
62  return sink('<');
63  }
64 
65  auto begin_struct(span_size_t count) -> result final {
66  result errors = sink('{');
67  errors |= _write_one(count, type_identity<span_size_t>{});
68  errors |= sink('|');
69  return errors;
70  }
71 
72  auto begin_member(string_view name) -> result final {
73  result errors = sink(name);
74  errors |= sink(':');
75  return errors;
76  }
77 
78  auto finish_member(string_view) -> result final {
79  return {};
80  }
81 
82  auto finish_struct() -> result final {
83  return sink("};");
84  }
85 
86  auto begin_list(span_size_t count) -> result final {
87  result errors = sink('[');
88  errors |= _write_one(count, type_identity<span_size_t>{});
89  errors |= sink('|');
90  return errors;
91  }
92 
93  auto begin_element(span_size_t) -> result final {
94  return {};
95  }
96 
98  return {};
99  }
100 
101  auto finish_list() -> result final {
102  return sink("];");
103  }
104 
105  auto finish() -> result final {
106  return sink(">\0");
107  }
108 
109 private:
110  auto _write_one(bool value, type_identity<bool>) -> result {
111  if(value) {
112  return sink("true");
113  }
114  return sink("false");
115  }
116 
117  auto _write_one(char value, type_identity<char>) -> result {
118  result errors = sink('\'');
119  errors |= sink(value);
120  errors |= sink('\'');
121  return errors;
122  }
123 
124  template <typename T, std::size_t L>
125  auto _sprintf_one(T value, const char (&fmt)[L]) -> result {
126  std::array<char, 64> temp{};
127  // TODO: to_chars from_chars when available
128  // NOLINTNEXTLINE(hicpp-vararg)
129  std::snprintf(
130  temp.data(), temp.size(), static_cast<const char*>(fmt), value);
131  return sink(string_view(temp.data()));
132  }
133 
134  auto _write_one(byte value, type_identity<byte>) -> result {
135  return _sprintf_one(value, "%02hhx");
136  }
137 
138  auto _write_one(signed char value, type_identity<signed char>) -> result {
139  return _sprintf_one(value, "%hhd");
140  }
141 
142  auto _write_one(short value, type_identity<short>) -> result {
143  return _sprintf_one(value, "%hd");
144  }
145 
146  auto _write_one(unsigned short value, type_identity<unsigned short>)
147  -> result {
148  return _sprintf_one(value, "%hu");
149  }
150 
151  auto _write_one(int value, type_identity<int>) -> result {
152  return _sprintf_one(value, "%d");
153  }
154 
155  auto _write_one(unsigned value, type_identity<unsigned>) -> result {
156  return _sprintf_one(value, "%u");
157  }
158 
159  auto _write_one(long value, type_identity<long>) -> result {
160  return _sprintf_one(value, "%ld");
161  }
162 
163  auto _write_one(unsigned long value, type_identity<unsigned long>)
164  -> result {
165  return _sprintf_one(value, "%lu");
166  }
167 
168  auto _write_one(long long value, type_identity<long long>) -> result {
169  return _sprintf_one(value, "%lld");
170  }
171 
172  auto _write_one(unsigned long long value, type_identity<unsigned long long>)
173  -> result {
174  return _sprintf_one(value, "%llu");
175  }
176 
177  auto _write_one(float value, type_identity<float>) -> result {
178  return _sprintf_one(value, "%f");
179  }
180 
181  auto _write_one(double value, type_identity<double>) -> result {
182  return _sprintf_one(value, "%lf");
183  }
184 
185  auto _write_one(identifier id, type_identity<identifier>) -> result {
186  return sink(id.name().view());
187  }
188 
189  auto _write_one(decl_name name, type_identity<decl_name>) -> result {
190  return sink(name);
191  }
192 
193  auto _write_one(string_view str, type_identity<string_view>) -> result {
194  result errors = sink('"');
195  errors |= _write_one(str.size(), type_identity<span_size_t>{});
196  errors |= sink('|');
197  errors |= sink(str);
198  errors |= sink('"');
199  return errors;
200  }
201 };
202 //------------------------------------------------------------------------------
207  : public serializer_backend_id<
208  common_deserializer_backend<string_deserializer_backend>,
209  EAGINE_ID_V(String)> {
210  using base = serializer_backend_id<
212  EAGINE_ID_V(String)>;
213 
214 public:
215  using base::base;
216  using base::consume_until;
217  using base::require;
220 
221  template <typename T>
222  auto do_read(span<T> values, span_size_t& done) -> result {
223  done = 0;
224  result errors{};
225  for(T& val : values) {
226  errors |= _read_one(val, ';');
227  if(errors) {
228  break;
229  }
230  ++done;
231  }
232 
233  return errors;
234  }
235 
236  auto enum_as_string() -> bool final {
237  return true;
238  }
239 
240  void skip_whitespaces() {
241  consume_until([](byte b) { return !std::isspace(b); });
242  }
243 
244  auto begin() -> result final {
245  skip_whitespaces();
246  return require('<');
247  }
248 
249  auto begin_struct(span_size_t& count) -> result final {
250  result errors = require('{');
251  if(!errors) {
252  errors |= _read_one(count, '|');
253  }
254  return errors;
255  }
256 
257  auto begin_member(string_view name) -> result final {
258  result errors = require(name);
259  if(!errors) {
260  errors |= require(':');
261  }
262  return errors;
263  }
264 
266  return {};
267  }
268 
269  auto finish_struct() -> result final {
270  return require("};");
271  }
272 
273  auto begin_list(span_size_t& count) -> result final {
274  result errors = require('[');
275  if(!errors) {
276  errors |= _read_one(count, '|');
277  }
278  return errors;
279  }
280 
282  return {};
283  }
284 
286  return {};
287  }
288 
289  auto finish_list() -> result final {
290  return require("];");
291  }
292 
293  auto finish() -> result final {
294  return require(">\0");
295  }
296 
297 private:
298  auto _read_one(bool& value, char delimiter) -> result {
299  result temp{};
300  if(this->consume("true", temp)) {
301  value = true;
302  } else if(this->consume("false", temp)) {
303  value = false;
304  } else {
305  return temp;
306  }
307  return require(delimiter);
308  }
309 
310  auto _read_one(char& value, char delimiter) -> result {
311  result errors = require('\'');
312  if(!errors) {
313  if(auto opt_char = this->top_char()) {
314  value = extract(opt_char);
315  pop(1);
316  } else {
317  errors |= error_code::not_enough_data;
318  }
319  if(!errors) {
320  const char t[3] = {'\'', delimiter, '\0'};
321  errors |= require(string_view(t));
322  }
323  }
324  return errors;
325  }
326 
327  template <typename T, std::size_t L>
328  auto _sscanf_one(T& value, char delimiter, const char (&fmt)[L]) -> result {
329  result errors{};
330  if(auto src = this->string_before(delimiter, 128)) {
331  auto fmtstr = static_cast<const char*>(fmt);
332  // TODO: to_chars from_chars when available
333  // NOLINTNEXTLINE(hicpp-vararg)
334  if(std::sscanf(src.data(), fmtstr, &value) == 1) {
335  pop(src.size() + 1);
336  } else {
337  errors |= error_code::invalid_format;
338  }
339  } else {
340  errors |= error_code::not_enough_data;
341  }
342  return errors;
343  }
344 
345  auto _read_one(byte& value, char delimiter) -> result {
346  const char fmt[6] = {'%', 'h', 'h', 'x', delimiter, '\0'};
347  return _sscanf_one(value, delimiter, fmt);
348  }
349 
350  auto _read_one(signed char& value, char delimiter) -> result {
351  const char fmt[6] = {'%', 'h', 'h', 'd', delimiter, '\0'};
352  return _sscanf_one(value, delimiter, fmt);
353  }
354 
355  auto _read_one(short& value, char delimiter) -> result {
356  const char fmt[5] = {'%', 'h', 'd', delimiter, '\0'};
357  return _sscanf_one(value, delimiter, fmt);
358  }
359 
360  auto _read_one(unsigned short& value, char delimiter) -> result {
361  const char fmt[5] = {'%', 'h', 'u', delimiter, '\0'};
362  return _sscanf_one(value, delimiter, fmt);
363  }
364 
365  auto _read_one(int& value, char delimiter) -> result {
366  const char fmt[4] = {'%', 'd', delimiter, '\0'};
367  return _sscanf_one(value, delimiter, fmt);
368  }
369 
370  auto _read_one(unsigned& value, char delimiter) -> result {
371  const char fmt[4] = {'%', 'u', delimiter, '\0'};
372  return _sscanf_one(value, delimiter, fmt);
373  }
374 
375  auto _read_one(long& value, char delimiter) -> result {
376  const char fmt[5] = {'%', 'l', 'd', delimiter, '\0'};
377  return _sscanf_one(value, delimiter, fmt);
378  }
379 
380  auto _read_one(unsigned long& value, char delimiter) -> result {
381  const char fmt[5] = {'%', 'l', 'u', delimiter, '\0'};
382  return _sscanf_one(value, delimiter, fmt);
383  }
384 
385  auto _read_one(long long& value, char delimiter) -> result {
386  const char fmt[6] = {'%', 'l', 'l', 'd', delimiter, '\0'};
387  return _sscanf_one(value, delimiter, fmt);
388  }
389 
390  auto _read_one(unsigned long long& value, char delimiter) -> result {
391  const char fmt[6] = {'%', 'l', 'l', 'u', delimiter, '\0'};
392  return _sscanf_one(value, delimiter, fmt);
393  }
394 
395  auto _read_one(float& value, char delimiter) -> result {
396  const char fmt[4] = {'%', 'f', delimiter, '\0'};
397  return _sscanf_one(value, delimiter, fmt);
398  }
399 
400  auto _read_one(double& value, char delimiter) -> result {
401  const char fmt[5] = {'%', 'l', 'f', delimiter, '\0'};
402  return _sscanf_one(value, delimiter, fmt);
403  }
404 
405  auto _read_one(identifier& value, char delimiter) -> result {
406  result errors{};
407  if(auto src = this->string_before(delimiter, 32)) {
408  value = identifier(src);
409  pop(src.size() + 1);
410  } else {
411  errors |= error_code::not_enough_data;
412  }
413  return errors;
414  }
415 
416  auto _read_one(decl_name_storage& value, char delimiter) -> result {
417  result errors{};
418  const auto max = decl_name_storage::max_length + 1;
419  if(auto src = this->string_before(delimiter, max)) {
420  value.assign(src);
421  pop(src.size() + 1);
422  } else {
423  errors |= error_code::not_enough_data;
424  }
425  return errors;
426  }
427 
428  auto _read_one(std::string& value, char delimiter) -> result {
429  result errors = require('"');
430  if(!errors) {
431  span_size_t len{0};
432  errors |= _read_one(len, '|');
433  if(!errors) {
434  auto str = this->top_string(len);
435  if(str.size() < len) {
436  errors |= error_code::not_enough_data;
437  } else {
438  assign_to(value, str);
439  pop(str.size());
440  errors |= require('"');
441  errors |= require(delimiter);
442  }
443  }
444  }
445  return errors;
446  }
447 };
448 //------------------------------------------------------------------------------
449 } // namespace eagine
450 
451 #ifdef __clang__
452 EAGINE_DIAG_POP()
453 #endif
454 
455 #endif // EAGINE_SERIALIZE_STRING_BACKEND_HPP
Base class partially implementing serializer and deserialized backends.
Definition: write_backend.hpp:287
Cross-platform implementation of deserializer backend using ASCII-only strings.
Definition: string_backend.hpp:206
std::ptrdiff_t span_size_t
Signed span size type used by eagine.
Definition: types.hpp:36
basic_string_span< const char > string_view
Alias for const string views.
Definition: string_span.hpp:116
#define EAGINE_ID_V(NAME)
Macro for constructing instances of eagine::identifier_t.
Definition: identifier.hpp:359
auto begin_struct(span_size_t count) -> result final
Begins the serialization of a structure instance.
Definition: string_backend.hpp:65
Common code is placed in this namespace.
Definition: eagine.hpp:21
auto begin_list(span_size_t count) -> result final
Begins the serialization of a container instance.
Definition: string_backend.hpp:86
auto sink() -> serializer_data_sink *final
Definition: write_backend.hpp:143
static constexpr auto extract(api_result_value< Result, api_result_validity::never > &) noexcept -> Result &
Overload of extract for api_result_value.
Definition: c_api_wrap.hpp:270
auto finish() -> result final
Finishes the deserialization of a potentially complex structured value.
Definition: string_backend.hpp:293
auto begin_member(string_view name) -> result final
Begins the serialization of a structure data member.
Definition: string_backend.hpp:72
Class for manipulating and testing a group of enumeration-based bits.
Definition: bitfield.hpp:19
auto begin_element(span_size_t) -> result final
Begins the deserialization of a container element.
Definition: string_backend.hpp:281
static constexpr auto view(T *addr, S size) noexcept -> const_span< T >
Creates a view starting at the specified pointer and specified length.
Definition: span.hpp:458
static constexpr auto assign_to(std::basic_string< C, T, A > &str, memory::basic_span< const C, P, S > spn) -> auto &
Assigns the contents of a span of characters to a standard string.
Definition: string_span.hpp:137
auto begin_list(span_size_t &count) -> result final
Begins the deserialization of a container instance.
Definition: string_backend.hpp:273
auto finish_element(span_size_t) -> result final
Finishes the deserialization of a container element.
Definition: string_backend.hpp:285
auto begin_member(string_view name) -> result final
Begins the deserialization of a structure data member.
Definition: string_backend.hpp:257
deserialization_error_code
Deserialization error code bits enumeration.
Definition: result.hpp:53
auto finish() -> result final
Finishes the serialization of a potentially complex structured value.
Definition: string_backend.hpp:105
serialization_error_code
Serialization error code bits enumeration.
Definition: result.hpp:24
auto finish_list() -> result final
Finishes the serialization of a container instance.
Definition: string_backend.hpp:101
auto begin_struct(span_size_t &count) -> result final
Begins the deserialization of a structure instance.
Definition: string_backend.hpp:249
static auto format(std::string &&fmt_str) noexcept -> format_string_and_list< 0 >
Function taking a format string, returning an object for variable specification.
Definition: str_format.hpp:118
auto finish_member(string_view) -> result final
Finishes the deserialization of a structure data member.
Definition: string_backend.hpp:265
auto finish_element(span_size_t) -> result final
Finishes the serialization of a container element.
Definition: string_backend.hpp:97
auto enum_as_string() -> bool final
@brie Indicates if the backed stores enumerators as strings (or numeric values).
Definition: string_backend.hpp:57
bitfield< deserialization_error_code > deserialization_errors
Alias for deserialization error bitfield.
Definition: result.hpp:106
auto finish_struct() -> result final
Finishes the deserialization of a structure instance.
Definition: string_backend.hpp:269
auto begin() -> result final
Starts the deserialization of a potentially complex structured value.
Definition: string_backend.hpp:244
auto enum_as_string() -> bool final
@brie Indicates if the backed stores enumerators as strings (or numeric values).
Definition: string_backend.hpp:236
auto finish_list() -> result final
Finishes the deserialization of a container instance.
Definition: string_backend.hpp:289
Cross-platform implementation of serializer backend using ASCII-only strings.
Definition: string_backend.hpp:26
auto finish_member(string_view) -> result final
Finishes the serialization of a structure data member.
Definition: string_backend.hpp:78
Template type used mostly for function type-tag dispatching.
Definition: type_identity.hpp:19
auto begin_element(span_size_t) -> result final
Begins the serialization of a container element.
Definition: string_backend.hpp:93
auto finish_struct() -> result final
Finishes the serialization of a structure instance.
Definition: string_backend.hpp:82
auto begin() -> result final
Starts the serialization of a potentially complex structured value.
Definition: string_backend.hpp:61
bitfield< serialization_error_code > serialization_errors
Alias for serialization error bitfield.
Definition: result.hpp:100
basic_identifier< 10, 6, default_identifier_char_set, identifier_t > identifier
Default identifier type used throughout the project.
Definition: identifier.hpp:346

Copyright © 2015-2021 Matúš Chochlík.
<chochlik -at -gmail.com>
Documentation generated on Tue Apr 13 2021 by Doxygen (version 1.8.17).