vsl_binary_io.h
Go to the documentation of this file.
1 // This is core/vsl/vsl_binary_io.h
2 #ifndef vsl_binary_io_h_
3 #define vsl_binary_io_h_
4 //:
5 // \file
6 // \brief Set of functions, and objects to perform binary IO
7 // \author Ian Scott, Tim Cootes (Manchester) March 2001
8 //
9 // You should include this file if you want to do binary_io
10 //
11 // Also included are a set of functions
12 // vsl_print_summary(std::ostream& os, bool b)
13 // for basic types to ensure that templated classes
14 // vsl_print_summaries can work with all types
15 
16 #include <iosfwd>
17 #include <string>
18 #include <fstream>
19 #include <map>
20 #include <utility>
21 #ifdef _MSC_VER
22 # include <vcl_msvc_warnings.h>
23 #endif
24 #include <vxl_config.h>
25 #include <vsl/vsl_export.h>
26 //: A binary output adaptor for any std::ostream
27 // Currently the main use of this is to encourage streams to be opened
28 // in binary mode (ie. without CR/LF conversion)
29 //
30 // This class also provide basic support for serialisation. This allows an
31 // object which has multiple pointers to it to be saved only once. During
32 // reloading, the pointers can be all set up again to point to the single
33 // object. vsl_b_ostream does not do the serialisation itself, but instead
34 // keeps records of unique identifiers to allow the user's code to perform
35 // serialisation safely. For instance, a smart pointer type object will have
36 // to know how to safely save whatever it is pointing to.
38 {
39  public:
40  //: Create this adaptor using an existing stream
41  // The stream (os) must be open (i.e. ready to receive insertions)
42  // so that the
43  // IO version and magic number can be written by this constructor.
44  // User is responsible for deleting os after deleting the adaptor
45  vsl_b_ostream(std::ostream *os);
46 
47  //: A reference to the adaptor's stream
48  std::ostream& os() const;
49 
50  //: Virtual destructor.
51  virtual ~vsl_b_ostream() = default;
52 
53  //: Returns true if the underlying stream has its fail bit set.
54  bool operator!() const;
55 
56  //: Clear the stream's record of any serialisation operations
57  // Calling this function while outputting serialisable things to stream,
58  // will mean that a second copy of an object may get stored to the stream.
59  // Calling this function may be required if you change the state of your program whilst
60  // you are writing to the same vsl_b_ostream. If the program is at any risk of
61  // reallocating the same memory to two different objects controlled by a smart pointer,
62  // then calling this function between writing then will prevent them being confused.
63  virtual void clear_serialisation_records();
64 
65 
66  //: Adds an object pointer to the serialisation records.
67  // Returns a unique identifier for the object.
68  //
69  // \a pointer must be non-null, so you should handle null pointers separately.
70  //
71  // You can optionally add some user-defined integer with each record
72  // If error checking is on, and the object pointer is null or already in the records,
73  // this function will abort()
74  virtual unsigned long add_serialisation_record(void *pointer, int other_data = 0);
75 
76  //: Returns a unique identifier for the object.
77  // Returns 0 if there is no record of the object.
78  virtual unsigned long get_serial_number(void *pointer) const;
79 
80  //: Set the user-defined data associated with the object
81  // If there is no record of the object, this function will return 0.
82  // However a retval of 0 does not necessarily imply that the object is
83  // unrecorded.
84  virtual int get_serialisation_other_data(void *pointer) const;
85 
86  //: Modify the user-defined data associated with the object
87  // If there is no record of the object, this function will abort.
88  virtual int set_serialisation_other_data(void *pointer, int other_data);
89 
90  //: The length of the b_stream header.
91  // You can move to this offset from the start of the file to get to
92  // the first real data item.
93  static constexpr std::streamoff header_length = 6;
94 
95  protected:
96  //: The member stream
97  std::ostream *os_;
98 
99  // Design notes: IMS
100  // I used to think that a pointer and class name were needed to identify an
101  // object. This is true if class your_class{my_class A}; your_class B;
102  // then &B = &(B.A).
103  // However this case doesn't arise in serialisation situations, because you
104  // can't have shared ownership of A.
105 
106  // I could have used the pointer itself as the unique identifier, but it is
107  // unreasonable to expect this to work cross-platform when the platforms have
108  // different pointer sizes.
109 
110  //: The type of the serialisation records
111  typedef std::map<void *, std::pair<unsigned long, int>, std::less<void *> >
113 
114  //: The serialisation records
115  // Records a pointer, a unique identifier, and an integer
116  // (user_defined data.)
118 
119  //: The version number of the IO scheme.
120  static constexpr unsigned short version_no_ = 1;
121 };
122 
123 
124 //: An adapter for a std::ofstream to make it suitable for binary IO
126 {
127  public:
128  //: Create this adaptor from a file.
129  // The adapter will delete the internal stream automatically on destruction.
130  vsl_b_ofstream(const std::string &filename,
131  std::ios::openmode mode = std::ios::out | std::ios::trunc):
132  vsl_b_ostream(new std::ofstream(filename.c_str(), mode | std::ios::binary)) {}
133 
134  //: Create this adaptor from a file.
135  // The adapter will delete the internal stream automatically on destruction.
136  vsl_b_ofstream(const char *filename,
137  std::ios::openmode mode = std::ios::out | std::ios::trunc) :
138  vsl_b_ostream(new std::ofstream(filename, mode | std::ios::binary)) {}
139 
140  //: Virtual destructor.
141  ~vsl_b_ofstream() override;
142 
143 
144  //: Close the stream
145  void close();
146 };
147 
148 
149 
150 
151 //: Test to see if a stream really is a binary vsl file.
152 // \return false if we can't find magic numbers and correct version number.
153 // The file pointer is reset to the beginning on leaving this function.
154 bool vsl_b_istream_test(std::istream &is);
155 
156 //: An adaptor for any std::istream to make it suitable for binary input
157 // Currently the main use of this is to encourage file streams to be opened
158 // in binary mode (ie. without CR/LF conversion)
159 //
160 // This class also provide basic support for serialisation. During loading,
161 // multiple pointers to one object can be all set up again to point to the
162 // single object. vsl_b_ostream does not do the serialisation itself, but
163 // instead keeps records of unique identifiers to allow the user's code to
164 // perform serialisation safely. For instance, a smart pointer type object will
165 // have to know how to safely save whatever it is pointing to.
167 {
168  public:
169  //: Create this adaptor using an existing stream.
170  // The stream (is) must be open (i.e. ready to be read from) so that the
171  // IO version and magic number can be read by this constructor.
172  // User is responsible for deleting is after deleting the adaptor
173  vsl_b_istream(std::istream *is);
174 
175  //: A reference to the adaptor's stream
176  std::istream & is() const;
177 
178  //: Virtual destructor.so that it can be overloaded
179  virtual ~vsl_b_istream() = default;
180 
181  //: Returns true if the underlying stream has its fail bit set.
182  bool operator!() const;
183 
184  //: Clear the stream's record of any serialisation operations
185  // Calling this function while inputting serialisable things from a stream,
186  // could cause errors during loading unless the records were cleared at a
187  // similar point during output.
188  virtual void clear_serialisation_records();
189 
190  //: Adds record of object's unique serial number, and location in memory.
191  // \a pointer must be non-null, so you should handle null pointers separately.
192  //
193  // Adding a null pointer or one that already exists will cause the function to abort(),
194  // if debugging is turned on;
195  //
196  // You can also store a single integer as other data.
197  // Interpretation of this data is entirely up to the client code.
198  virtual void add_serialisation_record(unsigned long serial_number,
199  void *pointer, int other_data = 0);
200 
201  //: Returns the pointer to the object identified by the unique serial number.
202  // Returns 0 if no record has been added.
203  virtual void * get_serialisation_pointer(unsigned long serial_number) const;
204 
205  //: Returns the user defined data associated with the unique serial number
206  // Returns 0 if no record has been added.
207  virtual int get_serialisation_other_data(unsigned long serial_number) const;
208 
209  //: Modify the user-defined data associated with the unique serial number
210  // If there is no record of the object, this function will abort.
211  virtual int set_serialisation_other_data(unsigned long serial_number,
212  int other_data);
213 
214 
215  //: Return the version number of the IO format of the file being read.
216  unsigned short version_no() const;
217 
218  protected:
219  //: The member stream
220  std::istream *is_;
221 
222  //: The type of the serialisation records.
223  typedef std::map<unsigned long, std::pair<void *, int>, std::less<unsigned long> >
225 
226  //: The serialisation records,
227  // The record takes a unique identifier of the object (which would be
228  // stored on the stream) and returns the pointer to the object, and
229  // an other_data integer.
231 
232  // The version number of the IO format of the file being read.
233  unsigned short version_no_;
234 };
235 
236 
237 //: An adapter for a std::ifstream to make it suitable for binary IO
239 {
240  public:
241  //: Create this adaptor from a file.
242  // The adapter will delete the stream automatically on destruction.
243  vsl_b_ifstream(const std::string &filename, std::ios::openmode mode = std::ios::in):
244  vsl_b_istream(new std::ifstream(filename.c_str(),
245  mode | std::ios::binary)) {}
246 
247  //: Create this adaptor from a file.
248  // The adapter will delete the stream automatically on destruction.
249  vsl_b_ifstream(const char *filename, std::ios::openmode mode = std::ios::in):
250  vsl_b_istream(new std::ifstream(filename, mode | std::ios::binary)) {}
251 
252  //: Virtual destructor.so that it can be overloaded
253  ~vsl_b_ifstream() override;
254 
255  //: Close the stream
256  void close();
257 };
258 
259 //: Write bool to vsl_b_ostream
260 void vsl_b_write(vsl_b_ostream& os,bool b);
261 //: Read bool from vsl_b_istream
262 void vsl_b_read(vsl_b_istream& is,bool& b);
263 //: Print to a stream
264 inline void vsl_print_summary(std::ostream& os, bool b )
265 { os << b; }
266 
267 //: Write char to vsl_b_ostream
268 void vsl_b_write(vsl_b_ostream& os,char n );
269 //: Read char from vsl_b_istream
270 void vsl_b_read(vsl_b_istream& is,char& n );
271 //: Print to a stream
272 inline void vsl_print_summary(std::ostream& os, char n )
273 { os << n; }
274 
275 //: Write signed char to vsl_b_ostream
276 void vsl_b_write(vsl_b_ostream& os,signed char n );
277 //: Read signed char from vsl_b_istream
278 void vsl_b_read(vsl_b_istream& is,signed char& n );
279 //: Print to a stream
280 inline void vsl_print_summary(std::ostream& os, signed char n )
281 { os << n; }
282 
283 //: Write to vsl_b_ostream
284 void vsl_b_write(vsl_b_ostream& os,unsigned char n );
285 //: Read from vsl_b_istream
286 void vsl_b_read(vsl_b_istream& is,unsigned char& n );
287 //: Print to a stream
288 inline void vsl_print_summary(std::ostream& os, unsigned char n )
289 { os << n; }
290 
291 //: Write to vsl_b_ostream
292 void vsl_b_write(vsl_b_ostream& os,const std::string& n );
293 //: Read from vsl_b_istream
294 void vsl_b_read(vsl_b_istream& is,std::string& n );
295 //: Print to a stream
296 inline void vsl_print_summary(std::ostream& os, const std::string& n )
297 { os << n; }
298 
299 //: Write to vsl_b_ostream
300 // \deprecated in favour of std::string version.
301 void vsl_b_write(vsl_b_ostream& os,const char* s );
302 //: Read from vsl_b_istream
303 // \deprecated in favour of std::string version.
304 // \note You must preallocate enough space at \p s for expected length of string.
305 // This function is easy to crash mith a malformed data file.
306 void vsl_b_read(vsl_b_istream& is,char* s );
307 //: Print to a stream
308 inline void vsl_print_summary(std::ostream& os, const char* s )
309 { os << s; }
310 
311 
312 // Visual Studio .NET on a 32-bit platform can check for 64-bit
313 // portability issues. When these warnings (/Wp64) are turn on,
314 // passing a ptrdiff_t as an int triggers a warning. The __w64
315 // keyword suppresses that warning here, because it's not a problem.
316 // On a real 64-bit platform, there will presumably be an overloaded
317 // vsl_b_write for the 64-bit integral type. We don't want to suppress
318 // the warning (C4244) completely, because it is a useful warning.
319 // 08/20/2003: Added macro that defines whether or not attribute needs
320 // to be used. A new version of MS .NET compiler required this change.
321 // Add compilers as needed. This could be moved to vcl_compiler.h.
322 // [Nils Krahnstoever]
323 #ifdef _MSC_VER
324 # define VCL_64BIT_ATTR __w64
325 #else
326 # define VCL_64BIT_ATTR /* */
327 #endif
328 
329 //: Write to vsl_b_ostream
330 void vsl_b_write(vsl_b_ostream& os, int VCL_64BIT_ATTR n );
331 //: Read from vsl_b_istream
332 void vsl_b_read(vsl_b_istream& is, int VCL_64BIT_ATTR &n );
333 //: Print to a stream
334 inline void vsl_print_summary(std::ostream& os, int VCL_64BIT_ATTR n )
335 { os << int(n); }
336 
337 #undef VCL_64BIT_ATTR
338 
339 //: Write to vsl_b_ostream
340 void vsl_b_write(vsl_b_ostream& os,unsigned int n );
341 //: Read from vsl_b_istream
342 void vsl_b_read(vsl_b_istream& is,unsigned int& n );
343 //: Print to a stream
344 inline void vsl_print_summary(std::ostream& os, unsigned int n )
345 { os << n; }
346 
347 //: Write to vsl_b_ostream
348 void vsl_b_write(vsl_b_ostream& os,short n );
349 //: Read from vsl_b_istream
350 void vsl_b_read(vsl_b_istream& is,short& n );
351 //: Print to a stream
352 inline void vsl_print_summary(std::ostream& os, short n )
353 { os << n; }
354 
355 //: Write to vsl_b_ostream
356 void vsl_b_write(vsl_b_ostream& os,unsigned short n );
357 //: Read from vsl_b_istream
358 void vsl_b_read(vsl_b_istream& is,unsigned short& n );
359 //: Print to a stream
360 inline void vsl_print_summary(std::ostream& os, unsigned short n )
361 { os << n; }
362 
363 //: Write to vsl_b_ostream
364 void vsl_b_write(vsl_b_ostream& os,long n );
365 //: Read from vsl_b_istream
366 void vsl_b_read(vsl_b_istream& is,long& n );
367 //: Print to a stream
368 inline void vsl_print_summary(std::ostream& os, long n )
369 { os << n; }
370 
371 //: Write to vsl_b_ostream
372 void vsl_b_write(vsl_b_ostream& os,unsigned long n );
373 //: Read from vsl_b_istream
374 void vsl_b_read(vsl_b_istream& is,unsigned long& n );
375 //: Print to a stream
376 inline void vsl_print_summary(std::ostream& os, unsigned long n )
377 { os << n; }
378 
379 #if VXL_HAS_INT_64 && !VXL_INT_64_IS_LONG
380 
381 //: Write to vsl_b_ostream
382 void vsl_b_write(vsl_b_ostream& os,vxl_int_64 n );
383 //: Read from vsl_b_istream
384 void vsl_b_read(vsl_b_istream& is,vxl_int_64& n );
385 //: Print to a stream
386 inline void vsl_print_summary(std::ostream& os, vxl_int_64 n )
387 {
388  os << n;
389 }
390 
391 //: Write to vsl_b_ostream
392 void vsl_b_write(vsl_b_ostream& os,vxl_uint_64 n );
393 //: Read from vsl_b_istream
394 void vsl_b_read(vsl_b_istream& is,vxl_uint_64& n );
395 //: Print to a stream
396 inline void vsl_print_summary(std::ostream& os, vxl_uint_64 n )
397 {
398  os << n;
399 }
400 
401 #endif // VXL_HAS_INT_64
402 
403 //: Write to vsl_b_ostream
404 // Number is saved with ANSI/IEEE Standard 754-1985 single precision.
405 void vsl_b_write(vsl_b_ostream& os,float n );
406 //: Read from vsl_b_istream
407 void vsl_b_read(vsl_b_istream& is,float& n );
408 //: Print to a stream
409 inline void vsl_print_summary(std::ostream& os, float n )
410 { os << n; }
411 
412 //: Write to vsl_b_ostream
413 // Number is saved with ANSI/IEEE Standard 754-1985 double precision.
414 void vsl_b_write(vsl_b_ostream& os,double n );
415 //: Read from vsl_b_istream
416 void vsl_b_read(vsl_b_istream& is,double& n );
417 //: Print to a stream
418 inline void vsl_print_summary(std::ostream& os, double n )
419 { os << n; }
420 
421 
422 #endif // vsl_binary_io_h_
#define VCL_64BIT_ATTR
A binary output adaptor for any std::ostream.
Definition: vsl_binary_io.h:37
An adapter for a std::ifstream to make it suitable for binary IO.
void vsl_b_read(vsl_b_istream &is, bool &b)
Read bool from vsl_b_istream.
virtual int set_serialisation_other_data(void *pointer, int other_data)
Modify the user-defined data associated with the object.
virtual int set_serialisation_other_data(unsigned long serial_number, int other_data)
Modify the user-defined data associated with the unique serial number.
vsl_b_istream(std::istream *is)
Create this adaptor using an existing stream.
~vsl_b_ofstream() override
Virtual destructor.
bool operator!() const
Returns true if the underlying stream has its fail bit set.
unsigned short version_no() const
Return the version number of the IO format of the file being read.
std::ostream * os_
The member stream.
Definition: vsl_binary_io.h:97
virtual void clear_serialisation_records()
Clear the stream's record of any serialisation operations.
virtual int get_serialisation_other_data(void *pointer) const
Set the user-defined data associated with the object.
std::istream & is() const
A reference to the adaptor's stream.
void vsl_print_summary(std::ostream &os, bool b)
Print to a stream.
serialisation_records_type serialisation_records_
The serialisation records,.
bool vsl_b_istream_test(std::istream &is)
Test to see if a stream really is a binary vsl file.
bool operator!() const
Returns true if the underlying stream has its fail bit set.
vsl_b_ofstream(const char *filename, std::ios::openmode mode=std::ios::out|std::ios::trunc)
Create this adaptor from a file.
vsl_b_ifstream(const std::string &filename, std::ios::openmode mode=std::ios::in)
Create this adaptor from a file.
static constexpr unsigned short version_no_
The version number of the IO scheme.
virtual int get_serialisation_other_data(unsigned long serial_number) const
Returns the user defined data associated with the unique serial number.
virtual ~vsl_b_ostream()=default
Virtual destructor.
vsl_b_ofstream(const std::string &filename, std::ios::openmode mode=std::ios::out|std::ios::trunc)
Create this adaptor from a file.
virtual unsigned long get_serial_number(void *pointer) const
Returns a unique identifier for the object.
virtual void * get_serialisation_pointer(unsigned long serial_number) const
Returns the pointer to the object identified by the unique serial number.
void close()
Close the stream.
virtual unsigned long add_serialisation_record(void *pointer, int other_data=0)
Adds an object pointer to the serialisation records.
static constexpr std::streamoff header_length
The length of the b_stream header.
Definition: vsl_binary_io.h:93
~vsl_b_ifstream() override
Virtual destructor.so that it can be overloaded.
std::map< unsigned long, std::pair< void *, int >, std::less< unsigned long > > serialisation_records_type
The type of the serialisation records.
unsigned short version_no_
virtual void add_serialisation_record(unsigned long serial_number, void *pointer, int other_data=0)
Adds record of object's unique serial number, and location in memory.
An adaptor for any std::istream to make it suitable for binary input.
An adapter for a std::ofstream to make it suitable for binary IO.
std::istream * is_
The member stream.
virtual void clear_serialisation_records()
Clear the stream's record of any serialisation operations.
serialisation_records_type serialisation_records_
The serialisation records.
std::ostream & os() const
A reference to the adaptor's stream.
std::map< void *, std::pair< unsigned long, int >, std::less< void * > > serialisation_records_type
The type of the serialisation records.
virtual ~vsl_b_istream()=default
Virtual destructor.so that it can be overloaded.
void close()
Close the stream.
vsl_b_ifstream(const char *filename, std::ios::openmode mode=std::ios::in)
Create this adaptor from a file.
vsl_b_ostream(std::ostream *os)
Create this adaptor using an existing stream.
void vsl_b_write(vsl_b_ostream &os, bool b)
Write bool to vsl_b_ostream.