serializing_stream.cpp
1 /*
2  * This file is part of CasADi.
3  *
4  * CasADi -- A symbolic framework for dynamic optimization.
5  * Copyright (C) 2010-2023 Joel Andersson, Joris Gillis, Moritz Diehl,
6  * KU Leuven. All rights reserved.
7  * Copyright (C) 2011-2014 Greg Horn
8  *
9  * CasADi is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 3 of the License, or (at your option) any later version.
13  *
14  * CasADi is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with CasADi; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22  *
23  */
24 
25 
26 #include "function.hpp"
27 #include "serializing_stream.hpp"
28 #include "slice.hpp"
29 #include "linsol.hpp"
30 #include "importer.hpp"
31 #include "resource_internal.hpp"
32 #include "fmu.hpp"
33 #include "generic_type.hpp"
34 #include "shared_object.hpp"
35 #include "sx_node.hpp"
36 #include "sparsity_internal.hpp"
37 #include "mx_node.hpp"
38 #include "function_internal.hpp"
39 #include "fmu_impl.hpp" // Not sure why this is needed and importer_internal.hpp is not
40 #include <iomanip>
41 
42 namespace casadi {
43 
44  static casadi_int serialization_protocol_version = 3;
45  static casadi_int serialization_check = 123456789012345;
46 
47  DeserializingStream::DeserializingStream(std::istream& in_s) : in(in_s), debug_(false) {
48  casadi_assert(in_s.good(), "Invalid input stream. If you specified an input file, "
49  "make sure it exists relative to the current directory.");
50 
51  if (in_s.peek() != std::char_traits<char>::eof()) {
52  setup();
53  }
54  }
55 
57  if (set_up_) return;
58  // Sanity check
59  casadi_int check;
60  unpack(check);
61  casadi_assert(check==serialization_check,
62  "DeserializingStream sanity check failed. "
63  "Expected " + str(serialization_check) + ", but got " + str(check) + ".");
64 
65  // API version check
66  casadi_int v;
67  unpack(v);
68  casadi_assert(v==serialization_protocol_version,
69  "Serialization protocol is not compatible. "
70  "Got version " + str(v) + ", while " +
71  str(serialization_protocol_version) + " was expected.");
72 
73  bool debug;
74  unpack(debug);
75  debug_ = debug;
76  set_up_ = true;
77  }
78 
79  SerializingStream::SerializingStream(std::ostream& out_s) :
80  SerializingStream(out_s, Dict()) {
81  }
82 
83  SerializingStream::SerializingStream(std::ostream& out_s, const Dict& opts) :
84  out(out_s), debug_(false) {
85  // Sanity check
87  // API version check
89 
90  bool debug = false;
91 
92  // Read options
93  for (auto&& op : opts) {
94  if (op.first=="debug") {
95  debug = op.second;
96  } else {
97  casadi_error("Unknown option: '" + op.first + "'.");
98  }
99  }
100 
101  pack(debug);
102  debug_ = debug;
103  }
104 
105  void SerializingStream::decorate(char e) {
106  if (debug_) pack(e);
107  }
108 
109  void DeserializingStream::assert_decoration(char e) {
110  if (debug_) {
111  char t;
112  unpack(t);
113  casadi_assert(t==e, "DeserializingStream error '" + str(e) + "' vs '" + str(t) + "'.");
114  }
115  }
116 
117  void DeserializingStream::unpack(casadi_int& e) {
118  assert_decoration('J');
119  int64_t n;
120  char* c = reinterpret_cast<char*>(&n);
121 
122  for (int j=0;j<8;++j) unpack(c[j]);
123  e = n;
124  }
125 
126  void SerializingStream::pack(casadi_int e) {
127  decorate('J');
128  int64_t n = e;
129  const char* c = reinterpret_cast<const char*>(&n);
130  for (int j=0;j<8;++j) pack(c[j]);
131  }
132 
133  void SerializingStream::pack(size_t e) {
134  decorate('K');
135  uint64_t n = e;
136  const char* c = reinterpret_cast<const char*>(&n);
137  for (int j=0;j<8;++j) pack(c[j]);
138  }
139 
140  void DeserializingStream::unpack(size_t& e) {
141  assert_decoration('K');
142  uint64_t n;
143  char* c = reinterpret_cast<char*>(&n);
144 
145  for (int j=0;j<8;++j) unpack(c[j]);
146  e = n;
147  }
148 
150  assert_decoration('i');
151  int32_t n;
152  char* c = reinterpret_cast<char*>(&n);
153 
154  for (int j=0;j<4;++j) unpack(c[j]);
155  e = n;
156  }
157 
159  decorate('i');
160  int32_t n = e;
161  const char* c = reinterpret_cast<const char*>(&n);
162  for (int j=0;j<4;++j) pack(c[j]);
163  }
164 
165 #if SIZE_MAX != UINT_MAX || defined(__EMSCRIPTEN__) || defined(__POWERPC__)
166  void DeserializingStream::unpack(unsigned int& e) {
167  assert_decoration('u');
168  uint32_t n;
169  char* c = reinterpret_cast<char*>(&n);
170 
171  for (int j=0;j<4;++j) unpack(c[j]);
172  e = n;
173  }
174 
175  void SerializingStream::pack(unsigned int e) {
176  decorate('u');
177  uint32_t n = e;
178  const char* c = reinterpret_cast<const char*>(&n);
179  for (int j=0;j<4;++j) pack(c[j]);
180  }
181 #endif
182 
184  assert_decoration('b');
185  char n;
186  unpack(n);
187  e = n;
188  }
189 
190  void SerializingStream::pack(bool e) {
191  decorate('b');
192  pack(static_cast<char>(e));
193  }
194 
196  unsigned char ref = 'a';
197  in.get(e);
198  char t;
199  in.get(t);
200  e = (reinterpret_cast<unsigned char&>(e)-ref) +
201  ((reinterpret_cast<unsigned char&>(t)-ref) << 4);
202  }
203 
204  void SerializingStream::pack(char e) {
205  unsigned char ref = 'a';
206  // Note: outputstreams work neatly with std::hex,
207  // but inputstreams don't
208  out.put(ref + (reinterpret_cast<unsigned char&>(e) % 16));
209  out.put(ref + (reinterpret_cast<unsigned char&>(e) >> 4));
210  }
211 
212  void SerializingStream::pack(const std::string& e) {
213  decorate('s');
214  int s = static_cast<int>(e.size());
215  pack(s);
216  const char* c = e.c_str();
217  for (int j = 0; j < s; ++j) pack(c[j]);
218  }
219 
220  void DeserializingStream::unpack(std::string& e) {
221  assert_decoration('s');
222  int s;
223  unpack(s);
224  e.resize(s);
225  for (int j=0;j<s;++j) unpack(e[j]);
226  }
227 
228  void DeserializingStream::unpack(double& e) {
229  assert_decoration('d');
230  char* c = reinterpret_cast<char*>(&e);
231  for (int j=0;j<8;++j) unpack(c[j]);
232  }
233 
234  void SerializingStream::pack(double e) {
235  decorate('d');
236  const char* c = reinterpret_cast<const char*>(&e);
237  for (int j=0;j<8;++j) pack(c[j]);
238  }
239 
241  decorate('S');
242  shared_pack(e);
243  }
244 
246  assert_decoration('S');
247  shared_unpack<Sparsity, SparsityInternal>(e);
248  }
249 
250  void SerializingStream::pack(const MX& e) {
251  decorate('X');
252  shared_pack(e);
253  }
254 
256  assert_decoration('X');
257  shared_unpack<MX, MXNode>(e);
258  }
259 
261  decorate('F');
262  shared_pack(e);
263  }
264 
266  assert_decoration('F');
267  shared_unpack<Function, FunctionInternal>(e);
268  }
269 
271  decorate('M');
272  shared_pack(e);
273  }
274 
276  assert_decoration('M');
277  shared_unpack<Importer, ImporterInternal>(e);
278  }
279 
281  decorate('R');
282  shared_pack(e);
283  }
284 
286  assert_decoration('R');
287  shared_unpack<Resource, ResourceInternal>(e);
288  }
289 
290  void SerializingStream::pack(const Fmu& e) {
291  decorate('F');
292  shared_pack(e);
293  }
294 
296  assert_decoration('F');
297  shared_unpack<Fmu, FmuInternal>(e);
298  }
299 
301  decorate('L');
302  shared_pack(e);
303  }
304 
306  assert_decoration('L');
307  shared_unpack<Linsol, LinsolInternal>(e);
308  }
309 
311  decorate('G');
312  shared_pack(e);
313  }
314 
316  assert_decoration('G');
317  shared_unpack<GenericType, SharedObjectInternal>(e);
318  }
319 
320  void SerializingStream::pack(std::istream& s) {
321  decorate('B');
322  s.seekg(0, std::ios::end);
323  size_t len = s.tellg();
324  s.seekg(0, std::ios::beg);
325  pack(len);
326  char buffer[1024];
327  while (true) {
328  s.read(buffer, 1024);
329  size_t c = s.gcount();
330  for (size_t j=0;j<c;++j) {
331  pack(buffer[j]);
332  }
333  if (s.eof()) break;
334  }
335  }
336 
337  void DeserializingStream::unpack(std::ostream& s) {
338  assert_decoration('B');
339  size_t len;
340  unpack(len);
341  for (size_t i=0;i<len;++i) {
342  char c;
343  unpack(c);
344  s.put(c);
345  }
346  }
347 
349  decorate('S');
350  e.serialize(*this);
351  }
352 
354  assert_decoration('S');
355  e = Slice::deserialize(*this);
356  }
357 
359  decorate('E');
360  shared_pack(e);
361  }
362 
364  assert_decoration('E');
365  shared_unpack<SXElem, SXNode>(e);
366  }
367 
368  template<>
369  void DeserializingStream::unpack(std::vector<bool>& e) {
370  assert_decoration('V');
371  casadi_int s;
372  unpack(s);
373  e.resize(s);
374  for (casadi_int i=0;i<s;++i) {
375  bool b;
376  unpack(b);
377  e[i] = b;
378  }
379  }
380 
381  int DeserializingStream::version(const std::string& name) {
382  int load_version;
383  unpack(name+"::serialization::version", load_version);
384  return load_version;
385  }
386 
387  int DeserializingStream::version(const std::string& name, int min, int max) {
388  int load_version = version(name);
389  casadi_assert(load_version>=min && load_version<=max,
390  "DeSerialization of " + name + " failed. "
391  "Object written in version " + str(load_version) +
392  " but can only read version " + str(min) + "..." + str(max) + ".");
393  return load_version;
394  }
395 
396  void DeserializingStream::version(const std::string& name, int v) {
397  int load_version = version(name);
398  casadi_assert(load_version==v,
399  "DeSerialization of " + name + " failed. "
400  "Object written in version " + str(load_version) +
401  " but can only read in version " + str(v) + ".");
402  }
403 
404  void SerializingStream::version(const std::string& name, int v) {
405  pack(name+"::serialization::version", v);
406  }
407 
409  node(obj), is_sx(false) {
410  if (node) obj->count++;
411  }
412 
414  node(obj), is_sx(true) {
415  if (node) obj->count++;
416  }
417 
419  node(std::move(rhs.node)), is_sx(std::move(rhs.is_sx)) {
420  rhs.node = nullptr;
421  }
422 
424  std::swap(node, other.node);
425  std::swap(is_sx, other.is_sx);
426  return *this;
427  }
428 
430  if (!node) return;
431  if (is_sx) {
432  if (--static_cast<SXNode*>(node)->count == 0) {
433  delete static_cast<SXNode*>(node);
434  }
435  } else {
436  if (--static_cast<SharedObjectInternal*>(node)->count == 0) {
437  delete static_cast<SharedObjectInternal*>(node);
438  }
439  }
440  }
441 
443  nodes_ = &s.nodes_;
444  }
445 
447  shared_map_ = &s.shared_map_;
448  }
449 
451  shared_map_.clear();
452  }
453 
455  nodes_.clear();
456  }
457 
458 } // namespace casadi
Helper class for Serialization.
DeserializingStream(std::istream &in_s)
Constructor.
void unpack(Sparsity &e)
Reconstruct an object from the input stream.
void version(const std::string &name, int v)
void connect(SerializingStream &s)
Interface to binary FMU.
Definition: fmu.hpp:62
Function object.
Definition: function.hpp:60
Generic data type, can hold different types such as bool, casadi_int, std::string etc.
Importer.
Definition: importer.hpp:86
Linear solver.
Definition: linsol.hpp:55
MX - Matrix expression.
Definition: mx.hpp:92
RAII class for reading from a zip file.
Definition: resource.hpp:44
The basic scalar symbolic class of CasADi.
Definition: sx_elem.hpp:75
Internal node class for SX.
Definition: sx_node.hpp:49
unsigned int count
Definition: sx_node.hpp:197
Helper class for Serialization.
void version(const std::string &name, int v)
SerializingStream(std::ostream &out)
Constructor.
void pack(const Sparsity &e)
Serializes an object to the output stream.
void connect(DeserializingStream &s)
Class representing a Slice.
Definition: slice.hpp:48
void serialize(SerializingStream &s) const
Serialize an object.
Definition: slice.cpp:292
static Slice deserialize(DeserializingStream &s)
Deserialize without type information.
Definition: slice.cpp:298
General sparsity class.
Definition: sparsity.hpp:106
UniversalNodeOwner & operator=(const UniversalNodeOwner &other)=delete
The casadi namespace.
Definition: archiver.cpp:28
static casadi_int serialization_check
static casadi_int serialization_protocol_version
std::string str(const T &v)
String representation, any type.
GenericType::Dict Dict
C++ equivalent of Python's dict or MATLAB's struct.