1 // Copyright (C) 2005  Davis E. King (davis@dlib.net)
2 // License: Boost Software License   See LICENSE.txt for the full license.
3 #ifndef DLIB_SERIALIZe_
4 #define DLIB_SERIALIZe_
5 
6 /*!
7     There are two global functions in the dlib namespace that provide serialization and
8     deserialization support.  Their signatures and specifications are as follows:
9 
10         void serialize (
11             const serializable_type& item,
12             std::ostream& out
13         );
14         /!*
15             ensures
16                 - writes the state of item to the output stream out
17                 - if (serializable_type implements the enumerable interface) then
18                     - item.at_start() == true
19             throws
20                 - serialization_error
21                     This exception is thrown if there is some problem which prevents
22                     us from successfully writing item to the output stream.
23                 - any other exception
24         *!/
25 
26         void deserialize (
27             serializable_type& item,
28             std::istream& in
29         );
30         /!*
31             ensures
32                 - #item == a deserialized copy of the serializable_type that was
33                   in the input stream in.
34                 - Reads all the bytes associated with the serialized serializable_type
35                   contained inside the input stream and no more.  This means you
36                   can serialize multiple objects to an output stream and then read
37                   them all back in, one after another, using deserialize().
38                 - if (serializable_type implements the enumerable interface) then
39                     - item.at_start() == true
40             throws
41                 - serialization_error
42                     This exception is thrown if there is some problem which prevents
43                     us from successfully deserializing item from the input stream.
44                     If this exception is thrown then item will have an initial value
45                     for its type.
46                 - any other exception
47         *!/
48 
49     For convenience, you can also serialize to a file using this syntax:
50         serialize("your_file.dat") << some_object << another_object;
51 
52         // or to a memory buffer.
53         std::vector<char> memory_buffer;
54         serialize(memory_buffer) << some_object << another_object;
55 
56         // or some other stream
57         std::ostringstream memory_buffer2;
58         serialize(memory_buffer2) << some_object << another_object;
59 
60     That overwrites the contents of your_file.dat with the serialized data from some_object
61     and another_object.  Then to recall the objects from the file you can do:
62         deserialize("your_file.dat") >> some_object >> another_object;
63         // or from a memory buffer or another stream called memory_buffer.
64         deserialize(memory_buffer) >> some_object >> another_object;
65 
66     Finally, you can chain as many objects together using the << and >> operators as you
67     like.
68 
69 
70     This file provides serialization support to the following object types:
71         - The C++ base types (NOT including raw pointer)
72         - std::string
73         - std::wstring
74         - std::vector
75         - std::list
76         - std::forward_list
77         - std::array
78         - std::deque
79         - std::map
80         - std::unordered_map
81         - std::multimap
82         - std::unordered_multimap
83         - std::set
84         - std::unordered_set
85         - std::multiset
86         - std::unordered_multiset
87         - std::pair
88         - std::tuple
89         - std::complex
90         - std::unique_ptr
91         - std::shared_ptr
92         - dlib::uint64
93         - dlib::int64
94         - float_details
95         - enumerable<T> where T is a serializable type
96         - map_pair<D,R> where D and R are both serializable types.
97         - C style arrays of serializable types
98         - Google protocol buffer objects.
99 
100     This file provides deserialization support to the following object types:
101         - The C++ base types (NOT including raw pointers)
102         - std::string
103         - std::wstring
104         - std::vector
105         - std::list
106         - std::forward_list
107         - std::array
108         - std::deque
109         - std::map
110         - std::unordered_map
111         - std::multimap
112         - std::unordered_multimap
113         - std::set
114         - std::unordered_set
115         - std::multiset
116         - std::unordered_multiset
117         - std::pair
118         - std::tuple
119         - std::complex
120         - std::unique_ptr
121         - std::shared_ptr
122         - dlib::uint64
123         - dlib::int64
124         - float_details
125         - C style arrays of serializable types
126         - Google protocol buffer objects.
127 
128     Support for deserialization of objects which implement the enumerable or
129     map_pair interfaces is the responsibility of those objects.
130 
131     Note that you can deserialize an integer value to any integral type (except for a
132     char type) if its value will fit into the target integer type.  I.e.  the types
133     short, int, long, unsigned short, unsigned int, unsigned long, and dlib::uint64
134     can all receive serialized data from each other so long as the actual serialized
135     value fits within the receiving integral type's range.
136 
137     Also note that for any container to be serializable the type of object it contains
138     must be serializable.
139 
140     FILE STREAMS
141         If you are serializing to and from file streams it is important to
142         remember to set the file streams to binary mode using the std::ios::binary
143         flag.
144 
145 
146     INTEGRAL SERIALIZATION FORMAT
147         All C++ integral types (except the char types) are serialized to the following
148         format:
149         The first byte is a control byte.  It tells you if the serialized number is
150         positive or negative and also tells you how many of the following bytes are
151         part of the number.  The absolute value of the number is stored in little
152         endian byte order and follows the control byte.
153 
154         The control byte:
155             The high order bit of the control byte is a flag that tells you if the
156             encoded number is negative or not.  It is set to 1 when the number is
157             negative and 0 otherwise.
158             The 4 low order bits of the control byte represent an unsigned number
159             and tells you how many of the following bytes are part of the encoded
160             number.
161 
162     bool SERIALIZATION FORMAT
163         A bool value is serialized as the single byte character '1' or '0' in ASCII.
164         Where '1' indicates true and '0' indicates false.
165 
166     FLOATING POINT SERIALIZATION FORMAT
167         To serialize a floating point value we convert it into a float_details object and
168         then serialize the exponent and mantissa values using dlib's integral serialization
169         format.  Therefore, the output is first the exponent and then the mantissa.  Note that
170         the mantissa is a signed integer (i.e. there is not a separate sign bit).
171 
172 
173     MAKING YOUR OWN CUSTOM OBJECTS SERIALIZABLE
174         Suppose you create your own type, my_custom_type, and you want it to be serializable.  I.e.
175         you want to be able to use the tools above to save and load it.  E.g. maybe you have a
176         std::vector<my_custom_type> you wish to save.
177 
178         To make my_custom_type properly serializable all you have to do is define global serialize
179         and deserialize functions **IN THE SAME NAMESPACE AS MY_CUSTOM_TYPE**.  You must define them
180         in your namespace so that argument dependent lookup will be able to find them.  So your code
181         might look like this:
182 
183             namespace your_namespace
184             {
185                 struct my_custom_type
186                 {
187                     int a;
188                     float b;
189                     std::vector<float> c;
190                 };
191                 void serialize (const my_custom_type& item, std::ostream& out);
192                 void deserialize (my_custom_type& item, std::istream& in);
193             }
194 
195         That's all you need to do.  You may optionally avail yourself of the
196         DLIB_DEFINE_DEFAULT_SERIALIZATION macro, which generates global friend serialize and
197         deserialize functions for you.  In that case you would do this instead:
198 
199             namespace your_namespace
200             {
201                 struct my_custom_type
202                 {
203                     int a;
204                     float b;
205                     std::vector<float> c;
206 
207                     DLIB_DEFINE_DEFAULT_SERIALIZATION(my_custom_type, a, b, c);
208                 };
209             }
210 
211 !*/
212 
213 
214 #include "algs.h"
215 #include "assert.h"
216 #include <iomanip>
217 #include <cstddef>
218 #include <iostream>
219 #include <fstream>
220 #include <string>
221 #include <vector>
222 #include <list>
223 #include <forward_list>
224 #include <array>
225 #include <deque>
226 #include <complex>
227 #include <map>
228 #include <unordered_map>
229 #include <tuple>
230 #include <memory>
231 #include <set>
232 #include <unordered_set>
233 #include <limits>
234 #include <type_traits>
235 #include <utility>
236 #include "uintn.h"
237 #include "interfaces/enumerable.h"
238 #include "interfaces/map_pair.h"
239 #include "enable_if.h"
240 #include "unicode.h"
241 #include "byte_orderer.h"
242 #include "float_details.h"
243 #include "vectorstream.h"
244 
245 namespace dlib
246 {
247 
248 // ----------------------------------------------------------------------------------------
249 
250     class serialization_error : public error
251     {
252         /*!
253             WHAT THIS OBJECT REPRESENTS
254                 This is the exception object.  It is thrown if serialization or
255                 deserialization fails.
256         !*/
257 
258     public:
serialization_error(const std::string & e)259         serialization_error(const std::string& e):error(e) {}
260     };
261 
262 
263     void check_serialized_version(
264         const std::string& expected_version,
265         std::istream& in
266     );
267     /*!
268         ensures
269             - Deserializes a string from in and if it doesn't match expected_version we
270               throw serialization_error.
271     !*/
272 
273 // ----------------------------------------------------------------------------------------
274 
275     /*!A ramdump information !*/
276     template <typename T>
277     struct ramdump_t
278     {
279         /*!
280             WHAT THIS OBJECT REPRESENTS
281                 This is a type decoration used to indicate that serialization should be
282                 done by simply dumping the memory of some object to disk as fast as
283                 possible without any sort of conversions.  This means that the data written
284                 will be "non-portable" in the sense that the format output by a RAM dump
285                 may depend on things like the endianness of your CPU or settings of certain
286                 compiler switches.
287 
288                 You use this object like this:
289                    serialize("yourfile.dat") << ramdump(yourobject);
290                    deserialize("yourfile.dat") >> ramdump(yourobject);
291                 or
292                    serialize(ramdump(yourobject), out);
293                    deserialize(ramdump(yourobject), in);
294 
295                 Also, not all objects have a ramdump mode.  If you try to use ramdump on an
296                 object that does not define a serialization dump for ramdump you will get a
297                 compiler error.
298         !*/
ramdump_tramdump_t299         ramdump_t(T& item_) : item(item_) {}
300         T& item;
301     };
302 
303     // This function just makes a ramdump that wraps an object.
304     template <typename T>
ramdump(T && item)305     ramdump_t<typename std::remove_reference<T>::type> ramdump(T&& item)
306     {
307         return ramdump_t<typename std::remove_reference<T>::type>(item);
308     }
309 
310 
311     template <
312         typename T
313         >
serialize(const ramdump_t<const T> & item_,std::ostream & out)314     void serialize (
315         const ramdump_t<const T>& item_,
316         std::ostream& out
317     )
318     {
319         // Move the const from inside the ramdump_t template to outside so we can bind
320         // against a serialize() call that takes just a const ramdump_t<T>.  Doing this
321         // saves you from needing to write multiple overloads of serialize() to handle
322         // these different const placement cases.
323         const auto temp = ramdump(const_cast<T&>(item_.item));
324         serialize(temp, out);
325     }
326 
327 // ----------------------------------------------------------------------------------------
328 
329     namespace ser_helper
330     {
331 
332         template <
333             typename T
334             >
pack_int(T item,std::ostream & out)335         typename enable_if_c<std::numeric_limits<T>::is_signed,bool>::type pack_int (
336             T item,
337             std::ostream& out
338         )
339         /*!
340             requires
341                 - T is a signed integral type
342             ensures
343                 - if (no problems occur serializing item) then
344                     - writes item to out
345                     - returns false
346                 - else
347                     - returns true
348         !*/
349         {
350             COMPILE_TIME_ASSERT(sizeof(T) <= 8);
351             unsigned char buf[9];
352             unsigned char size = sizeof(T);
353             unsigned char neg;
354             if (item < 0)
355             {
356                 neg = 0x80;
357                 item *= -1;
358             }
359             else
360             {
361                 neg = 0;
362             }
363 
364             for (unsigned char i = 1; i <= sizeof(T); ++i)
365             {
366                 buf[i] = static_cast<unsigned char>(item&0xFF);
367                 item >>= 8;
368                 if (item == 0) { size = i; break; }
369             }
370 
371             std::streambuf* sbuf = out.rdbuf();
372             buf[0] = size|neg;
373             if (sbuf->sputn(reinterpret_cast<char*>(buf),size+1) != size+1)
374             {
375                 out.setstate(std::ios::eofbit | std::ios::badbit);
376                 return true;
377             }
378 
379             return false;
380         }
381 
382     // ------------------------------------------------------------------------------------
383 
384         template <
385             typename T
386             >
unpack_int(T & item,std::istream & in)387         typename enable_if_c<std::numeric_limits<T>::is_signed,bool>::type unpack_int (
388             T& item,
389             std::istream& in
390         )
391         /*!
392             requires
393                 - T is a signed integral type
394             ensures
395                 - if (there are no problems deserializing item) then
396                     - returns false
397                     - #item == the value stored in in
398                 - else
399                     - returns true
400 
401         !*/
402         {
403             COMPILE_TIME_ASSERT(sizeof(T) <= 8);
404 
405 
406             unsigned char buf[8];
407             unsigned char size;
408             bool is_negative;
409 
410             std::streambuf* sbuf = in.rdbuf();
411 
412             item = 0;
413             int ch = sbuf->sbumpc();
414             if (ch != EOF)
415             {
416                 size = static_cast<unsigned char>(ch);
417             }
418             else
419             {
420                 in.setstate(std::ios::badbit);
421                 return true;
422             }
423 
424             if (size&0x80)
425                 is_negative = true;
426             else
427                 is_negative = false;
428             size &= 0x0F;
429 
430             // check if the serialized object is too big
431             if (size > (unsigned long)tmin<sizeof(T),8>::value || size == 0)
432             {
433                 return true;
434             }
435 
436             if (sbuf->sgetn(reinterpret_cast<char*>(&buf),size) != size)
437             {
438                 in.setstate(std::ios::badbit);
439                 return true;
440             }
441 
442 
443             for (unsigned char i = size-1; true; --i)
444             {
445                 item <<= 8;
446                 item |= buf[i];
447                 if (i == 0)
448                     break;
449             }
450 
451             if (is_negative)
452                 item *= -1;
453 
454 
455             return false;
456         }
457 
458     // ------------------------------------------------------------------------------------
459 
460         template <
461             typename T
462             >
pack_int(T item,std::ostream & out)463         typename disable_if_c<std::numeric_limits<T>::is_signed,bool>::type pack_int (
464             T item,
465             std::ostream& out
466         )
467         /*!
468             requires
469                 - T is an unsigned integral type
470             ensures
471                 - if (no problems occur serializing item) then
472                     - writes item to out
473                     - returns false
474                 - else
475                     - returns true
476         !*/
477         {
478             COMPILE_TIME_ASSERT(sizeof(T) <= 8);
479             unsigned char buf[9];
480             unsigned char size = sizeof(T);
481 
482             for (unsigned char i = 1; i <= sizeof(T); ++i)
483             {
484                 buf[i] = static_cast<unsigned char>(item&0xFF);
485                 item >>= 8;
486                 if (item == 0) { size = i; break; }
487             }
488 
489             std::streambuf* sbuf = out.rdbuf();
490             buf[0] = size;
491             if (sbuf->sputn(reinterpret_cast<char*>(buf),size+1) != size+1)
492             {
493                 out.setstate(std::ios::eofbit | std::ios::badbit);
494                 return true;
495             }
496 
497             return false;
498         }
499 
500     // ------------------------------------------------------------------------------------
501 
502         template <
503             typename T
504             >
unpack_int(T & item,std::istream & in)505         typename disable_if_c<std::numeric_limits<T>::is_signed,bool>::type unpack_int (
506             T& item,
507             std::istream& in
508         )
509         /*!
510             requires
511                 - T is an unsigned integral type
512             ensures
513                 - if (there are no problems deserializing item) then
514                     - returns false
515                     - #item == the value stored in in
516                 - else
517                     - returns true
518 
519         !*/
520         {
521             COMPILE_TIME_ASSERT(sizeof(T) <= 8);
522 
523             unsigned char buf[8];
524             unsigned char size;
525 
526             item = 0;
527 
528             std::streambuf* sbuf = in.rdbuf();
529             int ch = sbuf->sbumpc();
530             if (ch != EOF)
531             {
532                 size = static_cast<unsigned char>(ch);
533             }
534             else
535             {
536                 in.setstate(std::ios::badbit);
537                 return true;
538             }
539 
540 
541             // mask out the 3 reserved bits
542             size &= 0x8F;
543 
544             // check if an error occurred
545             if (size > (unsigned long)tmin<sizeof(T),8>::value || size == 0)
546                 return true;
547 
548 
549             if (sbuf->sgetn(reinterpret_cast<char*>(&buf),size) != size)
550             {
551                 in.setstate(std::ios::badbit);
552                 return true;
553             }
554 
555             for (unsigned char i = size-1; true; --i)
556             {
557                 item <<= 8;
558                 item |= buf[i];
559                 if (i == 0)
560                     break;
561             }
562 
563             return false;
564         }
565 
566     }
567 
568 // ----------------------------------------------------------------------------------------
569 
570     #define USE_DEFAULT_INT_SERIALIZATION_FOR(T)  \
571         inline void serialize (const T& item, std::ostream& out) \
572         { if (ser_helper::pack_int(item,out)) throw serialization_error("Error serializing object of type " + std::string(#T)); }   \
573         inline void deserialize (T& item, std::istream& in) \
574         { if (ser_helper::unpack_int(item,in)) throw serialization_error("Error deserializing object of type " + std::string(#T)); }
575 
576     template <typename T>
pack_byte(const T & ch,std::ostream & out)577     inline bool pack_byte (
578         const T& ch,
579         std::ostream& out
580     )
581     {
582         std::streambuf* sbuf = out.rdbuf();
583         return (sbuf->sputc((char)ch) == EOF);
584     }
585 
586     template <typename T>
unpack_byte(T & ch,std::istream & in)587     inline bool unpack_byte (
588         T& ch,
589         std::istream& in
590     )
591     {
592         std::streambuf* sbuf = in.rdbuf();
593         int temp = sbuf->sbumpc();
594         if (temp != EOF)
595         {
596             ch = static_cast<T>(temp);
597             return false;
598         }
599         else
600         {
601             return true;
602         }
603     }
604 
605     #define USE_DEFAULT_BYTE_SERIALIZATION_FOR(T)  \
606         inline void serialize (const T& item,std::ostream& out) \
607         { if (pack_byte(item,out)) throw serialization_error("Error serializing object of type " + std::string(#T)); } \
608         inline void deserialize (T& item, std::istream& in) \
609         { if (unpack_byte(item,in)) throw serialization_error("Error deserializing object of type " + std::string(#T)); }
610 
611 // ----------------------------------------------------------------------------------------
612 
613     USE_DEFAULT_INT_SERIALIZATION_FOR(short)
USE_DEFAULT_INT_SERIALIZATION_FOR(int)614     USE_DEFAULT_INT_SERIALIZATION_FOR(int)
615     USE_DEFAULT_INT_SERIALIZATION_FOR(long)
616     USE_DEFAULT_INT_SERIALIZATION_FOR(unsigned short)
617     USE_DEFAULT_INT_SERIALIZATION_FOR(unsigned int)
618     USE_DEFAULT_INT_SERIALIZATION_FOR(unsigned long)
619     USE_DEFAULT_INT_SERIALIZATION_FOR(uint64)
620     USE_DEFAULT_INT_SERIALIZATION_FOR(int64)
621 
622     USE_DEFAULT_BYTE_SERIALIZATION_FOR(char)
623     USE_DEFAULT_BYTE_SERIALIZATION_FOR(signed char)
624     USE_DEFAULT_BYTE_SERIALIZATION_FOR(unsigned char)
625 
626     // Don't define serialization for wchar_t when using visual studio and
627     // _NATIVE_WCHAR_T_DEFINED isn't defined since if it isn't they improperly set
628     // wchar_t to be a typedef rather than its own type as required by the C++
629     // standard.
630 #if !defined(_MSC_VER) || _NATIVE_WCHAR_T_DEFINED
631     USE_DEFAULT_INT_SERIALIZATION_FOR(wchar_t)
632 #endif
633 
634 // ----------------------------------------------------------------------------------------
635 
636     inline void serialize(
637         const float_details& item,
638         std::ostream& out
639     )
640     {
641         serialize(item.mantissa, out);
642         serialize(item.exponent, out);
643     }
644 
deserialize(float_details & item,std::istream & in)645     inline void deserialize(
646         float_details& item,
647         std::istream& in
648     )
649     {
650         deserialize(item.mantissa, in);
651         deserialize(item.exponent, in);
652     }
653 
654 // ----------------------------------------------------------------------------------------
655 
656     template <typename T>
serialize_floating_point(const T & item,std::ostream & out)657     inline void serialize_floating_point (
658         const T& item,
659         std::ostream& out
660     )
661     {
662         try
663         {
664             float_details temp = item;
665             serialize(temp, out);
666         }
667         catch (serialization_error& e)
668         { throw serialization_error(e.info + "\n   while serializing a floating point number."); }
669     }
670 
671     template <typename T>
old_deserialize_floating_point(T & item,std::istream & in)672     inline bool old_deserialize_floating_point (
673         T& item,
674         std::istream& in
675     )
676     {
677         std::ios::fmtflags oldflags = in.flags();
678         in.flags(static_cast<std::ios_base::fmtflags>(0));
679         std::streamsize ss = in.precision(35);
680         if (in.peek() == 'i')
681         {
682             item = std::numeric_limits<T>::infinity();
683             in.get();
684             in.get();
685             in.get();
686         }
687         else if (in.peek() == 'n')
688         {
689             item = -std::numeric_limits<T>::infinity();
690             in.get();
691             in.get();
692             in.get();
693             in.get();
694         }
695         else if (in.peek() == 'N')
696         {
697             item = std::numeric_limits<T>::quiet_NaN();
698             in.get();
699             in.get();
700             in.get();
701         }
702         else
703         {
704             in >> item;
705         }
706         in.flags(oldflags);
707         in.precision(ss);
708         return (in.get() != ' ');
709     }
710 
711     template <typename T>
deserialize_floating_point(T & item,std::istream & in)712     inline void deserialize_floating_point (
713         T& item,
714         std::istream& in
715     )
716     {
717         // check if the serialized data uses the older ASCII based format.  We can check
718         // this easily because the new format starts with the integer control byte which
719         // always has 0 bits in the positions corresponding to the bitmask 0x70.  Moreover,
720         // since the previous format used ASCII numbers we know that no valid bytes can
721         // have bit values of one in the positions indicated 0x70.  So this test looks at
722         // the first byte and checks if the serialized data uses the old format or the new
723         // format.
724         if ((in.rdbuf()->sgetc()&0x70) == 0)
725         {
726             try
727             {
728                 // Use the fast and compact binary serialization format.
729                 float_details temp;
730                 deserialize(temp, in);
731                 item = temp;
732             }
733             catch (serialization_error& e)
734             { throw serialization_error(e.info + "\n   while deserializing a floating point number."); }
735         }
736         else
737         {
738             if (old_deserialize_floating_point(item, in))
739                 throw serialization_error("Error deserializing a floating point number.");
740         }
741     }
742 
serialize(const float & item,std::ostream & out)743     inline void serialize ( const float& item, std::ostream& out)
744     {
745         serialize_floating_point(item,out);
746     }
747 
deserialize(float & item,std::istream & in)748     inline void deserialize (float& item, std::istream& in)
749     {
750         deserialize_floating_point(item,in);
751     }
752 
serialize(const double & item,std::ostream & out)753     inline void serialize ( const double& item, std::ostream& out)
754     {
755         serialize_floating_point(item,out);
756     }
757 
deserialize(double & item,std::istream & in)758     inline void deserialize (double& item, std::istream& in)
759     {
760         deserialize_floating_point(item,in);
761     }
762 
serialize(const long double & item,std::ostream & out)763     inline void serialize ( const long double& item, std::ostream& out)
764     {
765         serialize_floating_point(item,out);
766     }
767 
deserialize(long double & item,std::istream & in)768     inline void deserialize ( long double& item, std::istream& in)
769     {
770         deserialize_floating_point(item,in);
771     }
772 
773 // ----------------------------------------------------------------------------------------
774 
775     template <
776         typename T
777         >
serialize(const std::complex<T> & item,std::ostream & out)778     inline void serialize (
779         const std::complex<T>& item,
780         std::ostream& out
781     )
782     {
783         try
784         {
785             serialize(item.real(),out);
786             serialize(item.imag(),out);
787         }
788         catch (serialization_error& e)
789         {
790             throw serialization_error(e.info + "\n   while serializing an object of type std::complex");
791         }
792     }
793 
794 // ----------------------------------------------------------------------------------------
795 
796     template <
797         typename T
798         >
deserialize(std::complex<T> & item,std::istream & in)799     inline void deserialize (
800         std::complex<T>& item,
801         std::istream& in
802     )
803     {
804         try
805         {
806             T real, imag;
807             deserialize(real,in);
808             deserialize(imag,in);
809             item = std::complex<T>(real,imag);
810         }
811         catch (serialization_error& e)
812         {
813             throw serialization_error(e.info + "\n   while deserializing an object of type std::complex");
814         }
815     }
816 
817 // ----------------------------------------------------------------------------------------
818 // prototypes
819 
820     template <typename domain, typename range, typename compare, typename alloc>
821     void serialize (
822         const std::map<domain,range, compare, alloc>& item,
823         std::ostream& out
824     );
825 
826     template <typename domain, typename range, typename compare, typename alloc>
827     void deserialize (
828         std::map<domain, range, compare, alloc>& item,
829         std::istream& in
830     );
831 
832     template <typename domain, typename range, typename hash, typename keyEqual, typename alloc>
833     void serialize (
834         const std::unordered_map<domain, range, hash, keyEqual, alloc>& item,
835         std::ostream& out
836     );
837 
838     template <typename domain, typename range, typename hash, typename keyEqual, typename alloc>
839     void deserialize (
840         std::unordered_map<domain, range, hash, keyEqual, alloc>& item,
841         std::istream& in
842     );
843 
844     template <typename domain, typename range, typename compare, typename alloc>
845     void serialize (
846         const std::multimap<domain,range, compare, alloc>& item,
847         std::ostream& out
848     );
849 
850     template <typename domain, typename range, typename compare, typename alloc>
851     void deserialize (
852         std::multimap<domain, range, compare, alloc>& item,
853         std::istream& in
854     );
855 
856     template <typename domain, typename range, typename hash, typename keyEqual, typename alloc>
857     void serialize (
858         const std::unordered_multimap<domain, range, hash, keyEqual, alloc>& item,
859         std::ostream& out
860     );
861 
862     template <typename domain, typename range, typename hash, typename keyEqual, typename alloc>
863     void deserialize (
864         std::unordered_multimap<domain, range, hash, keyEqual, alloc>& item,
865         std::istream& in
866     );
867 
868     template <typename domain, typename compare, typename alloc>
869     void serialize (
870         const std::set<domain, compare, alloc>& item,
871         std::ostream& out
872     );
873 
874     template <typename domain, typename compare, typename alloc>
875     void deserialize (
876         std::set<domain, compare, alloc>& item,
877         std::istream& in
878     );
879 
880     template <typename domain, typename hash, typename keyEqual, typename alloc>
881     void serialize (
882         const std::unordered_set<domain, hash, keyEqual, alloc>& item,
883         std::ostream& out
884     );
885 
886     template <typename domain, typename hash, typename keyEqual, typename alloc>
887     void deserialize (
888         std::unordered_set<domain, hash, keyEqual, alloc>& item,
889         std::istream& in
890     );
891 
892     template <typename domain, typename compare, typename alloc>
893     void serialize (
894         const std::multiset<domain, compare, alloc>& item,
895         std::ostream& out
896     );
897 
898     template <typename domain, typename compare, typename alloc>
899     void deserialize (
900         std::multiset<domain, compare, alloc>& item,
901         std::istream& in
902     );
903 
904     template <typename domain, typename hash, typename keyEqual, typename alloc>
905     void serialize (
906         const std::unordered_multiset<domain, hash, keyEqual, alloc>& item,
907         std::ostream& out
908     );
909 
910     template <typename domain, typename hash, typename keyEqual, typename alloc>
911     void deserialize (
912         std::unordered_multiset<domain, hash, keyEqual, alloc>& item,
913         std::istream& in
914     );
915 
916     template <typename T, typename alloc>
917     void serialize (
918         const std::vector<T,alloc>& item,
919         std::ostream& out
920     );
921 
922     template <typename T, typename alloc>
923     void deserialize (
924         std::vector<T,alloc>& item,
925         std::istream& in
926     );
927 
928     template <typename T, typename alloc>
929     void serialize (
930         const std::list<T,alloc>& item,
931         std::ostream& out
932     );
933 
934     template <typename T, typename alloc>
935     void deserialize (
936         std::list<T,alloc>& item,
937         std::istream& in
938     );
939 
940     template <typename T, typename alloc>
941     void serialize (
942         const std::forward_list<T,alloc>& item,
943         std::ostream& out
944     );
945 
946     template <typename T, typename alloc>
947     void deserialize (
948         std::forward_list<T,alloc>& item,
949         std::istream& in
950     );
951 
952     template <typename T, typename alloc>
953     void serialize (
954         const std::deque<T,alloc>& item,
955         std::ostream& out
956     );
957 
958     template <typename T, typename alloc>
959     void deserialize (
960         std::deque<T,alloc>& item,
961         std::istream& in
962     );
963 
964     template <typename... Types>
965     void serialize (
966         const std::tuple<Types...>& item,
967         std::ostream& out
968     );
969 
970     template <typename... Types>
971     void deserialize (
972         std::tuple<Types...>& item,
973         std::istream& in
974     );
975 
976     template <typename T, typename deleter>
977     void serialize (
978         const std::unique_ptr<T, deleter>& item,
979         std::ostream& out
980     );
981 
982     template <typename T, typename deleter>
983     void deserialize (
984         std::unique_ptr<T, deleter>& item,
985         std::istream& in
986     );
987 
988     template <typename T>
989     void serialize (
990         const std::shared_ptr<T>& item,
991         std::ostream& out
992     );
993 
994     template <typename T>
995     void deserialize (
996         std::shared_ptr<T>& item,
997         std::istream& in
998     );
999 
1000     inline void serialize (
1001         const std::string& item,
1002         std::ostream& out
1003     );
1004 
1005     inline void deserialize (
1006         std::string& item,
1007         std::istream& in
1008     );
1009 
1010     inline void serialize (
1011         const std::wstring& item,
1012         std::ostream& out
1013     );
1014 
1015     inline void deserialize (
1016         std::wstring& item,
1017         std::istream& in
1018     );
1019 
1020     inline void serialize (
1021         const ustring& item,
1022         std::ostream& out
1023     );
1024 
1025     inline void deserialize (
1026         ustring& item,
1027         std::istream& in
1028     );
1029 
1030     template <
1031         typename T
1032         >
1033     inline void serialize (
1034         const enumerable<T>& item,
1035         std::ostream& out
1036     );
1037 
1038     template <
1039         typename domain,
1040         typename range
1041         >
1042     inline void serialize (
1043         const map_pair<domain,range>& item,
1044         std::ostream& out
1045     );
1046 
1047     template <
1048         typename T,
1049         size_t length
1050         >
1051     inline void serialize (
1052         const T (&array)[length],
1053         std::ostream& out
1054     );
1055 
1056     template <
1057         typename T,
1058         size_t length
1059         >
1060     inline void deserialize (
1061         T (&array)[length],
1062         std::istream& in
1063     );
1064 
1065 // ----------------------------------------------------------------------------------------
1066 // ----------------------------------------------------------------------------------------
1067 // ----------------------------------------------------------------------------------------
1068 // ----------------------------------------------------------------------------------------
1069 
serialize(bool item,std::ostream & out)1070     inline void serialize (
1071         bool item,
1072         std::ostream& out
1073     )
1074     {
1075         if (item)
1076             out << '1';
1077         else
1078             out << '0';
1079 
1080         if (!out)
1081             throw serialization_error("Error serializing object of type bool");
1082     }
1083 
deserialize(bool & item,std::istream & in)1084     inline void deserialize (
1085         bool& item,
1086         std::istream& in
1087     )
1088     {
1089         int ch = in.get();
1090         if (ch != EOF)
1091         {
1092             if (ch == '1')
1093                 item = true;
1094             else if (ch == '0')
1095                 item = false;
1096             else
1097                 throw serialization_error("Error deserializing object of type bool");
1098         }
1099         else
1100         {
1101             throw serialization_error("Error deserializing object of type bool");
1102         }
1103     }
1104 
1105 // ----------------------------------------------------------------------------------------
1106 
1107     template <typename first_type, typename second_type>
serialize(const std::pair<first_type,second_type> & item,std::ostream & out)1108     void serialize (
1109         const std::pair<first_type, second_type>& item,
1110         std::ostream& out
1111     )
1112     {
1113         try
1114         {
1115             serialize(item.first,out);
1116             serialize(item.second,out);
1117         }
1118         catch (serialization_error& e)
1119         { throw serialization_error(e.info + "\n   while serializing object of type std::pair"); }
1120     }
1121 
1122     template <typename first_type, typename second_type>
deserialize(std::pair<first_type,second_type> & item,std::istream & in)1123     void deserialize (
1124         std::pair<first_type, second_type>& item,
1125         std::istream& in
1126     )
1127     {
1128         try
1129         {
1130             deserialize(item.first,in);
1131             deserialize(item.second,in);
1132         }
1133         catch (serialization_error& e)
1134         { throw serialization_error(e.info + "\n   while deserializing object of type std::pair"); }
1135     }
1136 
1137 // ----------------------------------------------------------------------------------------
1138 
1139     template<std::size_t I = 0, typename FuncT, typename... Tp>
1140     inline typename std::enable_if<I == sizeof...(Tp), void>::type
for_each_in_tuple(std::tuple<Tp...> &,FuncT)1141     for_each_in_tuple(std::tuple<Tp...>&, FuncT)
1142     {}
1143 
1144     template<std::size_t I = 0, typename FuncT, typename... Tp>
1145     inline typename std::enable_if<I < sizeof...(Tp), void>::type
1146     for_each_in_tuple(std::tuple<Tp...>& t, FuncT f)
1147     {
1148         f(std::get<I>(t));
1149         for_each_in_tuple<I + 1, FuncT, Tp...>(t, f);
1150     }
1151 
1152     template<std::size_t I = 0, typename FuncT, typename... Tp>
1153     inline typename std::enable_if<I == sizeof...(Tp), void>::type
for_each_in_tuple(const std::tuple<Tp...> &,FuncT)1154     for_each_in_tuple(const std::tuple<Tp...>&, FuncT)
1155     {}
1156 
1157     template<std::size_t I = 0, typename FuncT, typename... Tp>
1158     inline typename std::enable_if<I < sizeof...(Tp), void>::type
1159     for_each_in_tuple(const std::tuple<Tp...>& t, FuncT f)
1160     {
1161         f(std::get<I>(t));
1162         for_each_in_tuple<I + 1, FuncT, Tp...>(t, f);
1163     }
1164 
1165     struct serialize_tuple_helper
1166     {
serialize_tuple_helperserialize_tuple_helper1167         serialize_tuple_helper(std::ostream& out_) : out(out_) {}
1168 
1169         template<typename T>
operatorserialize_tuple_helper1170         void operator()(const T& item)
1171         {
1172             serialize(item, out);
1173         }
1174 
1175         std::ostream& out;
1176     };
1177 
1178     struct deserialize_tuple_helper
1179     {
deserialize_tuple_helperdeserialize_tuple_helper1180         deserialize_tuple_helper(std::istream& in_) : in(in_) {}
1181 
1182         template<typename T>
operatordeserialize_tuple_helper1183         void operator()(T& item)
1184         {
1185             deserialize(item, in);
1186         }
1187 
1188         std::istream& in;
1189     };
1190 
1191     template <typename... Types>
serialize(const std::tuple<Types...> & item,std::ostream & out)1192     void serialize (
1193         const std::tuple<Types...>& item,
1194         std::ostream& out
1195     )
1196     {
1197         try
1198         {
1199             for_each_in_tuple(item, serialize_tuple_helper(out));
1200         }
1201         catch (serialization_error& e)
1202         { throw serialization_error(e.info + "\n   while serializing object of type std::tuple"); }
1203     }
1204 
1205     template <typename... Types>
deserialize(std::tuple<Types...> & item,std::istream & in)1206     void deserialize (
1207         std::tuple<Types...>& item,
1208         std::istream& in
1209     )
1210     {
1211         try
1212         {
1213             for_each_in_tuple(item, deserialize_tuple_helper(in));
1214         }
1215         catch (serialization_error& e)
1216         { throw serialization_error(e.info + "\n   while deserializing object of type std::tuple"); }
1217     }
1218 
1219 // ----------------------------------------------------------------------------------------
1220 
1221     template <typename domain, typename range, typename compare, typename alloc>
serialize(const std::map<domain,range,compare,alloc> & item,std::ostream & out)1222     void serialize (
1223         const std::map<domain,range, compare, alloc>& item,
1224         std::ostream& out
1225     )
1226     {
1227         try
1228         {
1229             const unsigned long size = static_cast<unsigned long>(item.size());
1230 
1231             serialize(size,out);
1232             typename std::map<domain,range,compare,alloc>::const_iterator i;
1233             for (i = item.begin(); i != item.end(); ++i)
1234             {
1235                 serialize(i->first,out);
1236                 serialize(i->second,out);
1237             }
1238 
1239         }
1240         catch (serialization_error& e)
1241         { throw serialization_error(e.info + "\n   while serializing object of type std::map"); }
1242     }
1243 
1244     template <typename domain, typename range, typename compare, typename alloc>
deserialize(std::map<domain,range,compare,alloc> & item,std::istream & in)1245     void deserialize (
1246         std::map<domain, range, compare, alloc>& item,
1247         std::istream& in
1248     )
1249     {
1250         try
1251         {
1252             item.clear();
1253 
1254             unsigned long size;
1255             deserialize(size,in);
1256             domain d;
1257             range r;
1258             for (unsigned long i = 0; i < size; ++i)
1259             {
1260                 deserialize(d,in);
1261                 deserialize(r,in);
1262                 item[d] = r;
1263             }
1264         }
1265         catch (serialization_error& e)
1266         { throw serialization_error(e.info + "\n   while deserializing object of type std::map"); }
1267     }
1268 
1269 // ----------------------------------------------------------------------------------------
1270 
1271     template <typename domain, typename range, typename hash, typename keyEqual, typename alloc>
serialize(const std::unordered_map<domain,range,hash,keyEqual,alloc> & item,std::ostream & out)1272     void serialize (
1273         const std::unordered_map<domain, range, hash, keyEqual, alloc>& item,
1274         std::ostream& out
1275     )
1276     {
1277         try
1278         {
1279             serialize(item.size(),out);
1280             for (const auto& x : item)
1281             {
1282                 serialize(x.first,out);
1283                 serialize(x.second,out);
1284             }
1285         }
1286         catch (serialization_error& e)
1287         { throw serialization_error(e.info + "\n   while serializing object of type std::unordered_map"); }
1288     }
1289 
1290     template <typename domain, typename range, typename hash, typename keyEqual, typename alloc>
deserialize(std::unordered_map<domain,range,hash,keyEqual,alloc> & item,std::istream & in)1291     void deserialize (
1292         std::unordered_map<domain, range, hash, keyEqual, alloc>& item,
1293         std::istream& in
1294     )
1295     {
1296         try
1297         {
1298             item.clear();
1299             std::size_t size;
1300             deserialize(size,in);
1301             domain d;
1302             range r;
1303             for (unsigned long i = 0; i < size; ++i)
1304             {
1305                 deserialize(d,in);
1306                 deserialize(r,in);
1307                 item[d] = r;
1308             }
1309         }
1310         catch (serialization_error& e)
1311         { throw serialization_error(e.info + "\n   while deserializing object of type std::unordered_map"); }
1312     }
1313 
1314 // ----------------------------------------------------------------------------------------
1315 
1316     template <typename domain, typename range, typename compare, typename alloc>
serialize(const std::multimap<domain,range,compare,alloc> & item,std::ostream & out)1317     void serialize (
1318         const std::multimap<domain,range, compare, alloc>& item,
1319         std::ostream& out
1320     )
1321     {
1322         try
1323         {
1324             serialize(item.size(),out);
1325             for (const auto& x : item)
1326             {
1327                 serialize(x.first,out);
1328                 serialize(x.second,out);
1329             }
1330         }
1331         catch (serialization_error& e)
1332         { throw serialization_error(e.info + "\n   while serializing object of type std::multimap"); }
1333     }
1334 
1335     template <typename domain, typename range, typename compare, typename alloc>
deserialize(std::multimap<domain,range,compare,alloc> & item,std::istream & in)1336     void deserialize (
1337         std::multimap<domain, range, compare, alloc>& item,
1338         std::istream& in
1339     )
1340     {
1341         try
1342         {
1343             item.clear();
1344             std::size_t size;
1345             deserialize(size,in);
1346             domain d;
1347             range r;
1348             for (unsigned long i = 0; i < size; ++i)
1349             {
1350                 deserialize(d,in);
1351                 deserialize(r,in);
1352                 item.insert({d,r});
1353             }
1354         }
1355         catch (serialization_error& e)
1356         { throw serialization_error(e.info + "\n   while deserializing object of type std::multimap"); }
1357     }
1358 
1359 // ----------------------------------------------------------------------------------------
1360 
1361     template <typename domain, typename range, typename hash, typename keyEqual, typename alloc>
serialize(const std::unordered_multimap<domain,range,hash,keyEqual,alloc> & item,std::ostream & out)1362     void serialize (
1363         const std::unordered_multimap<domain, range, hash, keyEqual, alloc>& item,
1364         std::ostream& out
1365     )
1366     {
1367         try
1368         {
1369             serialize(item.size(),out);
1370             for (const auto& x : item)
1371             {
1372                 serialize(x.first,out);
1373                 serialize(x.second,out);
1374             }
1375         }
1376         catch (serialization_error& e)
1377         { throw serialization_error(e.info + "\n   while serializing object of type std::unordered_multimap"); }
1378     }
1379 
1380     template <typename domain, typename range, typename hash, typename keyEqual, typename alloc>
deserialize(std::unordered_multimap<domain,range,hash,keyEqual,alloc> & item,std::istream & in)1381     void deserialize (
1382         std::unordered_multimap<domain, range, hash, keyEqual, alloc>& item,
1383         std::istream& in
1384     )
1385     {
1386         try
1387         {
1388             item.clear();
1389             std::size_t size;
1390             deserialize(size,in);
1391             domain d;
1392             range r;
1393             for (unsigned long i = 0; i < size; ++i)
1394             {
1395                 deserialize(d,in);
1396                 deserialize(r,in);
1397                 item.insert({d,r});
1398             }
1399         }
1400         catch (serialization_error& e)
1401         { throw serialization_error(e.info + "\n   while deserializing object of type std::unordered_multimap"); }
1402     }
1403 
1404 // ----------------------------------------------------------------------------------------
1405 
1406     template <typename domain, typename compare, typename alloc>
serialize(const std::set<domain,compare,alloc> & item,std::ostream & out)1407     void serialize (
1408         const std::set<domain, compare, alloc>& item,
1409         std::ostream& out
1410     )
1411     {
1412         try
1413         {
1414             const unsigned long size = static_cast<unsigned long>(item.size());
1415 
1416             serialize(size,out);
1417             typename std::set<domain,compare,alloc>::const_iterator i;
1418             for (i = item.begin(); i != item.end(); ++i)
1419             {
1420                 serialize(*i,out);
1421             }
1422 
1423         }
1424         catch (serialization_error& e)
1425         { throw serialization_error(e.info + "\n   while serializing object of type std::set"); }
1426     }
1427 
1428     template <typename domain, typename compare, typename alloc>
deserialize(std::set<domain,compare,alloc> & item,std::istream & in)1429     void deserialize (
1430         std::set<domain, compare, alloc>& item,
1431         std::istream& in
1432     )
1433     {
1434         try
1435         {
1436             item.clear();
1437 
1438             unsigned long size;
1439             deserialize(size,in);
1440             domain d;
1441             for (unsigned long i = 0; i < size; ++i)
1442             {
1443                 deserialize(d,in);
1444                 item.insert(d);
1445             }
1446         }
1447         catch (serialization_error& e)
1448         { throw serialization_error(e.info + "\n   while deserializing object of type std::set"); }
1449     }
1450 
1451 // ----------------------------------------------------------------------------------------
1452 
1453     template <typename domain, typename hash, typename keyEqual, typename alloc>
serialize(const std::unordered_set<domain,hash,keyEqual,alloc> & item,std::ostream & out)1454     void serialize (
1455         const std::unordered_set<domain, hash, keyEqual, alloc>& item,
1456         std::ostream& out
1457     )
1458     {
1459         try
1460         {
1461             serialize(item.size(),out);
1462             for (const auto& x : item)
1463                 serialize(x,out);
1464         }
1465         catch (serialization_error& e)
1466         { throw serialization_error(e.info + "\n   while serializing object of type std::unordered_set"); }
1467     }
1468 
1469     template <typename domain, typename hash, typename keyEqual, typename alloc>
deserialize(std::unordered_set<domain,hash,keyEqual,alloc> & item,std::istream & in)1470     void deserialize (
1471         std::unordered_set<domain, hash, keyEqual, alloc>& item,
1472         std::istream& in
1473     )
1474     {
1475         try
1476         {
1477             item.clear();
1478             std::size_t size;
1479             deserialize(size,in);
1480             domain d;
1481             for (unsigned long i = 0; i < size; ++i)
1482             {
1483                 deserialize(d,in);
1484                 item.insert(d);
1485             }
1486         }
1487         catch (serialization_error& e)
1488         { throw serialization_error(e.info + "\n   while deserializing object of type std::unordered_set"); }
1489     }
1490 
1491 // ----------------------------------------------------------------------------------------
1492 
1493     template <typename domain, typename compare, typename alloc>
serialize(const std::multiset<domain,compare,alloc> & item,std::ostream & out)1494     void serialize (
1495         const std::multiset<domain, compare, alloc>& item,
1496         std::ostream& out
1497     )
1498     {
1499         try
1500         {
1501             serialize(item.size(),out);
1502             for (const auto& x : item)
1503                 serialize(x,out);
1504         }
1505         catch (serialization_error& e)
1506         { throw serialization_error(e.info + "\n   while serializing object of type std::multiset"); }
1507     }
1508 
1509     template <typename domain, typename compare, typename alloc>
deserialize(std::multiset<domain,compare,alloc> & item,std::istream & in)1510     void deserialize (
1511         std::multiset<domain, compare, alloc>& item,
1512         std::istream& in
1513     )
1514     {
1515         try
1516         {
1517             item.clear();
1518             std::size_t size;
1519             deserialize(size,in);
1520             domain d;
1521             for (unsigned long i = 0; i < size; ++i)
1522             {
1523                 deserialize(d,in);
1524                 item.insert(d);
1525             }
1526         }
1527         catch (serialization_error& e)
1528         { throw serialization_error(e.info + "\n   while deserializing object of type std::multiset"); }
1529     }
1530 
1531 // ----------------------------------------------------------------------------------------
1532 
1533     template <typename domain, typename hash, typename keyEqual, typename alloc>
serialize(const std::unordered_multiset<domain,hash,keyEqual,alloc> & item,std::ostream & out)1534     void serialize (
1535         const std::unordered_multiset<domain, hash, keyEqual, alloc>& item,
1536         std::ostream& out
1537     )
1538     {
1539         try
1540         {
1541             serialize(item.size(),out);
1542             for (const auto& x : item)
1543                 serialize(x,out);
1544         }
1545         catch (serialization_error& e)
1546         { throw serialization_error(e.info + "\n   while serializing object of type std::unordered_multiset"); }
1547     }
1548 
1549     template <typename domain, typename hash, typename keyEqual, typename alloc>
deserialize(std::unordered_multiset<domain,hash,keyEqual,alloc> & item,std::istream & in)1550     void deserialize (
1551         std::unordered_multiset<domain, hash, keyEqual, alloc>& item,
1552         std::istream& in
1553     )
1554     {
1555         try
1556         {
1557             item.clear();
1558             std::size_t size;
1559             deserialize(size,in);
1560             domain d;
1561             for (unsigned long i = 0; i < size; ++i)
1562             {
1563                 deserialize(d,in);
1564                 item.insert(d);
1565             }
1566         }
1567         catch (serialization_error& e)
1568         { throw serialization_error(e.info + "\n   while deserializing object of type std::unordered_multiset"); }
1569     }
1570 
1571 // ----------------------------------------------------------------------------------------
1572 
1573     template <typename alloc>
serialize(const std::vector<bool,alloc> & item,std::ostream & out)1574     void serialize (
1575         const std::vector<bool,alloc>& item,
1576         std::ostream& out
1577     )
1578     {
1579         std::vector<unsigned char> temp(item.size());
1580         for (unsigned long i = 0; i < item.size(); ++i)
1581         {
1582             if (item[i])
1583                 temp[i] = '1';
1584             else
1585                 temp[i] = '0';
1586         }
1587         serialize(temp, out);
1588     }
1589 
1590     template <typename alloc>
deserialize(std::vector<bool,alloc> & item,std::istream & in)1591     void deserialize (
1592         std::vector<bool,alloc>& item,
1593         std::istream& in
1594     )
1595     {
1596         std::vector<unsigned char> temp;
1597         deserialize(temp, in);
1598         item.resize(temp.size());
1599         for (unsigned long i = 0; i < temp.size(); ++i)
1600         {
1601             if (temp[i] == '1')
1602                 item[i] = true;
1603             else
1604                 item[i] = false;
1605         }
1606     }
1607 
1608 // ----------------------------------------------------------------------------------------
1609 
1610     template <typename T, typename alloc>
serialize(const std::vector<T,alloc> & item,std::ostream & out)1611     void serialize (
1612         const std::vector<T,alloc>& item,
1613         std::ostream& out
1614     )
1615     {
1616         try
1617         {
1618             const unsigned long size = static_cast<unsigned long>(item.size());
1619 
1620             serialize(size,out);
1621             for (unsigned long i = 0; i < item.size(); ++i)
1622                 serialize(item[i],out);
1623         }
1624         catch (serialization_error& e)
1625         { throw serialization_error(e.info + "\n   while serializing object of type std::vector"); }
1626     }
1627 
1628     template <typename T, typename alloc>
deserialize(std::vector<T,alloc> & item,std::istream & in)1629     void deserialize (
1630         std::vector<T, alloc>& item,
1631         std::istream& in
1632     )
1633     {
1634         try
1635         {
1636             unsigned long size;
1637             deserialize(size,in);
1638             item.resize(size);
1639             for (unsigned long i = 0; i < size; ++i)
1640                 deserialize(item[i],in);
1641         }
1642         catch (serialization_error& e)
1643         { throw serialization_error(e.info + "\n   while deserializing object of type std::vector"); }
1644     }
1645 
1646 // ----------------------------------------------------------------------------------------
1647 
1648     template <typename alloc>
serialize(const std::vector<char,alloc> & item,std::ostream & out)1649     void serialize (
1650         const std::vector<char,alloc>& item,
1651         std::ostream& out
1652     )
1653     {
1654         try
1655         {
1656             const unsigned long size = static_cast<unsigned long>(item.size());
1657             serialize(size,out);
1658             if (item.size() != 0)
1659                 out.write(&item[0], item.size());
1660         }
1661         catch (serialization_error& e)
1662         { throw serialization_error(e.info + "\n   while serializing object of type std::vector"); }
1663     }
1664 
1665     template <typename alloc>
deserialize(std::vector<char,alloc> & item,std::istream & in)1666     void deserialize (
1667         std::vector<char, alloc>& item,
1668         std::istream& in
1669     )
1670     {
1671         try
1672         {
1673             unsigned long size;
1674             deserialize(size,in);
1675             item.resize(size);
1676             if (item.size() != 0)
1677                 in.read(&item[0], item.size());
1678         }
1679         catch (serialization_error& e)
1680         { throw serialization_error(e.info + "\n   while deserializing object of type std::vector"); }
1681     }
1682 
1683 // ----------------------------------------------------------------------------------------
1684 
1685     template <typename alloc>
serialize(const std::vector<unsigned char,alloc> & item,std::ostream & out)1686     void serialize (
1687         const std::vector<unsigned char,alloc>& item,
1688         std::ostream& out
1689     )
1690     {
1691         try
1692         {
1693             const unsigned long size = static_cast<unsigned long>(item.size());
1694             serialize(size,out);
1695             if (item.size() != 0)
1696                 out.write((char*)&item[0], item.size());
1697         }
1698         catch (serialization_error& e)
1699         { throw serialization_error(e.info + "\n   while serializing object of type std::vector"); }
1700     }
1701 
1702     template <typename alloc>
deserialize(std::vector<unsigned char,alloc> & item,std::istream & in)1703     void deserialize (
1704         std::vector<unsigned char, alloc>& item,
1705         std::istream& in
1706     )
1707     {
1708         try
1709         {
1710             unsigned long size;
1711             deserialize(size,in);
1712             item.resize(size);
1713             if (item.size() != 0)
1714                 in.read((char*)&item[0], item.size());
1715         }
1716         catch (serialization_error& e)
1717         { throw serialization_error(e.info + "\n   while deserializing object of type std::vector"); }
1718     }
1719 
1720 // ----------------------------------------------------------------------------------------
1721 
1722     template <typename T, typename alloc>
serialize(const std::list<T,alloc> & item,std::ostream & out)1723     void serialize (
1724         const std::list<T,alloc>& item,
1725         std::ostream& out
1726     )
1727     {
1728         try
1729         {
1730             const unsigned long size = static_cast<unsigned long>(item.size());
1731             serialize(size,out);
1732             for (const auto& x : item)
1733                 serialize(x, out);
1734         }
1735         catch (serialization_error& e)
1736         { throw serialization_error(e.info + "\n   while serializing object of type std::list"); }
1737     }
1738 
1739     template <typename T, typename alloc>
deserialize(std::list<T,alloc> & item,std::istream & in)1740     void deserialize (
1741         std::list<T,alloc>& item,
1742         std::istream& in
1743     )
1744     {
1745         try
1746         {
1747             unsigned long size;
1748             deserialize(size, in);
1749             item.resize(size);
1750             for (auto& x : item)
1751                 deserialize(x, in);
1752         }
1753         catch (serialization_error& e)
1754         { throw serialization_error(e.info + "\n   while deserializing object of type std::list"); }
1755     }
1756 
1757 // ----------------------------------------------------------------------------------------
1758 
1759     template <typename T, typename alloc>
serialize(const std::forward_list<T,alloc> & item,std::ostream & out)1760     void serialize (
1761         const std::forward_list<T,alloc>& item,
1762         std::ostream& out
1763     )
1764     {
1765         try
1766         {
1767             const unsigned long size = std::distance(item.begin(), item.end());
1768             serialize(size,out);
1769             for (const auto& x : item)
1770                 serialize(x, out);
1771         }
1772         catch (serialization_error& e)
1773         { throw serialization_error(e.info + "\n   while serializing object of type std::forward_list"); }
1774     }
1775 
1776     template <typename T, typename alloc>
deserialize(std::forward_list<T,alloc> & item,std::istream & in)1777     void deserialize (
1778         std::forward_list<T,alloc>& item,
1779         std::istream& in
1780     )
1781     {
1782         try
1783         {
1784             unsigned long size;
1785             deserialize(size,in);
1786             item.resize(size);
1787             for (auto& x : item)
1788                 deserialize(x,in);
1789         }
1790         catch (serialization_error& e)
1791         { throw serialization_error(e.info + "\n   while deserializing object of type std::forward_list"); }
1792     }
1793 
1794 // ----------------------------------------------------------------------------------------
1795 
1796     template <typename T, typename alloc>
serialize(const std::deque<T,alloc> & item,std::ostream & out)1797     void serialize (
1798         const std::deque<T,alloc>& item,
1799         std::ostream& out
1800     )
1801     {
1802         try
1803         {
1804             const unsigned long size = static_cast<unsigned long>(item.size());
1805 
1806             serialize(size,out);
1807             for (unsigned long i = 0; i < item.size(); ++i)
1808                 serialize(item[i],out);
1809         }
1810         catch (serialization_error& e)
1811         { throw serialization_error(e.info + "\n   while serializing object of type std::deque"); }
1812     }
1813 
1814     template <typename T, typename alloc>
deserialize(std::deque<T,alloc> & item,std::istream & in)1815     void deserialize (
1816         std::deque<T, alloc>& item,
1817         std::istream& in
1818     )
1819     {
1820         try
1821         {
1822             unsigned long size;
1823             deserialize(size,in);
1824             item.resize(size);
1825             for (unsigned long i = 0; i < size; ++i)
1826                 deserialize(item[i],in);
1827         }
1828         catch (serialization_error& e)
1829         { throw serialization_error(e.info + "\n   while deserializing object of type std::deque"); }
1830     }
1831 
1832 // ----------------------------------------------------------------------------------------
1833 
serialize(const std::string & item,std::ostream & out)1834     inline void serialize (
1835         const std::string& item,
1836         std::ostream& out
1837     )
1838     {
1839         const unsigned long size = static_cast<unsigned long>(item.size());
1840         try{ serialize(size,out); }
1841         catch (serialization_error& e)
1842         { throw serialization_error(e.info + "\n   while serializing object of type std::string"); }
1843 
1844         out.write(item.c_str(),size);
1845         if (!out) throw serialization_error("Error serializing object of type std::string");
1846     }
1847 
deserialize(std::string & item,std::istream & in)1848     inline void deserialize (
1849         std::string& item,
1850         std::istream& in
1851     )
1852     {
1853         unsigned long size;
1854         try { deserialize(size,in); }
1855         catch (serialization_error& e)
1856         { throw serialization_error(e.info + "\n   while deserializing object of type std::string"); }
1857 
1858         item.resize(size);
1859         if (size != 0)
1860         {
1861             in.read(&item[0],size);
1862             if (!in) throw serialization_error("Error deserializing object of type std::string");
1863         }
1864     }
1865 
1866 // ----------------------------------------------------------------------------------------
1867 
serialize(const std::wstring & item,std::ostream & out)1868     inline void serialize (
1869         const std::wstring& item,
1870         std::ostream& out
1871     )
1872     {
1873         const unsigned long size = static_cast<unsigned long>(item.size());
1874         try{ serialize(size,out); }
1875         catch (serialization_error& e)
1876         { throw serialization_error(e.info + "\n   while serializing object of type std::wstring"); }
1877 
1878         for (unsigned long i = 0; i < item.size(); ++i)
1879             serialize(item[i], out);
1880         if (!out) throw serialization_error("Error serializing object of type std::wstring");
1881     }
1882 
deserialize(std::wstring & item,std::istream & in)1883     inline void deserialize (
1884         std::wstring& item,
1885         std::istream& in
1886     )
1887     {
1888         unsigned long size;
1889         try { deserialize(size,in); }
1890         catch (serialization_error& e)
1891         { throw serialization_error(e.info + "\n   while deserializing object of type std::wstring"); }
1892 
1893         item.resize(size);
1894         for (unsigned long i = 0; i < item.size(); ++i)
1895             deserialize(item[i],in);
1896 
1897         if (!in) throw serialization_error("Error deserializing object of type std::wstring");
1898     }
1899 
1900 // ----------------------------------------------------------------------------------------
1901 
serialize(const ustring & item,std::ostream & out)1902     inline void serialize (
1903         const ustring& item,
1904         std::ostream& out
1905     )
1906     {
1907         const unsigned long size = static_cast<unsigned long>(item.size());
1908         try{ serialize(size,out); }
1909         catch (serialization_error& e)
1910         { throw serialization_error(e.info + "\n   while serializing object of type ustring"); }
1911 
1912         for (unsigned long i = 0; i < item.size(); ++i)
1913             serialize(item[i], out);
1914         if (!out) throw serialization_error("Error serializing object of type ustring");
1915     }
1916 
deserialize(ustring & item,std::istream & in)1917     inline void deserialize (
1918         ustring& item,
1919         std::istream& in
1920     )
1921     {
1922         unsigned long size;
1923         try { deserialize(size,in); }
1924         catch (serialization_error& e)
1925         { throw serialization_error(e.info + "\n   while deserializing object of type ustring"); }
1926 
1927         item.resize(size);
1928         for (unsigned long i = 0; i < item.size(); ++i)
1929             deserialize(item[i],in);
1930 
1931         if (!in) throw serialization_error("Error deserializing object of type ustring");
1932     }
1933 
1934 // ----------------------------------------------------------------------------------------
1935 
1936     template <
1937         typename T
1938         >
serialize(const enumerable<T> & item,std::ostream & out)1939     inline void serialize (
1940         const enumerable<T>& item,
1941         std::ostream& out
1942     )
1943     {
1944         try
1945         {
1946             item.reset();
1947             serialize(item.size(),out);
1948             while (item.move_next())
1949                 serialize(item.element(),out);
1950             item.reset();
1951         }
1952         catch (serialization_error& e)
1953         {
1954             throw serialization_error(e.info + "\n   while serializing object of type enumerable");
1955         }
1956     }
1957 
1958 // ----------------------------------------------------------------------------------------
1959 
1960     template <
1961         typename domain,
1962         typename range
1963         >
serialize(const map_pair<domain,range> & item,std::ostream & out)1964     inline void serialize (
1965         const map_pair<domain,range>& item,
1966         std::ostream& out
1967     )
1968     {
1969         try
1970         {
1971             serialize(item.key(),out);
1972             serialize(item.value(),out);
1973         }
1974         catch (serialization_error& e)
1975         {
1976             throw serialization_error(e.info + "\n   while serializing object of type map_pair");
1977         }
1978     }
1979 
1980 // ----------------------------------------------------------------------------------------
1981 
1982     template <
1983         typename T,
1984         size_t length
1985         >
serialize(const T (& array)[length],std::ostream & out)1986     inline void serialize (
1987         const T (&array)[length],
1988         std::ostream& out
1989     )
1990     {
1991         try
1992         {
1993             serialize(length,out);
1994             for (size_t i = 0; i < length; ++i)
1995                 serialize(array[i],out);
1996         }
1997         catch (serialization_error& e)
1998         {
1999             throw serialization_error(e.info + "\n   while serializing a C style array");
2000         }
2001     }
2002 
2003     template <
2004         size_t length
2005         >
serialize(const char (& array)[length],std::ostream & out)2006     inline void serialize (
2007         const char (&array)[length],
2008         std::ostream& out
2009     )
2010     {
2011         if (length != 0 && array[length-1] == '\0')
2012         {
2013             // If this is a null terminated string then don't serialize the trailing null.
2014             // We do this so that the serialization format for C-strings is the same as
2015             // std::string.
2016             serialize(length-1, out);
2017             out.write(array, length-1);
2018             if (!out)
2019                 throw serialization_error("Error serializing a C-style string");
2020         }
2021         else
2022         {
2023             try
2024             {
2025                 serialize(length,out);
2026             }
2027             catch (serialization_error& e)
2028             {
2029                 throw serialization_error(e.info + "\n   while serializing a C style array");
2030             }
2031             if (length != 0)
2032                 out.write(array, length);
2033             if (!out)
2034                 throw serialization_error("Error serializing a C-style string");
2035         }
2036     }
2037 
2038 // ----------------------------------------------------------------------------------------
2039 
2040     template <
2041         typename T,
2042         size_t length
2043         >
deserialize(T (& array)[length],std::istream & in)2044     inline void deserialize (
2045         T (&array)[length],
2046         std::istream& in
2047     )
2048     {
2049         size_t size;
2050         try
2051         {
2052             deserialize(size,in);
2053             if (size == length)
2054             {
2055                 for (size_t i = 0; i < length; ++i)
2056                     deserialize(array[i],in);
2057             }
2058         }
2059         catch (serialization_error& e)
2060         {
2061             throw serialization_error(e.info + "\n   while deserializing a C style array");
2062         }
2063 
2064         if (size != length)
2065             throw serialization_error("Error deserializing a C style array, lengths do not match");
2066     }
2067 
2068     template <
2069         size_t length
2070         >
deserialize(char (& array)[length],std::istream & in)2071     inline void deserialize (
2072         char (&array)[length],
2073         std::istream& in
2074     )
2075     {
2076         size_t size;
2077         try
2078         {
2079             deserialize(size,in);
2080         }
2081         catch (serialization_error& e)
2082         {
2083             throw serialization_error(e.info + "\n   while deserializing a C style array");
2084         }
2085 
2086         if (size == length)
2087         {
2088             in.read(array, size);
2089             if (!in)
2090                 throw serialization_error("Error deserializing a C-style array");
2091         }
2092         else if (size+1 == length)
2093         {
2094             // In this case we are deserializing a C-style array so we need to add the null
2095             // terminator.
2096             in.read(array, size);
2097             array[size] = '\0';
2098             if (!in)
2099                 throw serialization_error("Error deserializing a C-style string");
2100         }
2101         else
2102         {
2103             throw serialization_error("Error deserializing a C style array, lengths do not match");
2104         }
2105     }
2106 
2107 // ----------------------------------------------------------------------------------------
2108 
2109     template <
2110         typename T,
2111         size_t N
2112         >
serialize(const std::array<T,N> & array,std::ostream & out)2113     inline void serialize (
2114         const std::array<T,N>& array,
2115         std::ostream& out
2116     )
2117     {
2118         typedef T c_array_type[N];
2119         serialize(*(const c_array_type*)array.data(), out);
2120     }
2121 
2122     template <
2123         typename T,
2124         size_t N
2125         >
deserialize(std::array<T,N> & array,std::istream & in)2126     inline void deserialize (
2127         std::array<T,N>& array,
2128         std::istream& in
2129     )
2130     {
2131         typedef T c_array_type[N];
2132         deserialize(*(c_array_type*)array.data(), in);
2133     }
2134 
2135     template <
2136         typename T
2137         >
serialize(const std::array<T,0> &,std::ostream & out)2138     inline void serialize (
2139         const std::array<T,0>& /*array*/,
2140         std::ostream& out
2141     )
2142     {
2143         size_t N = 0;
2144         serialize(N, out);
2145     }
2146 
2147     template <
2148         typename T
2149         >
deserialize(std::array<T,0> &,std::istream & in)2150     inline void deserialize (
2151         std::array<T,0>& /*array*/,
2152         std::istream& in
2153     )
2154     {
2155         size_t N;
2156         deserialize(N, in);
2157         if (N != 0)
2158         {
2159             std::ostringstream sout;
2160             sout << "Expected std::array of size 0 but found a size of " << N;
2161             throw serialization_error(sout.str());
2162         }
2163     }
2164 
2165 // ----------------------------------------------------------------------------------------
2166 
2167     template <typename T, typename deleter>
serialize(const std::unique_ptr<T,deleter> & item,std::ostream & out)2168     void serialize (
2169         const std::unique_ptr<T, deleter>& item,
2170         std::ostream& out
2171     )
2172     {
2173         try
2174         {
2175             bool is_non_empty = item != nullptr;
2176             serialize(is_non_empty, out);
2177             if (is_non_empty)
2178                 serialize(*item, out);
2179         }
2180         catch (serialization_error& e)
2181         {
2182             throw serialization_error(e.info + "\n   while serializing an object of type std::unique_ptr");
2183         }
2184     }
2185 
2186     template <typename T, typename deleter>
deserialize(std::unique_ptr<T,deleter> & item,std::istream & in)2187     void deserialize (
2188         std::unique_ptr<T, deleter>& item,
2189         std::istream& in
2190     )
2191     {
2192         try
2193         {
2194             //when deserializing unique_ptr, this is fresh state, so reset the pointers, even if item is non-empty
2195             bool is_non_empty;
2196             deserialize(is_non_empty, in);
2197             item.reset(is_non_empty ? new T() : nullptr); //can't use make_unique since dlib does not use C++14 as a minimum requirement.
2198 
2199             if (is_non_empty)
2200                 deserialize(*item, in);
2201         }
2202         catch (serialization_error& e)
2203         {
2204             throw serialization_error(e.info + "\n   while deserializing an object of type std::unique_ptr");
2205         }
2206     }
2207 
2208 // ----------------------------------------------------------------------------------------
2209 
2210     template <typename T>
serialize(const std::shared_ptr<T> & item,std::ostream & out)2211     void serialize (
2212         const std::shared_ptr<T>& item,
2213         std::ostream& out
2214     )
2215     {
2216         try
2217         {
2218             bool is_non_empty = item != nullptr;
2219             serialize(is_non_empty, out);
2220             if (is_non_empty)
2221                 serialize(*item, out);
2222         }
2223         catch (serialization_error& e)
2224         {
2225             throw serialization_error(e.info + "\n   while serializing an object of type std::shared_ptr");
2226         }
2227     }
2228 
2229     template <typename T>
deserialize(std::shared_ptr<T> & item,std::istream & in)2230     void deserialize (
2231         std::shared_ptr<T>& item,
2232         std::istream& in
2233     )
2234     {
2235         try
2236         {
2237             //when deserializing shared_ptr, this is fresh state, so reset the pointers, even if item is non-empty
2238             bool is_non_empty;
2239             deserialize(is_non_empty, in);
2240             item = is_non_empty ? std::make_shared<T>() : nullptr;
2241 
2242             if (is_non_empty)
2243                 deserialize(*item, in);
2244         }
2245         catch (serialization_error& e)
2246         {
2247             throw serialization_error(e.info + "\n   while deserializing an object of type std::shared_ptr");
2248         }
2249     }
2250 
2251 // ----------------------------------------------------------------------------------------
2252 
2253     class proxy_serialize
2254     {
2255     public:
proxy_serialize(const std::string & filename)2256         explicit proxy_serialize (
2257             const std::string& filename
2258         ) : fout_optional_owning_ptr(new std::ofstream(filename.c_str(), std::ios::binary)),
2259             fout(*fout_optional_owning_ptr)
2260         {
2261             if (!fout)
2262                 throw serialization_error("Unable to open " + filename + " for writing.");
2263         }
2264 
proxy_serialize(std::vector<char> & buf)2265         explicit proxy_serialize (
2266             std::vector<char>& buf
2267         ) : fout_optional_owning_ptr(new vectorstream(buf)),
2268             fout(*fout_optional_owning_ptr)
2269         {
2270         }
2271 
proxy_serialize(std::vector<int8_t> & buf)2272         explicit proxy_serialize (
2273             std::vector<int8_t>& buf
2274         ) : fout_optional_owning_ptr(new vectorstream(buf)),
2275             fout(*fout_optional_owning_ptr)
2276         {
2277         }
2278 
proxy_serialize(std::vector<uint8_t> & buf)2279         explicit proxy_serialize (
2280             std::vector<uint8_t>& buf
2281         ) : fout_optional_owning_ptr(new vectorstream(buf)),
2282             fout(*fout_optional_owning_ptr)
2283         {
2284         }
2285 
proxy_serialize(std::ostream & ss)2286         explicit proxy_serialize (
2287             std::ostream& ss
2288         ) : fout_optional_owning_ptr(nullptr),
2289             fout(ss)
2290         {}
2291 
2292         template <typename T>
2293         inline proxy_serialize& operator<<(const T& item)
2294         {
2295             serialize(item, fout);
2296             return *this;
2297         }
2298 
2299     private:
2300         std::unique_ptr<std::ostream> fout_optional_owning_ptr;
2301         std::ostream& fout;
2302     };
2303 
2304     class proxy_deserialize
2305     {
2306     public:
proxy_deserialize(const std::string & filename_)2307         explicit proxy_deserialize (
2308             const std::string& filename_
2309         )  : filename(filename_),
2310              fin_optional_owning_ptr(new std::ifstream(filename.c_str(), std::ios::binary)),
2311              fin(*fin_optional_owning_ptr)
2312         {
2313             if (!fin)
2314                 throw serialization_error("Unable to open " + filename + " for reading.");
2315             init();
2316         }
2317 
proxy_deserialize(std::vector<char> & buf)2318         explicit proxy_deserialize (
2319             std::vector<char>& buf
2320         ) : fin_optional_owning_ptr(new vectorstream(buf)),
2321             fin(*fin_optional_owning_ptr)
2322         {
2323             init();
2324         }
2325 
proxy_deserialize(std::vector<int8_t> & buf)2326         explicit proxy_deserialize (
2327             std::vector<int8_t>& buf
2328         ) : fin_optional_owning_ptr(new vectorstream(buf)),
2329             fin(*fin_optional_owning_ptr)
2330         {
2331             init();
2332         }
2333 
proxy_deserialize(std::vector<uint8_t> & buf)2334         explicit proxy_deserialize (
2335             std::vector<uint8_t>& buf
2336         ) : fin_optional_owning_ptr(new vectorstream(buf)),
2337             fin(*fin_optional_owning_ptr)
2338         {
2339             init();
2340         }
2341 
proxy_deserialize(std::istream & ss)2342         explicit proxy_deserialize (
2343             std::istream& ss
2344         ) : fin_optional_owning_ptr(nullptr),
2345             fin(ss)
2346         {
2347             init();
2348         }
2349 
2350         template <typename T>
2351         inline proxy_deserialize& operator>>(T& item)
2352         {
2353             return doit(item);
2354         }
2355 
2356         template <typename T>
2357         inline proxy_deserialize& operator>>(ramdump_t<T>&& item)
2358         {
2359             return doit(std::move(item));
2360         }
2361 
2362     private:
2363 
init()2364         void init()
2365         {
2366             // read the file header into a buffer and then seek back to the start of the
2367             // file.
2368             fin.read(file_header,4);
2369             fin.clear();
2370             fin.seekg(0);
2371         }
2372 
2373     private:
2374 
2375         template <typename T>
doit(T && item)2376         inline proxy_deserialize& doit(T&& item)
2377         {
2378             try
2379             {
2380                 if (fin.peek() == EOF)
2381                     throw serialization_error("No more objects were in the stream!");
2382                 deserialize(std::forward<T>(item), fin);
2383             }
2384             catch (serialization_error& e)
2385             {
2386                 std::string suffix;
2387                 if (looks_like_a_compressed_file())
2388                     suffix = "\n *** THIS LOOKS LIKE A COMPRESSED FILE.  DID YOU FORGET TO DECOMPRESS IT? *** \n";
2389 
2390                 const std::string stream_description = filename.empty() ? "stream" : "file '" + filename + "'";
2391 
2392                 if (objects_read == 0)
2393                 {
2394                     throw serialization_error("An error occurred while trying to read the first"
2395                         " object from the " + stream_description + ".\nERROR: " + e.info + "\n" + suffix);
2396                 }
2397                 else if (objects_read == 1)
2398                 {
2399                     throw serialization_error("An error occurred while trying to read the second"
2400                         " object from the " + stream_description + ".\nERROR: " + e.info + "\n" + suffix);
2401                 }
2402                 else if (objects_read == 2)
2403                 {
2404                     throw serialization_error("An error occurred while trying to read the third"
2405                         " object from the " + stream_description + ".\nERROR: " + e.info + "\n" + suffix);
2406                 }
2407                 else
2408                 {
2409                     throw serialization_error("An error occurred while trying to read the " +
2410                         std::to_string(objects_read+1) + "th object from the " + stream_description + ".\nERROR: " + e.info + "\n" + suffix);
2411                 }
2412             }
2413             ++objects_read;
2414             return *this;
2415         }
2416 
2417         int objects_read = 0;
2418         const std::string filename = "";
2419         std::unique_ptr<std::istream> fin_optional_owning_ptr;
2420         std::istream& fin;
2421 
2422         // We don't need to look at the file header.  However, it's here because people
2423         // keep posting questions to the dlib forums asking why they get file load errors.
2424         // Then it turns out that the problem is they have a compressed file that NEEDS TO
2425         // BE DECOMPRESSED by bzip2 or whatever and the reason they are getting
2426         // deserialization errors is because they didn't decompress the file.  So we are
2427         // going to check if this file looks like a compressed file and if so then emit an
2428         // error message telling them to unzip the file. :(
2429         char file_header[4] = {0,0,0,0};
2430 
looks_like_a_compressed_file()2431         bool looks_like_a_compressed_file(
2432         ) const
2433         {
2434             if (file_header[0] == 'B' && file_header[1] == 'Z' && file_header[2] == 'h' &&
2435                 ('0' <= file_header[3] && file_header[3] <= '9') )
2436             {
2437                 return true;
2438             }
2439 
2440             return false;
2441         }
2442     };
2443 
serialize(const std::string & filename)2444     inline proxy_serialize serialize(const std::string& filename)
2445     { return proxy_serialize(filename); }
serialize(std::ostream & ss)2446     inline proxy_serialize serialize(std::ostream& ss)
2447     { return proxy_serialize(ss); }
serialize(std::vector<char> & buf)2448     inline proxy_serialize serialize(std::vector<char>& buf)
2449     { return proxy_serialize(buf); }
serialize(std::vector<int8_t> & buf)2450     inline proxy_serialize serialize(std::vector<int8_t>& buf)
2451     { return proxy_serialize(buf); }
serialize(std::vector<uint8_t> & buf)2452     inline proxy_serialize serialize(std::vector<uint8_t>& buf)
2453     { return proxy_serialize(buf); }
deserialize(const std::string & filename)2454     inline proxy_deserialize deserialize(const std::string& filename)
2455     { return proxy_deserialize(filename); }
deserialize(std::istream & ss)2456     inline proxy_deserialize deserialize(std::istream& ss)
2457     { return proxy_deserialize(ss); }
deserialize(std::vector<char> & buf)2458     inline proxy_deserialize deserialize(std::vector<char>& buf)
2459     { return proxy_deserialize(buf); }
deserialize(std::vector<int8_t> & buf)2460     inline proxy_deserialize deserialize(std::vector<int8_t>& buf)
2461     { return proxy_deserialize(buf); }
deserialize(std::vector<uint8_t> & buf)2462     inline proxy_deserialize deserialize(std::vector<uint8_t>& buf)
2463     { return proxy_deserialize(buf); }
2464 
2465 // ----------------------------------------------------------------------------------------
2466 
2467 }
2468 
2469 // forward declare the MessageLite object so we can reference it below.
2470 namespace google
2471 {
2472     namespace protobuf
2473     {
2474         class MessageLite;
2475     }
2476 }
2477 
2478 namespace dlib
2479 {
2480 
2481     /*!A is_protocol_buffer
2482         This is a template that tells you if a type is a Google protocol buffer object.
2483     !*/
2484 
2485     template <typename T, typename U = void >
2486     struct is_protocol_buffer
2487     {
2488         static const bool value = false;
2489     };
2490 
2491     template <typename T>
2492     struct is_protocol_buffer <T,typename enable_if<is_convertible<T*,::google::protobuf::MessageLite*> >::type  >
2493     {
2494         static const bool value = true;
2495     };
2496 
2497     template <typename T>
2498     typename enable_if<is_protocol_buffer<T> >::type serialize(const T& item, std::ostream& out)
2499     {
2500         // Note that Google protocol buffer messages are not self delimiting
2501         // (see https://developers.google.com/protocol-buffers/docs/techniques)
2502         // This means they don't record their length or where they end, so we have
2503         // to record this information ourselves.  So we save the size as a little endian 32bit
2504         // integer prefixed onto the front of the message.
2505 
2506         byte_orderer bo;
2507 
2508         // serialize into temp string
2509         std::string temp;
2510         if (!item.SerializeToString(&temp))
2511             throw dlib::serialization_error("Error while serializing a Google Protocol Buffer object.");
2512         if (temp.size() > std::numeric_limits<uint32>::max())
2513             throw dlib::serialization_error("Error while serializing a Google Protocol Buffer object, message too large.");
2514 
2515         // write temp to the output stream
2516         uint32 size = static_cast<uint32>(temp.size());
2517         bo.host_to_little(size);
2518         out.write((char*)&size, sizeof(size));
2519         out.write(temp.c_str(), temp.size());
2520     }
2521 
2522     template <typename T>
2523     typename enable_if<is_protocol_buffer<T> >::type deserialize(T& item, std::istream& in)
2524     {
2525         // Note that Google protocol buffer messages are not self delimiting
2526         // (see https://developers.google.com/protocol-buffers/docs/techniques)
2527         // This means they don't record their length or where they end, so we have
2528         // to record this information ourselves.  So we save the size as a little endian 32bit
2529         // integer prefixed onto the front of the message.
2530 
2531         byte_orderer bo;
2532 
2533         uint32 size = 0;
2534         // read the size
2535         in.read((char*)&size, sizeof(size));
2536         bo.little_to_host(size);
2537         if (!in || size == 0)
2538             throw dlib::serialization_error("Error while deserializing a Google Protocol Buffer object.");
2539 
2540         // read the bytes into temp
2541         std::string temp;
2542         temp.resize(size);
2543         in.read(&temp[0], size);
2544 
2545         // parse temp into item
2546         if (!in || !item.ParseFromString(temp))
2547         {
2548             throw dlib::serialization_error("Error while deserializing a Google Protocol Buffer object.");
2549         }
2550     }
2551 
2552 // ----------------------------------------------------------------------------------------
2553 
2554     inline void check_serialized_version(const std::string& expected_version, std::istream& in)
2555     {
2556         std::string version;
2557         deserialize(version, in);
2558         if (version != expected_version)
2559         {
2560             throw serialization_error("Unexpected version '"+version+
2561                 "' found while deserializing object. Expected version to be '"+expected_version+"'.");
2562         }
2563     }
2564 
2565 // ----------------------------------------------------------------------------------------
2566 
2567     template<typename T>
2568     inline void serialize_these(std::ostream& out, const T& x)
2569     {
2570         using dlib::serialize;
2571         serialize(x, out);
2572     }
2573 
2574     template<typename T, typename... Rest>
2575     inline void serialize_these(std::ostream& out, const T& x, const Rest& ... rest)
2576     {
2577         serialize_these(out, x);
2578         serialize_these(out, rest...);
2579     }
2580 
2581     template<typename T>
2582     inline void deserialize_these(std::istream& in, T& x)
2583     {
2584         using dlib::deserialize;
2585         deserialize(x, in);
2586     }
2587 
2588     template<typename T, typename... Rest>
2589     inline void deserialize_these(std::istream& in, T& x, Rest& ... rest)
2590     {
2591         deserialize_these(in, x);
2592         deserialize_these(in, rest...);
2593     }
2594 
2595     #define DLIB_DEFINE_DEFAULT_SERIALIZATION(Type, ...)                \
2596     void serialize_to(std::ostream& dlibDefaultSer$_out) const          \
2597     {                                                                   \
2598         using dlib::serialize;                                          \
2599         using dlib::serialize_these;                                    \
2600         try                                                             \
2601         {                                                               \
2602             /* Write a version header so that if, at a later time, */   \
2603             /* you realize you need to change the serialization    */   \
2604             /* format you can identify which version of the format */   \
2605             /* you are encountering when reading old files.        */   \
2606             int dlibDefaultSer$_version = 1;                            \
2607             serialize(dlibDefaultSer$_version, dlibDefaultSer$_out);    \
2608             serialize_these(dlibDefaultSer$_out, __VA_ARGS__);          \
2609         }                                                               \
2610         catch (dlib::serialization_error& e)                            \
2611         {                                                               \
2612             throw dlib::serialization_error(e.info + "\n   while serializing object of type " #Type); \
2613         }                                                               \
2614     }                                                                   \
2615                                                                         \
2616     void deserialize_from(std::istream& dlibDefaultSer$_in)             \
2617     {                                                                   \
2618         using dlib::deserialize;                                        \
2619         using dlib::deserialize_these;                                  \
2620         try                                                             \
2621         {                                                               \
2622             int dlibDefaultSer$_version = 0;                            \
2623             deserialize(dlibDefaultSer$_version, dlibDefaultSer$_in);   \
2624             if (dlibDefaultSer$_version != 1)                           \
2625                 throw dlib::serialization_error("Unexpected version found while deserializing " #Type); \
2626             deserialize_these(dlibDefaultSer$_in, __VA_ARGS__);         \
2627         }                                                               \
2628         catch (dlib::serialization_error& e)                            \
2629         {                                                               \
2630             throw dlib::serialization_error(e.info + "\n   while deserializing object of type " #Type); \
2631         }                                                               \
2632     }                                                                   \
2633     inline friend void serialize(const Type& item, std::ostream& out)   \
2634     {                                                                   \
2635         item.serialize_to(out);                                         \
2636     }                                                                   \
2637     inline friend void deserialize(Type& item, std::istream& in)        \
2638     {                                                                   \
2639         item.deserialize_from(in);                                      \
2640     }
2641 }
2642 
2643 #endif // DLIB_SERIALIZe_
2644 
2645