binary_serializer.h Source File

CPP API: binary_serializer.h Source File
binary_serializer.h
Go to the documentation of this file.
1 /*
2 * Copyright (C) 2020-2026 MEmilio
3 *
4 * Authors: Daniel Abele
5 *
6 * Contact: Martin J. Kuehn <Martin.Kuehn@DLR.de>
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 */
20 #ifndef MIO_IO_BINARY_SERIALIZER_H
21 #define MIO_IO_BINARY_SERIALIZER_H
22 
23 #include "memilio/io/io.h"
26 
27 #include <memory>
28 #include <type_traits>
29 #include <utility>
30 #include <vector>
31 
32 namespace mio
33 {
34 
39 {
40 public:
47  ByteStream(size_t n)
48  : m_buf(n, 0)
49  , m_read_head(0)
50  {
51  }
52 
57  : ByteStream(0)
58  {
59  }
60 
66  void write(const unsigned char* const p, size_t s)
67  {
68  m_buf.insert(m_buf.end(), p, p + s);
69  }
70 
77  bool read(unsigned char* p, size_t s)
78  {
79  if (s <= (m_buf.size() - m_read_head)) {
80  auto read_begin = m_buf.begin() + m_read_head;
81  auto read_end = read_begin + s;
82  std::copy(read_begin, read_end, p);
83  m_read_head += s;
84  return true;
85  }
86  return false;
87  }
88 
93  void reset(size_t n)
94  {
95  m_buf.assign(n, 0);
96  m_read_head = 0;
97  }
98 
102  void reset()
103  {
104  reset(0);
105  }
106 
111  const unsigned char* data() const
112  {
113  return m_buf.data();
114  }
115  unsigned char* data()
116  {
117  return m_buf.data();
118  }
124  size_t data_size() const
125  {
126  return m_buf.size();
127  }
128 
129 private:
130  std::vector<unsigned char> m_buf;
131  size_t m_read_head;
132 };
133 
139 {
140 public:
141  BinarySerializerObject(ByteStream& stream, std::shared_ptr<IOStatus> status, int flags)
143  , m_stream(stream)
144  {
145  }
146 
154  template <class T>
155  requires std::is_trivial_v<T>
156  void add_element(const std::string& name, const T& value);
157 
163  void add_element(const std::string& name, const std::string& value);
164 
170  template <class T>
171  requires(!std::is_trivial_v<T>)
172  void add_element(const std::string& name, const T& value);
173 
182  template <class T>
183  requires std::is_trivial_v<T>
184  IOResult<T> expect_element(const std::string& name, Tag<T> tag);
185 
192  template <class T>
193  requires(!std::is_trivial_v<T>)
194  IOResult<T> expect_element(const std::string& name, Tag<T> tag);
195 
203 
209  template <class T>
210  void add_optional(const std::string& name, const T* value);
211 
217  template <class T>
218  IOResult<boost::optional<T>> expect_optional(const std::string& name, Tag<T>);
219 
226  template <class Iter>
227  void add_list(const std::string& name, Iter b, Iter e);
228 
234  template <class T>
235  IOResult<std::vector<T>> expect_list(const std::string& name, Tag<T>);
236 
237 private:
239 };
240 
246 {
247 public:
248  BinarySerializerContext(ByteStream& stream, std::shared_ptr<IOStatus> status, int flags)
250  , m_stream(stream)
251  {
252  }
253 
258  BinarySerializerObject create_object(const std::string& type)
259  {
262  obj.add_element("Type", type);
263  }
264  return obj;
265  }
266 
271  BinarySerializerObject expect_object(const std::string& type)
272  {
275  auto type_result = obj.expect_element("Type", Tag<std::string>{});
276  if (!type_result) {
277  *m_status = IOStatus(StatusCode::InvalidType, "No TypeInfo in stream.");
278  }
279  else if (type_result.value() != type) {
281  "Unexpected type in stream:" + type_result.value() + ". Expected " + type);
282  }
283  }
284  return obj;
285  }
286 
293  template <class T>
294  requires std::is_trivial_v<T>
295  friend void serialize_internal(BinarySerializerContext& ctxt, const T& t)
296  {
297  //add element to dummy object.
298  //objects don't store anything in the stream, so this has no overhead.
299  BinarySerializerObject obj(ctxt.m_stream, ctxt.m_status, ctxt.m_flags);
300  obj.add_element("", t);
301  }
302 
309  template <class T>
310  requires std::is_trivial_v<T>
312  {
313  unused(tag);
314  //read element from on dummy object.
315  BinarySerializerObject obj(ctxt.m_stream, ctxt.m_status, ctxt.m_flags);
316  return obj.expect_element("", Tag<T>{});
317  }
318 
319 private:
321 };
322 
323 template <class T>
324  requires std::is_trivial_v<T>
325 void BinarySerializerObject::add_element(const std::string& name, const T& value)
326 {
327  mio::unused(name);
328  auto p = reinterpret_cast<const unsigned char*>(std::addressof(value));
329  m_stream.write(p, sizeof(value));
330 }
331 
332 template <class T>
333  requires(!std::is_trivial_v<T>)
334 void BinarySerializerObject::add_element(const std::string& name, const T& value)
335 {
336  mio::unused(name);
338  mio::serialize(ctxt, value);
339 }
340 
341 inline void BinarySerializerObject::add_element(const std::string& name, const std::string& value)
342 {
343  mio::unused(name);
344  const auto size = value.size();
345  const auto p_size = reinterpret_cast<const unsigned char*>(std::addressof(size));
346  const auto p_data = reinterpret_cast<const unsigned char*>(value.data());
347  m_stream.write(p_size, sizeof(size));
348  m_stream.write(p_data, size);
349 }
350 
351 template <class T>
352  requires std::is_trivial_v<T>
354 {
355  mio::unused(name);
356 
357  if (m_status->is_ok()) {
358  T t;
359  if (m_stream.read(reinterpret_cast<unsigned char*>(std::addressof(t)), sizeof(t))) {
360  return mio::success(t);
361  }
362  else {
363  *m_status =
364  IOStatus(mio::StatusCode::UnknownError, "Unexpected EOF reading " + name + " from binary stream.");
365  }
366  }
367  return failure(*m_status);
368 }
369 
370 template <class T>
371  requires(!std::is_trivial_v<T>)
372 IOResult<T> BinarySerializerObject::expect_element(const std::string& name, Tag<T> tag)
373 {
374  mio::unused(name);
375  if (m_status->is_ok()) {
377  return mio::deserialize(ctxt, tag);
378  }
379  return failure(*m_status);
380 }
381 
382 inline IOResult<std::string> BinarySerializerObject::expect_element(const std::string& name, Tag<std::string>)
383 {
384  mio::unused(name);
385  if (m_status->is_ok()) {
386  size_t size;
387  if (m_stream.read(reinterpret_cast<unsigned char*>(&size), sizeof(size))) {
388  std::string t(size, 0);
389  if (m_stream.read(reinterpret_cast<unsigned char*>(&t[0]), size)) {
390  return success(t);
391  }
392  }
393  *m_status = IOStatus(StatusCode::UnknownError, "Unexpected EOF reading " + name + " from binary stream.");
394  }
395  return failure(*m_status);
396 }
397 
398 template <class Iter>
399 void BinarySerializerObject::add_list(const std::string& name, Iter b, Iter e)
400 {
401  mio::unused(name);
402  add_element("Size", size_t(e - b));
403  for (; b != e; ++b) {
404  add_element("Item", *b);
405  }
406 }
407 
408 template <class T>
410 {
411  mio::unused(name);
412  BOOST_OUTCOME_TRY(auto&& size, expect_element("Size", Tag<size_t>{}));
413  std::vector<T> v;
414  v.reserve(size);
415  for (auto i = size_t(0); i < size; ++i) {
416  BOOST_OUTCOME_TRY(auto&& t, expect_element("Item", Tag<T>{}));
417  v.emplace_back(std::move(t));
418  }
419  return success(v);
420 }
421 
422 template <class T>
423 void BinarySerializerObject::add_optional(const std::string& name, const T* value)
424 {
425  mio::unused(name);
426  add_element("Exists", size_t(value ? 1 : 0));
427  if (value) {
428  add_element("Value", *value);
429  }
430 }
431 
432 template <class T>
434 {
435  mio::unused(name);
436  BOOST_OUTCOME_TRY(auto&& size, expect_element("Exists", Tag<size_t>{}));
437  if (size) {
438  BOOST_OUTCOME_TRY(auto&& t, expect_element("Value", Tag<T>{}));
439  return mio::success(t);
440  }
441  return mio::success(boost::optional<T>{});
442 }
443 
451 template <class T>
452 ByteStream serialize_binary(const T& t, int flags = 0)
453 {
454  ByteStream stream;
455  BinarySerializerContext ctxt(stream, std::make_shared<IOStatus>(), flags);
456  mio::serialize(ctxt, t);
457  return stream;
458 }
459 
467 template <class T>
469 {
470  BinarySerializerContext ctxt(stream, std::make_shared<IOStatus>(), flags);
471  return mio::deserialize(ctxt, Tag<T>{});
472 }
473 
474 } // namespace mio
475 
476 #endif
Serializes objects in binary format.
Definition: binary_serializer.h:246
BinarySerializerContext(ByteStream &stream, std::shared_ptr< IOStatus > status, int flags)
Definition: binary_serializer.h:248
requires std::is_trivial_v< T > friend void serialize_internal(BinarySerializerContext &ctxt, const T &t)
Serialize "naked" ints, etc.
Definition: binary_serializer.h:295
ByteStream & m_stream
Reference to a stream that stores the serialized bytes.
Definition: binary_serializer.h:320
BinarySerializerObject create_object(const std::string &type)
Begin serialization of a new object.
Definition: binary_serializer.h:258
requires std::is_trivial_v< T > friend IOResult< T > deserialize_internal(BinarySerializerContext &ctxt, Tag< T > tag)
Deserialize "naked" ints, etc.
Definition: binary_serializer.h:311
BinarySerializerObject expect_object(const std::string &type)
Begin deserialization of an object.
Definition: binary_serializer.h:271
Stores a binary serialized object.
Definition: binary_serializer.h:139
requires std::is_trivial_v< T > void add_element(const std::string &name, const T &value)
Add element of basic type to this object.
Definition: binary_serializer.h:325
IOResult< boost::optional< T > > expect_optional(const std::string &name, Tag< T >)
Get optional element from this object.
Definition: binary_serializer.h:433
void add_optional(const std::string &name, const T *value)
Add optional element to this object.
Definition: binary_serializer.h:423
requires(!std::is_trivial_v< T >) void add_element(const std requires std::is_trivial_v< T > IOResult< T > expect_element(const std::string &name, Tag< T > tag)
Add serializable value as an element to this object.
requires(!std::is_trivial_v< T >) IOResult< T > expect_element(const std IOResult< std::string > expect_element(const std::string &name, Tag< std::string > tag)
Get deserializable element from this object.
BinarySerializerObject(ByteStream &stream, std::shared_ptr< IOStatus > status, int flags)
Definition: binary_serializer.h:141
void add_list(const std::string &name, Iter b, Iter e)
Add a list of elements to this object.
Definition: binary_serializer.h:399
IOResult< std::vector< T > > expect_list(const std::string &name, Tag< T >)
Get a list of elements from this object.
Definition: binary_serializer.h:409
ByteStream & m_stream
Reference to a stream that stores the serialized bytes.
Definition: binary_serializer.h:238
In-memory stream of bytes.
Definition: binary_serializer.h:39
ByteStream(size_t n)
Create stream with n readable bytes initialized to 0.
Definition: binary_serializer.h:47
void reset()
Reset the stream to empty.
Definition: binary_serializer.h:102
bool read(unsigned char *p, size_t s)
Read bytes from the stream.
Definition: binary_serializer.h:77
void reset(size_t n)
Reset the stream to n readable bytes of value 0.
Definition: binary_serializer.h:93
std::vector< unsigned char > m_buf
store of written/readable bytes
Definition: binary_serializer.h:130
ByteStream()
Create empty stream.
Definition: binary_serializer.h:56
void write(const unsigned char *const p, size_t s)
Write bytes to the stream.
Definition: binary_serializer.h:66
unsigned char * data()
Get the pointer to the buffer of the stream.
Definition: binary_serializer.h:115
const unsigned char * data() const
Get the pointer to the buffer of the stream.
Definition: binary_serializer.h:111
size_t m_read_head
index in the buffer where next byte is read/written
Definition: binary_serializer.h:131
size_t data_size() const
Get the size of the buffer of the stream.
Definition: binary_serializer.h:124
IOStatus represents the result of an operation.
Definition: io.h:197
Base class for implementations of serialization framework concepts.
Definition: serializer_base.h:35
const IOStatus & status() const
The current status of serialization.
Definition: serializer_base.h:69
int m_flags
Definition: serializer_base.h:86
int flags() const
Flags that determine the behavior of serialization.
Definition: serializer_base.h:51
std::shared_ptr< IOStatus > m_status
Definition: serializer_base.h:85
trait_value< T >::RETURN_TYPE & value(T &x)
Definition: ad.hpp:3308
int size(Comm comm)
Return the size of the given communicator.
Definition: miompi.cpp:75
A collection of classes to simplify handling of matrix shapes in meta programming.
Definition: models/abm/analyze_result.h:30
IOResult< T > deserialize(IOContext &io, Tag< T > tag)
Restores an object from the data stored in an IO context.
Definition: io.h:860
auto failure(const IOStatus &s)
Create an object that is implicitly convertible to an error IOResult<T>.
Definition: io.h:380
void serialize(IOContext &io, const T &t)
Save data that describes an object in a format determined by the given context.
Definition: io.h:836
boost::outcome_v2::in_place_type_t< T > Tag
Type that is used for overload resolution.
Definition: io.h:407
auto i
Definition: io.h:809
IOResult< T > deserialize_binary(ByteStream &stream, Tag< T >, int flags=0)
Deserialize an object from binary format.
Definition: binary_serializer.h:468
requires(!std::is_trivial_v< T >) void BinarySerializerObject
Definition: binary_serializer.h:333
auto success()
Create an object that is implicitly convertible to a succesful IOResult<void>.
Definition: io.h:359
ByteStream serialize_binary(const T &t, int flags=0)
Serialize an object into binary format.
Definition: binary_serializer.h:452
void unused(T &&...)
Does nothing, can be used to mark variables as not used.
Definition: compiler_diagnostics.h:30
@ IOF_IncludeTypeInfo
Include type info in the serialization.
Definition: io.h:88
boost::outcome_v2::unchecked< T, IOStatus > IOResult
Value-or-error type for operations that return a value but can fail.
Definition: io.h:353