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