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 
49  casadi_assert(in_s.good(), "Invalid input stream. If you specified an input file, "
50  "make sure it exists relative to the current directory.");
51 
52  // Sanity check
53  casadi_int check;
54  unpack(check);
55  casadi_assert(check==serialization_check,
56  "DeserializingStream sanity check failed. "
57  "Expected " + str(serialization_check) + ", but got " + str(check) + ".");
58 
59  // API version check
60  casadi_int v;
61  unpack(v);
62  casadi_assert(v==serialization_protocol_version,
63  "Serialization protocol is not compatible. "
64  "Got version " + str(v) + ", while " +
65  str(serialization_protocol_version) + " was expected.");
66 
67  bool debug;
68  unpack(debug);
69  debug_ = debug;
70 
71  }
72 
73  SerializingStream::SerializingStream(std::ostream& out_s) :
74  SerializingStream(out_s, Dict()) {
75  }
76 
77  SerializingStream::SerializingStream(std::ostream& out_s, const Dict& opts) :
78  out(out_s), debug_(false) {
79  // Sanity check
81  // API version check
83 
84  bool debug = false;
85 
86  // Read options
87  for (auto&& op : opts) {
88  if (op.first=="debug") {
89  debug = op.second;
90  } else {
91  casadi_error("Unknown option: '" + op.first + "'.");
92  }
93  }
94 
95  pack(debug);
96  debug_ = debug;
97  }
98 
99  void SerializingStream::decorate(char e) {
100  if (debug_) pack(e);
101  }
102 
103  void DeserializingStream::assert_decoration(char e) {
104  if (debug_) {
105  char t;
106  unpack(t);
107  casadi_assert(t==e, "DeserializingStream error '" + str(e) + "' vs '" + str(t) + "'.");
108  }
109  }
110 
111  void DeserializingStream::unpack(casadi_int& e) {
112  assert_decoration('J');
113  int64_t n;
114  char* c = reinterpret_cast<char*>(&n);
115 
116  for (int j=0;j<8;++j) unpack(c[j]);
117  e = n;
118  }
119 
120  void SerializingStream::pack(casadi_int e) {
121  decorate('J');
122  int64_t n = e;
123  const char* c = reinterpret_cast<const char*>(&n);
124  for (int j=0;j<8;++j) pack(c[j]);
125  }
126 
127  void SerializingStream::pack(size_t e) {
128  decorate('K');
129  uint64_t n = e;
130  const char* c = reinterpret_cast<const char*>(&n);
131  for (int j=0;j<8;++j) pack(c[j]);
132  }
133 
134  void DeserializingStream::unpack(size_t& e) {
135  assert_decoration('K');
136  uint64_t n;
137  char* c = reinterpret_cast<char*>(&n);
138 
139  for (int j=0;j<8;++j) unpack(c[j]);
140  e = n;
141  }
142 
144  assert_decoration('i');
145  int32_t n;
146  char* c = reinterpret_cast<char*>(&n);
147 
148  for (int j=0;j<4;++j) unpack(c[j]);
149  e = n;
150  }
151 
153  decorate('i');
154  int32_t n = e;
155  const char* c = reinterpret_cast<const char*>(&n);
156  for (int j=0;j<4;++j) pack(c[j]);
157  }
158 
159 #if SIZE_MAX != UINT_MAX || defined(__EMSCRIPTEN__)
160  void DeserializingStream::unpack(unsigned int& e) {
161  assert_decoration('u');
162  uint32_t n;
163  char* c = reinterpret_cast<char*>(&n);
164 
165  for (int j=0;j<4;++j) unpack(c[j]);
166  e = n;
167  }
168 
169  void SerializingStream::pack(unsigned int e) {
170  decorate('u');
171  uint32_t n = e;
172  const char* c = reinterpret_cast<const char*>(&n);
173  for (int j=0;j<4;++j) pack(c[j]);
174  }
175 #endif
176 
178  assert_decoration('b');
179  char n;
180  unpack(n);
181  e = n;
182  }
183 
184  void SerializingStream::pack(bool e) {
185  decorate('b');
186  pack(static_cast<char>(e));
187  }
188 
190  unsigned char ref = 'a';
191  in.get(e);
192  char t;
193  in.get(t);
194  e = (reinterpret_cast<unsigned char&>(e)-ref) +
195  ((reinterpret_cast<unsigned char&>(t)-ref) << 4);
196  }
197 
198  void SerializingStream::pack(char e) {
199  unsigned char ref = 'a';
200  // Note: outputstreams work neatly with std::hex,
201  // but inputstreams don't
202  out.put(ref + (reinterpret_cast<unsigned char&>(e) % 16));
203  out.put(ref + (reinterpret_cast<unsigned char&>(e) >> 4));
204  }
205 
206  void SerializingStream::pack(const std::string& e) {
207  decorate('s');
208  int s = static_cast<int>(e.size());
209  pack(s);
210  const char* c = e.c_str();
211  for (int j = 0; j < s; ++j) pack(c[j]);
212  }
213 
214  void DeserializingStream::unpack(std::string& e) {
215  assert_decoration('s');
216  int s;
217  unpack(s);
218  e.resize(s);
219  for (int j=0;j<s;++j) unpack(e[j]);
220  }
221 
222  void DeserializingStream::unpack(double& e) {
223  assert_decoration('d');
224  char* c = reinterpret_cast<char*>(&e);
225  for (int j=0;j<8;++j) unpack(c[j]);
226  }
227 
228  void SerializingStream::pack(double e) {
229  decorate('d');
230  const char* c = reinterpret_cast<const char*>(&e);
231  for (int j=0;j<8;++j) pack(c[j]);
232  }
233 
235  decorate('S');
236  shared_pack(e);
237  }
238 
240  assert_decoration('S');
241  shared_unpack<Sparsity, SparsityInternal>(e);
242  }
243 
244  void SerializingStream::pack(const MX& e) {
245  decorate('X');
246  shared_pack(e);
247  }
248 
250  assert_decoration('X');
251  shared_unpack<MX, MXNode>(e);
252  }
253 
255  decorate('F');
256  shared_pack(e);
257  }
258 
260  assert_decoration('F');
261  shared_unpack<Function, FunctionInternal>(e);
262  }
263 
265  decorate('M');
266  shared_pack(e);
267  }
268 
270  assert_decoration('M');
271  shared_unpack<Importer, ImporterInternal>(e);
272  }
273 
275  decorate('R');
276  shared_pack(e);
277  }
278 
280  assert_decoration('R');
281  shared_unpack<Resource, ResourceInternal>(e);
282  }
283 
284  void SerializingStream::pack(const Fmu& e) {
285  decorate('F');
286  shared_pack(e);
287  }
288 
290  assert_decoration('F');
291  shared_unpack<Fmu, FmuInternal>(e);
292  }
293 
295  decorate('L');
296  shared_pack(e);
297  }
298 
300  assert_decoration('L');
301  shared_unpack<Linsol, LinsolInternal>(e);
302  }
303 
305  decorate('G');
306  shared_pack(e);
307  }
308 
310  assert_decoration('G');
311  shared_unpack<GenericType, SharedObjectInternal>(e);
312  }
313 
314  void SerializingStream::pack(std::istream& s) {
315  decorate('B');
316  s.seekg(0, std::ios::end);
317  size_t len = s.tellg();
318  s.seekg(0, std::ios::beg);
319  pack(len);
320  char buffer[1024];
321  for (size_t i=0;i<len;++i) {
322  s.read(buffer, 1024);
323  size_t c = s.gcount();
324  for (size_t j=0;j<c;++j) {
325  pack(buffer[j]);
326  }
327  if (s.rdstate() & std::ifstream::eofbit) break;
328  }
329  }
330 
331  void DeserializingStream::unpack(std::ostream& s) {
332  assert_decoration('B');
333  size_t len;
334  unpack(len);
335  for (size_t i=0;i<len;++i) {
336  char c;
337  unpack(c);
338  s.put(c);
339  }
340  }
341 
343  decorate('S');
344  e.serialize(*this);
345  }
346 
348  assert_decoration('S');
349  e = Slice::deserialize(*this);
350  }
351 
353  decorate('E');
354  shared_pack(e);
355  }
356 
358  assert_decoration('E');
359  shared_unpack<SXElem, SXNode>(e);
360  }
361 
362  template<>
363  void DeserializingStream::unpack(std::vector<bool>& e) {
364  assert_decoration('V');
365  casadi_int s;
366  unpack(s);
367  e.resize(s);
368  for (casadi_int i=0;i<s;++i) {
369  bool b;
370  unpack(b);
371  e[i] = b;
372  }
373  }
374 
375  int DeserializingStream::version(const std::string& name) {
376  int load_version;
377  unpack(name+"::serialization::version", load_version);
378  return load_version;
379  }
380 
381  int DeserializingStream::version(const std::string& name, int min, int max) {
382  int load_version = version(name);
383  casadi_assert(load_version>=min && load_version<=max,
384  "DeSerialization of " + name + " failed. "
385  "Object written in version " + str(load_version) +
386  " but can only read version " + str(min) + "..." + str(max) + ".");
387  return load_version;
388  }
389 
390  void DeserializingStream::version(const std::string& name, int v) {
391  int load_version = version(name);
392  casadi_assert(load_version==v,
393  "DeSerialization of " + name + " failed. "
394  "Object written in version " + str(load_version) +
395  " but can only read in version " + str(v) + ".");
396  }
397 
398  void SerializingStream::version(const std::string& name, int v) {
399  pack(name+"::serialization::version", v);
400  }
401 
403  node(obj), is_sx(false) {
404  if (node) obj->count++;
405  }
406 
408  node(obj), is_sx(true) {
409  if (node) obj->count++;
410  }
411 
413  node(std::move(rhs.node)), is_sx(std::move(rhs.is_sx)) {
414  rhs.node = nullptr;
415  }
416 
418  std::swap(node, other.node);
419  std::swap(is_sx, other.is_sx);
420  return *this;
421  }
422 
424  if (!node) return;
425  if (is_sx) {
426  if (--static_cast<SXNode*>(node)->count == 0) {
427  delete static_cast<SXNode*>(node);
428  }
429  } else {
430  if (--static_cast<SharedObjectInternal*>(node)->count == 0) {
431  delete static_cast<SharedObjectInternal*>(node);
432  }
433  }
434  }
435 
437  nodes_ = &s.nodes_;
438  }
439 
441  shared_map_ = &s.shared_map_;
442  }
443 
445  shared_map_.clear();
446  }
447 
449  nodes_.clear();
450  }
451 
452 } // 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:61
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.