// Copyright (C) 2008 Davis E. King (davis@dlib.net) // License: Boost Software License See LICENSE.txt for the full license. #include <iostream> #include <fstream> #include <sstream> #include <dlib/compress_stream.h> #include <dlib/base64.h> #include <string> #include <cstdlib> #include <ctime> #include <dlib/serialize.h> #include <dlib/image_transforms.h> #include <dlib/rand.h> #include "tester.h" namespace { // ---------------------------------------------------------------------------------------- using namespace test; using namespace dlib; using namespace std; struct test_object { signed char i1; signed short i2; signed long i3; unsigned char i4; unsigned short i5; unsigned long i6; uint64 i7; int64 i8; signed char i1_0; signed short i2_0; signed long i3_0; unsigned char i4_0; unsigned short i5_0; unsigned long i6_0; uint64 i7_0; int64 i8_0; signed char i1_n; signed short i2_n; signed long i3_n; float f1; double f2; long double f3; float f1_inf; double f2_inf; long double f3_inf; float f1_ninf; double f2_ninf; long double f3_ninf; float f1_qnan; double f2_qnan; long double f3_qnan; float f1_snan; double f2_snan; long double f3_snan; std::string s1; std::wstring s2; int array[10]; bool b_true; bool b_false; void set_state_1( ) { i1 = 1; i2 = 2; i3 = 3; i4 = 4; i5 = 5; i6 = 6; i7 = 7; i8 = 8; i1_0 = 0; i2_0 = 0; i3_0 = 0; i4_0 = 0; i5_0 = 0; i6_0 = 0; i7_0 = 0; i8_0 = 0; i1_n = -1; i2_n = -2; i3_n = -3; f1 = 123.456f; f2 = 543.341; f3 = 5234234.23; f1_inf = numeric_limits<float>::infinity(); f2_inf = numeric_limits<double>::infinity(); f3_inf = numeric_limits<long double>::infinity(); f1_ninf = -numeric_limits<float>::infinity(); f2_ninf = -numeric_limits<double>::infinity(); f3_ninf = -numeric_limits<long double>::infinity(); f1_qnan = numeric_limits<float>::quiet_NaN(); f2_qnan = numeric_limits<double>::quiet_NaN(); f3_qnan = numeric_limits<long double>::quiet_NaN(); f1_snan = numeric_limits<float>::signaling_NaN(); f2_snan = numeric_limits<double>::signaling_NaN(); f3_snan = numeric_limits<long double>::signaling_NaN(); s1 = "davis"; s2 = L"yo yo yo"; for (int i = 0; i < 10; ++i) array[i] = i; b_true = true; b_false = false; } void set_state_2( ) { i1 = 10; i2 = 20; i3 = 30; i4 = 40; i5 = 50; i6 = 60; i7 = 70; i8 = 80; i1_0 = 5; i2_0 = 6; i3_0 = 7; i4_0 = 8; i5_0 = 9; i6_0 = 10; i7_0 = 11; i8_0 = 12; i1_n = -13; i2_n = -25; i3_n = -12; f1 = 45.3f; f2 = 0.001; f3 = 2.332; f1_inf = f1; f2_inf = f2; f3_inf = f3; f1_ninf = f1; f2_ninf = f2; f3_ninf = f3; f1_qnan = f1; f2_qnan = f2; f3_qnan = f3; f1_snan = f1; f2_snan = f2; f3_snan = f3; s1 = ""; s2 = L""; for (int i = 0; i < 10; ++i) array[i] = 10-i; b_true = false; b_false = true; } void assert_in_state_1 ( ) { DLIB_TEST (i1 == 1); DLIB_TEST (i2 == 2); DLIB_TEST (i3 == 3); DLIB_TEST (i4 == 4); DLIB_TEST (i5 == 5); DLIB_TEST (i6 == 6); DLIB_TEST (i7 == 7); DLIB_TEST (i8 == 8); DLIB_TEST (i1_0 == 0); DLIB_TEST (i2_0 == 0); DLIB_TEST (i3_0 == 0); DLIB_TEST (i4_0 == 0); DLIB_TEST (i5_0 == 0); DLIB_TEST (i6_0 == 0); DLIB_TEST (i7_0 == 0); DLIB_TEST (i8_0 == 0); DLIB_TEST (i1_n == -1); DLIB_TEST (i2_n == -2); DLIB_TEST (i3_n == -3); DLIB_TEST (abs(f1 -123.456) < 1e-5); DLIB_TEST (abs(f2 - 543.341) < 1e-10); DLIB_TEST (abs(f3 - 5234234.23) < 1e-10); DLIB_TEST (f1_inf == numeric_limits<float>::infinity()); DLIB_TEST (f2_inf == numeric_limits<double>::infinity()); DLIB_TEST (f3_inf == numeric_limits<long double>::infinity()); DLIB_TEST (f1_ninf == -numeric_limits<float>::infinity()); DLIB_TEST (f2_ninf == -numeric_limits<double>::infinity()); DLIB_TEST (f3_ninf == -numeric_limits<long double>::infinity()); DLIB_TEST (!(f1_qnan <= numeric_limits<float>::infinity() && f1_qnan >= -numeric_limits<float>::infinity() )); DLIB_TEST (!(f2_qnan <= numeric_limits<double>::infinity() && f1_qnan >= -numeric_limits<double>::infinity() )); DLIB_TEST (!(f3_qnan <= numeric_limits<long double>::infinity() && f1_qnan >= -numeric_limits<long double>::infinity() )); DLIB_TEST (!(f1_snan <= numeric_limits<float>::infinity() && f1_qnan >= -numeric_limits<float>::infinity() )); DLIB_TEST (!(f2_snan <= numeric_limits<double>::infinity() && f1_qnan >= -numeric_limits<double>::infinity() )); DLIB_TEST (!(f3_snan <= numeric_limits<long double>::infinity() && f1_qnan >= -numeric_limits<long double>::infinity() )); DLIB_TEST (s1 == "davis"); DLIB_TEST (s2 == L"yo yo yo"); for (int i = 0; i < 10; ++i) { DLIB_TEST (array[i] == i); } DLIB_TEST (b_true == true); DLIB_TEST (b_false == false); } void assert_in_state_2 ( ) { DLIB_TEST (i1 == 10); DLIB_TEST (i2 == 20); DLIB_TEST (i3 == 30); DLIB_TEST (i4 == 40); DLIB_TEST (i5 == 50); DLIB_TEST (i6 == 60); DLIB_TEST (i7 == 70); DLIB_TEST (i8 == 80); DLIB_TEST (i1_0 == 5); DLIB_TEST (i2_0 == 6); DLIB_TEST (i3_0 == 7); DLIB_TEST (i4_0 == 8); DLIB_TEST (i5_0 == 9); DLIB_TEST (i6_0 == 10); DLIB_TEST (i7_0 == 11); DLIB_TEST (i8_0 == 12); DLIB_TEST (i1_n == -13); DLIB_TEST (i2_n == -25); DLIB_TEST (i3_n == -12); DLIB_TEST (abs(f1 - 45.3) < 1e-5); DLIB_TEST (abs(f2 - 0.001) < 1e-10); DLIB_TEST (abs(f3 - 2.332) < 1e-10); DLIB_TEST (abs(f1_inf - 45.3) < 1e-5); DLIB_TEST (abs(f2_inf - 0.001) < 1e-10); DLIB_TEST (abs(f3_inf - 2.332) < 1e-10); DLIB_TEST (abs(f1_ninf - 45.3) < 1e-5); DLIB_TEST (abs(f2_ninf - 0.001) < 1e-10); DLIB_TEST (abs(f3_ninf - 2.332) < 1e-10); DLIB_TEST (abs(f1_qnan - 45.3) < 1e-5); DLIB_TEST (abs(f2_qnan - 0.001) < 1e-10); DLIB_TEST (abs(f3_qnan - 2.332) < 1e-10); DLIB_TEST (abs(f1_snan - 45.3) < 1e-5); DLIB_TEST (abs(f2_snan - 0.001) < 1e-10); DLIB_TEST (abs(f3_snan - 2.332) < 1e-10); DLIB_TEST (s1 == ""); DLIB_TEST (s2 == L""); for (int i = 0; i < 10; ++i) { DLIB_TEST (array[i] == 10-i); } DLIB_TEST (b_true == false); DLIB_TEST (b_false == true); } }; // ---------------------------------------------------------------------------------------- void serialize ( const test_object& item, std::ostream& out ) { dlib::serialize(item.i1,out); dlib::serialize(item.i2,out); dlib::serialize(item.i3,out); dlib::serialize(item.i4,out); dlib::serialize(item.i5,out); dlib::serialize(item.i6,out); dlib::serialize(item.i7,out); dlib::serialize(item.i8,out); dlib::serialize(item.i1_0,out); dlib::serialize(item.i2_0,out); dlib::serialize(item.i3_0,out); dlib::serialize(item.i4_0,out); dlib::serialize(item.i5_0,out); dlib::serialize(item.i6_0,out); dlib::serialize(item.i7_0,out); dlib::serialize(item.i8_0,out); dlib::serialize(item.i1_n,out); dlib::serialize(item.i2_n,out); dlib::serialize(item.i3_n,out); dlib::serialize(item.f1,out); dlib::serialize(item.f2,out); dlib::serialize(item.f3,out); dlib::serialize(item.f1_inf,out); dlib::serialize(item.f2_inf,out); dlib::serialize(item.f3_inf,out); dlib::serialize(item.f1_ninf,out); dlib::serialize(item.f2_ninf,out); dlib::serialize(item.f3_ninf,out); dlib::serialize(item.f1_qnan,out); dlib::serialize(item.f2_qnan,out); dlib::serialize(item.f3_qnan,out); dlib::serialize(item.f1_snan,out); dlib::serialize(item.f2_snan,out); dlib::serialize(item.f3_snan,out); dlib::serialize(item.s1,out); dlib::serialize(item.s2,out); dlib::serialize(item.array,out); dlib::serialize(item.b_true,out); dlib::serialize(item.b_false,out); } // ---------------------------------------------------------------------------------------- void deserialize ( test_object& item, std::istream& in ) { dlib::deserialize(item.i1,in); dlib::deserialize(item.i2,in); dlib::deserialize(item.i3,in); dlib::deserialize(item.i4,in); dlib::deserialize(item.i5,in); dlib::deserialize(item.i6,in); dlib::deserialize(item.i7,in); dlib::deserialize(item.i8,in); dlib::deserialize(item.i1_0,in); dlib::deserialize(item.i2_0,in); dlib::deserialize(item.i3_0,in); dlib::deserialize(item.i4_0,in); dlib::deserialize(item.i5_0,in); dlib::deserialize(item.i6_0,in); dlib::deserialize(item.i7_0,in); dlib::deserialize(item.i8_0,in); dlib::deserialize(item.i1_n,in); dlib::deserialize(item.i2_n,in); dlib::deserialize(item.i3_n,in); dlib::deserialize(item.f1,in); dlib::deserialize(item.f2,in); dlib::deserialize(item.f3,in); dlib::deserialize(item.f1_inf,in); dlib::deserialize(item.f2_inf,in); dlib::deserialize(item.f3_inf,in); dlib::deserialize(item.f1_ninf,in); dlib::deserialize(item.f2_ninf,in); dlib::deserialize(item.f3_ninf,in); dlib::deserialize(item.f1_qnan,in); dlib::deserialize(item.f2_qnan,in); dlib::deserialize(item.f3_qnan,in); dlib::deserialize(item.f1_snan,in); dlib::deserialize(item.f2_snan,in); dlib::deserialize(item.f3_snan,in); dlib::deserialize(item.s1,in); dlib::deserialize(item.s2,in); dlib::deserialize(item.array,in); dlib::deserialize(item.b_true,in); dlib::deserialize(item.b_false,in); } template<typename T> bool pointers_values_equal(const unique_ptr<T>& l, const unique_ptr<T>& r) { return l && r ? *l == *r : l == r; } template<typename T> bool pointers_values_equal(const shared_ptr<T>& l, const shared_ptr<T>& r) { return l && r ? *l == *r : l == r; } struct immutable_type { immutable_type() = default; immutable_type(const immutable_type& other) = delete; immutable_type& operator=(const immutable_type& other) = delete; immutable_type(immutable_type&& other) = delete; immutable_type& operator=(immutable_type&& other) = delete; friend void serialize(const immutable_type&, std::ostream&) {} friend void deserialize(immutable_type&, std::istream&) {} bool operator==(const immutable_type&) const {return true;} }; struct my_custom_type { int a; float b; std::vector<float> c; std::list<string> d; std::forward_list<string> e; std::pair<int,string> f; std::tuple<int,string,float> g; std::map<string,int> h; std::unordered_map<string, int> i; std::multimap<string, int> j; std::unordered_multimap<string, int> k; std::set<string> l; std::unordered_set<string> m; std::multiset<string> n; std::unordered_multiset<string> o; std::shared_ptr<string> ptr_shared1; std::shared_ptr<string> ptr_shared2; std::vector<std::complex<double>> p; #if __cplusplus >= 201703L std::variant<int,float,std::string> q; std::optional<std::vector<std::string>> r; #endif bool operator==(const my_custom_type& rhs) const { #if __cplusplus >= 201703L const bool cpp17_ok = std::tie(q, r) == std::tie(rhs.q, rhs.r); #else const bool cpp17_ok = true; #endif return std::tie(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) == std::tie(rhs.a,rhs.b,rhs.c,rhs.d,rhs.e,rhs.f,rhs.g,rhs.h,rhs.i,rhs.j,rhs.k,rhs.l,rhs.m,rhs.n,rhs.o,rhs.p) && cpp17_ok && pointers_values_equal(ptr_shared1, rhs.ptr_shared1) && pointers_values_equal(ptr_shared2, rhs.ptr_shared2); } #if __cplusplus >= 201703L DLIB_DEFINE_DEFAULT_SERIALIZATION(my_custom_type, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, ptr_shared1, ptr_shared2, q, r); #else DLIB_DEFINE_DEFAULT_SERIALIZATION(my_custom_type, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, ptr_shared1, ptr_shared2); #endif }; struct my_custom_type_array { std::vector<my_custom_type> v; bool operator==(const my_custom_type_array& rhs) const { return v == rhs.v; } DLIB_DEFINE_DEFAULT_SERIALIZATION(my_custom_type_array, v); }; // ---------------------------------------------------------------------------------------- // This function returns the contents of the file 'stuff.bin' but using the old // floating point serialization format. const std::string get_decoded_string() { dlib::base64::kernel_1a base64_coder; dlib::compress_stream::kernel_1ea compressor; std::ostringstream sout; std::istringstream sin; // The base64 encoded data from the file 'stuff.bin' we want to decode and return. sout << "AVaifX9zEbXa9aocsrcRuvnNrR3WLuuU5eLWiy0UeXmnKXGLKZz8V44gzT4CM6wnCmAHFQug8G3C"; sout << "4cuLdNgp2ApkeLcvwFNJRENE0ShrRaxEBFEA8nah7vm8B2VmgImNblCejuP5IcDt60EaCKlqiit8"; sout << "+JGrzYxqBm3xFS4P+qlOROdbxc7pXBmUdh0rqNSEvn0FBPdoqY/5SpHgA2yAcH8XFrM1cdu0xS3P"; sout << "8PBcmLMJ7bFdzplwhrjuxtm4NfEOi6Rl9sU44AXycYgJd0+uH+dyoI9X3co5b3YWJtjvdVeztNAr"; sout << "BfSPfR6oAVNfiMBG7QA="; // Put the data into the istream sin sin.str(sout.str()); sout.str(""); // Decode the base64 text into its compressed binary form base64_coder.decode(sin,sout); sin.clear(); sin.str(sout.str()); sout.str(""); // Decompress the data into its original form compressor.decompress(sin,sout); // Return the decoded and decompressed data return sout.str(); } // This function returns the contents of the file 'stuff.bin' but using the new // floating point serialization format. const std::string get_decoded_string2() { dlib::base64 base64_coder; dlib::compress_stream::kernel_1ea compressor; std::ostringstream sout; std::istringstream sin; // The base64 encoded data from the file 'stuff.bin' we want to decode and return. sout << "AVaifX9zEbXa9aocsrcRuvnNqzZLptZ5mRd46xScCIfX6sq/46hG9JwIInElG50EtJKJY/+jAWit"; sout << "TpDBWrxBz124JRLsBz62h0D3Tqgnd8zygRx7t33Ybw40o07MrhzNEHgYavUukaPje5by78JIWHgk"; sout << "l7nb/TK+9ndVLrAThJ4v+GiPT3kh9H1tAAAAAQhbLa06pQjhrnjTXcRox1ZBEAV9/q1zAA=="; // Put the data into the istream sin sin.str(sout.str()); sout.str(""); // Decode the base64 text into its compressed binary form base64_coder.decode(sin,sout); sin.clear(); sin.str(sout.str()); sout.str(""); // Decompress the data into its original form compressor.decompress(sin,sout); // Return the decoded and decompressed data return sout.str(); } // ---------------------------------------------------------------------------------------- // Declare the logger we will use in this test. The name of the tester // should start with "test." logger dlog("test.serialize"); void serialize_test ( ) /*! ensures - runs tests on the serialization code for compliance with the specs !*/ { print_spinner(); ostringstream sout; test_object obj; obj.set_state_1(); obj.assert_in_state_1(); serialize(obj, sout); obj.assert_in_state_1(); obj.set_state_2(); obj.assert_in_state_2(); serialize(obj, sout); obj.assert_in_state_2(); istringstream sin(sout.str()); deserialize(obj,sin); obj.assert_in_state_1(); deserialize(obj,sin); obj.assert_in_state_2(); // now do the same thing as above but deserialize from some stored binary // data to make sure the serialized values are portable between different // machines sin.clear(); sin.str(get_decoded_string()); deserialize(obj,sin); obj.assert_in_state_1(); deserialize(obj,sin); obj.assert_in_state_2(); sin.clear(); sin.str(get_decoded_string2()); deserialize(obj,sin); obj.assert_in_state_1(); deserialize(obj,sin); obj.assert_in_state_2(); /* // This is the code that produced the encoded data stored in the get_decoded_string() function ofstream fout("stuff.bin",ios::binary); obj.set_state_1(); obj.assert_in_state_1(); serialize(obj, fout); obj.assert_in_state_1(); obj.set_state_2(); obj.assert_in_state_2(); serialize(obj, fout); obj.assert_in_state_2(); */ test_object obj2; obj.set_state_1(); obj2.set_state_2(); dlib::serialize("serialization_test.dat") << obj << obj2; obj.assert_in_state_1(); obj2.assert_in_state_2(); obj.set_state_2(); obj2.set_state_1(); obj.assert_in_state_2(); obj2.assert_in_state_1(); dlib::deserialize("serialization_test.dat") >> obj >> obj2; obj.assert_in_state_1(); obj2.assert_in_state_2(); } template <typename T> void test_vector ( ) { std::vector<T> a, b; for (int i = -10; i < 30; ++i) { a.push_back(i); } ostringstream sout; dlib::serialize(a, sout); istringstream sin(sout.str()); dlib::deserialize(b, sin); DLIB_TEST(a.size() == b.size()); DLIB_TEST(a.size() == 40); for (unsigned long i = 0; i < a.size(); ++i) { DLIB_TEST(a[i] == b[i]); } std::vector<T> c; sout.str(""); dlib::serialize(c, sout); sin.str(sout.str()); dlib::deserialize(a, sin); DLIB_TEST(a.size() == 0); DLIB_TEST(c.size() == 0); } void test_std_array ( ) { std::array<int,5> a, b; a = {1, 2, 3, 4, 5}; ostringstream sout; dlib::serialize(a, sout); istringstream sin(sout.str()); dlib::deserialize(b, sin); DLIB_TEST(a.size() == b.size()); DLIB_TEST(a.size() == 5); for (unsigned long i = 0; i < a.size(); ++i) { DLIB_TEST(a[i] == b[i]); } std::array<int,0> aa, bb; sout.str(""); dlib::serialize(aa, sout); sin.str(sout.str()); dlib::deserialize(bb, sin); DLIB_TEST(bb.size() == 0); } void test_vector_bool ( ) { std::vector<bool> a, b; a.push_back(true); a.push_back(true); a.push_back(false); a.push_back(true); a.push_back(false); a.push_back(true); ostringstream sout; dlib::serialize(a, sout); istringstream sin(sout.str()); dlib::deserialize(b, sin); DLIB_TEST(a.size() == b.size()); DLIB_TEST(a.size() == 6); for (unsigned long i = 0; i < a.size(); ++i) { DLIB_TEST(a[i] == b[i]); } } // ---------------------------------------------------------------------------------------- // This function returns the contents of the file 'matarray.dat' const std::string get_decoded_string_matarray_old() { dlib::base64 base64_coder; dlib::compress_stream::kernel_1ea compressor; std::ostringstream sout; std::istringstream sin; // The base64 encoded data from the file 'matarray.dat' we want to decode and return. sout << "AW852sEbTIeV+m/wLUcKJKPW+6IclviUWZcFh1daDZ0blDjPNTgPx0Lv56sIEwlG4I6C5OJzJBkZ"; sout << "PvczLjS7IEKh6eg7amNOyEexsQSgojL1oMe2gDEfkyInUGPJV90sNS0cvp/hIB134V8JCTYUP6vH"; sout << "9qpegLSIIQG+/NjLWyK2472vC88BJfKgkL3CPLMjQwB3tB928FNLbESDLIvpnb6q9ve68iuoyZZt"; sout << "z3TTJxHW3MIdgzuhNomvPxfo/Q+7lC/Orj0FewUX90al6DckwzOtLVRidh/ZKpsQsxzJYQGkjdX5"; sout << "mDzzXKqQb3Y3DnzEmwtRD9CUON3iRv1r26gHWLYorrYA"; // Put the data into the istream sin sin.str(sout.str()); sout.str(""); // Decode the base64 text into its compressed binary form base64_coder.decode(sin,sout); sin.clear(); sin.str(sout.str()); sout.str(""); // Decompress the data into its original form compressor.decompress(sin,sout); // Return the decoded and decompressed data return sout.str(); } // This function returns the contents of the file 'matarray.dat' const std::string get_decoded_string_matarray() { dlib::base64 base64_coder; dlib::compress_stream::kernel_1ea compressor; std::ostringstream sout; std::istringstream sin; // The base64 encoded data from the file 'matarray.dat' we want to decode and return. sout << "gO6XH2WGbm8Xaw3a5FJbh3V823W6P2Qk/vHaAAAAARccIppHWdmViaKby7JA5PQvXjYMWUYvXRHv"; sout << "xPdURZl1un3CT/rjT11Yry0y3+1W7GBmfBJ0gVFKGdiGuqoNAMtmzL/ll3YfEQ7ED7aB33aDTktw"; sout << "AWVkHT+gqTbKwjP+8YvB3s3ziK640ITOAWazAghKDVl7AHGn+fjq29paBZMczuJofl8FinZUhwa9"; sout << "Ol5gdAEQa6VZDmJUeo2soTJcEDpkW9LkRmXvjQkyEHfEHQNFDfQq4p2U+dHz4lOKlcj3VzQIeG/s"; sout << "oxa9KhJND4aQ5xeNUUHUzFBU3XhQHlyDIn/RNdX/ZwA="; // Put the data into the istream sin sin.str(sout.str()); sout.str(""); // Decode the base64 text into its compressed binary form base64_coder.decode(sin,sout); sin.clear(); sin.str(sout.str()); sout.str(""); // Decompress the data into its original form compressor.decompress(sin,sout); // Return the decoded and decompressed data return sout.str(); } void setup_mats_and_arrays ( array2d<int>& a, matrix<int>& m, array2d<unsigned char>& img1, array2d<rgb_pixel>& img2, array2d<bgr_pixel>& img3, array2d<rgb_alpha_pixel>& img4, array2d<hsi_pixel>& img5 ) { a.set_size(3,5); int cnt = 0; for (long r = 0; r < a.nr(); ++r) { for (long c = 0; c < a.nc(); ++c) { a[r][c] = cnt++; } } m = mat(a); img1.set_size(3,5); img2.set_size(3,5); img3.set_size(3,5); img4.set_size(3,5); img5.set_size(3,5); assign_all_pixels(img1, 0); assign_all_pixels(img2, 0); assign_all_pixels(img3, 0); assign_all_pixels(img4, 0); assign_all_pixels(img5, 0); unsigned char pcnt = 0; for (long r = 0; r < img1.nr(); ++r) { for (long c = 0; c < img1.nc(); ++c) { rgb_alpha_pixel temp; temp.red = pcnt++; temp.green = pcnt++; temp.blue = pcnt++; temp.alpha = 150+pcnt++; assign_pixel(img1[r][c], temp); assign_pixel(img2[r][c], temp); assign_pixel(img3[r][c], temp); assign_pixel(img4[r][c], temp); } } for (long r = 0; r < img5.nr(); ++r) { for (long c = 0; c < img5.nc(); ++c) { img5[r][c].h = pcnt++; img5[r][c].s = pcnt++; img5[r][c].i = pcnt++; } } } void test_deserialize( std::istream& fin ) { array2d<int> a; matrix<int> m; array2d<unsigned char> img1; array2d<rgb_pixel> img2; array2d<bgr_pixel> img3; array2d<rgb_alpha_pixel> img4; array2d<hsi_pixel> img5; setup_mats_and_arrays(a,m,img1,img2,img3,img4,img5); array2d<unsigned char> img1_; array2d<rgb_pixel> img2_; array2d<bgr_pixel> img3_; array2d<rgb_alpha_pixel> img4_; array2d<hsi_pixel> img5_; matrix<int> m_; array2d<int> a_; deserialize(a_, fin); DLIB_TEST(mat(a_) == mat(a)); deserialize(m_, fin); DLIB_TEST(mat(m_) == mat(m)); deserialize(a_, fin); DLIB_TEST(mat(a_) == mat(a)); deserialize(m_, fin); DLIB_TEST(mat(m_) == mat(m)); deserialize(img1_, fin); DLIB_TEST(mat(img1_) == mat(img1)); deserialize(img2_, fin); DLIB_TEST(mat(img2_) == mat(img2)); deserialize(img3_, fin); DLIB_TEST(mat(img3_) == mat(img3)); deserialize(img4_, fin); DLIB_TEST(mat(img4_) == mat(img4)); deserialize(img5_, fin); DLIB_TEST(mat(img5_) == mat(img5)); } void test_deserialize_all_array2d( std::istream& fin ) { array2d<int> a; matrix<int> m; array2d<unsigned char> img1; array2d<rgb_pixel> img2; array2d<bgr_pixel> img3; array2d<rgb_alpha_pixel> img4; array2d<hsi_pixel> img5; setup_mats_and_arrays(a,m,img1,img2,img3,img4,img5); array2d<unsigned char> img1_; array2d<rgb_pixel> img2_; array2d<bgr_pixel> img3_; array2d<rgb_alpha_pixel> img4_; array2d<hsi_pixel> img5_; array2d<int> m_; array2d<int> a_; deserialize(a_, fin); DLIB_TEST(mat(a_) == mat(a)); deserialize(m_, fin); DLIB_TEST(mat(m_) == mat(m)); deserialize(a_, fin); DLIB_TEST(mat(a_) == mat(a)); deserialize(m_, fin); DLIB_TEST(mat(m_) == mat(m)); deserialize(img1_, fin); DLIB_TEST(mat(img1_) == mat(img1)); deserialize(img2_, fin); DLIB_TEST(mat(img2_) == mat(img2)); deserialize(img3_, fin); DLIB_TEST(mat(img3_) == mat(img3)); deserialize(img4_, fin); DLIB_TEST(mat(img4_) == mat(img4)); deserialize(img5_, fin); DLIB_TEST(mat(img5_) == mat(img5)); } void test_deserialize_all_matrix( std::istream& fin ) { array2d<int> a; matrix<int> m; array2d<unsigned char> img1; array2d<rgb_pixel> img2; array2d<bgr_pixel> img3; array2d<rgb_alpha_pixel> img4; array2d<hsi_pixel> img5; setup_mats_and_arrays(a,m,img1,img2,img3,img4,img5); matrix<unsigned char> img1_; matrix<rgb_pixel> img2_; matrix<bgr_pixel> img3_; matrix<rgb_alpha_pixel> img4_; matrix<hsi_pixel> img5_; matrix<int> m_; matrix<int> a_; deserialize(a_, fin); DLIB_TEST(mat(a_) == mat(a)); deserialize(m_, fin); DLIB_TEST(mat(m_) == mat(m)); deserialize(a_, fin); DLIB_TEST(mat(a_) == mat(a)); deserialize(m_, fin); DLIB_TEST(mat(m_) == mat(m)); deserialize(img1_, fin); DLIB_TEST(mat(img1_) == mat(img1)); deserialize(img2_, fin); DLIB_TEST(mat(img2_) == mat(img2)); deserialize(img3_, fin); DLIB_TEST(mat(img3_) == mat(img3)); deserialize(img4_, fin); DLIB_TEST(mat(img4_) == mat(img4)); deserialize(img5_, fin); DLIB_TEST(mat(img5_) == mat(img5)); } void test_array2d_and_matrix_serialization() { ostringstream sout; array2d<int> a; matrix<int> m; array2d<unsigned char> img1; array2d<rgb_pixel> img2; array2d<bgr_pixel> img3; array2d<rgb_alpha_pixel> img4; array2d<hsi_pixel> img5; setup_mats_and_arrays(a,m,img1,img2,img3,img4,img5); serialize(a, sout); serialize(m, sout); serialize(a, sout); serialize(m, sout); serialize(img1, sout); serialize(img2, sout); serialize(img3, sout); serialize(img4, sout); serialize(img5, sout); // -------------------- { istringstream sin(sout.str()); test_deserialize(sin); } { istringstream sin(sout.str()); test_deserialize_all_array2d(sin); } { istringstream sin(sout.str()); test_deserialize_all_matrix(sin); } { istringstream sin(get_decoded_string_matarray()); test_deserialize(sin); } { istringstream sin(get_decoded_string_matarray()); test_deserialize_all_array2d(sin); } { istringstream sin(get_decoded_string_matarray()); test_deserialize_all_matrix(sin); } { // Make sure we can still deserialize the serialization // format for array2d and matrix objects used by older versions // of dlib. istringstream sin(get_decoded_string_matarray_old()); test_deserialize(sin); } } // ---------------------------------------------------------------------------------------- void test_strings() { string str1 = "stuff"; char buf[6]; buf[0] = 0; buf[1] = 1; buf[2] = 2; buf[3] = 0; buf[4] = 3; buf[5] = 3; dlib::serialize("ser_test_string.dat") << str1 << buf << "morestuff" << ""; string str2, str3, str4; char buf2[6]; memset(buf2,0,sizeof(buf2)); dlib::deserialize("ser_test_string.dat") >> str2 >> buf2 >> str3 >> str4; DLIB_TEST(str2 == "stuff"); DLIB_TEST(str3 == "morestuff"); DLIB_TEST(str4 == ""); DLIB_TEST(buf2[0] == 0); DLIB_TEST(buf2[1] == 1); DLIB_TEST(buf2[2] == 2); DLIB_TEST(buf2[3] == 0); DLIB_TEST(buf2[4] == 3); DLIB_TEST(buf2[5] == 3); ofstream fout("ser_test_string.dat", ios::binary); dlib::serialize(str1, fout); dlib::serialize(buf, fout); dlib::serialize("morestuff", fout); fout.close(); ifstream fin("ser_test_string.dat", ios::binary); memset(buf2,0,sizeof(buf2)); str2.clear(); str3.clear(); dlib::deserialize(str2, fin); dlib::deserialize(buf2, fin); dlib::deserialize(str3, fin); DLIB_TEST(str2 == "stuff"); DLIB_TEST(str3 == "morestuff"); DLIB_TEST(buf2[0] == 0); DLIB_TEST(buf2[1] == 1); DLIB_TEST(buf2[2] == 2); DLIB_TEST(buf2[3] == 0); DLIB_TEST(buf2[4] == 3); DLIB_TEST(buf2[5] == 3); // make sure ramdump() overloads compile and work. { matrix<double,2,2> a = {1,2,3,4}; const matrix<double,2,2> b = {3,2,3,4}; dlib::serialize("ramdump_mat.dat") << ramdump(a) << ramdump(b); matrix<double,2,2> A, B; dlib::deserialize("ramdump_mat.dat") >> ramdump(A) >> ramdump(B); DLIB_TEST(A == a); DLIB_TEST(B == b); A = 0; B = 0; DLIB_TEST(A != a); DLIB_TEST(B != b); ostringstream sout; dlib::serialize(ramdump(a), sout); dlib::serialize(ramdump(b), sout); istringstream sin(sout.str()); dlib::deserialize(ramdump(A), sin); dlib::deserialize(ramdump(B), sin); DLIB_TEST(A == a); DLIB_TEST(B == b); } } void test_macros_and_serializers() { std::unique_ptr<string> uptr1, uptr2, uptr3, uptr4; uptr1.reset(new string("hello from uptr1")); my_custom_type t1, t2, t3, t4; t1.a = 1; t1.b = 2.5; t1.c = {1.f, 2.f, 3.f, 4.f, 5.f}; t1.d.push_back("hello from back of list"); t1.d.push_back("world from back of list"); t1.d.push_front("world from front of list"); t1.d.push_front("hello from front of list"); t1.e.push_front("world from forward_list"); t1.e.push_front("hello from forward_list"); t1.f = make_pair(2, "hello from pair"); std::get<0>(t1.g) = 2; std::get<1>(t1.g) = "hello from tuple"; std::get<2>(t1.g) = 1.4142; t1.h["key"] = 15; t1.i["key"] = 16; t1.i.insert({"inserted key", 17}); t1.j.insert({"key", 21}); t1.j.insert({"key", 22}); t1.j.insert({"inserted key", 23}); t1.j.insert({"inserted key", 24}); t1.j.insert({"key", 25}); t1.j.insert({"key", 26}); t1.k.insert({"inserted key", 27}); t1.k.insert({"inserted key", 28}); t1.l.insert("hello from set"); t1.m.insert("hello from unordered_set"); t1.n.insert("hello from multiset"); t1.n.insert("hello from multiset"); t1.o.insert("hello from unordered_multiset"); t1.o.insert("hello from unordered_multiset"); t1.ptr_shared1 = make_shared<string>("hello from shared_ptr"); dlib::rand rng(std::time(NULL)); for (int i = 0 ; i < 1024 ; i++) t1.p.push_back(rng.get_random_gaussian()); #if __cplusplus >= 201703L t1.q = "hello there from std::variant, welcome!"; t1.r = {"hello from optional vector of string"}; #endif t2.a = 2; t2.b = 4.0; t2.c.resize(10); my_custom_type_array v1, v2; v1.v.push_back(t1); v1.v.push_back(t2); #if __cplusplus >= 201703L std::variant<int,float,std::string,immutable_type> i1, i2; i1 = std::string("hello from variant that can hold an immutable type"); #else // make it so that we don't need to add #if guards in every block below std::string i1, i2; i1 = "std::variant not supported"; #endif { dlib::serialize("serialization_test_macros.dat") << t1 << t2 << v1 << uptr1 << uptr2 << i1; dlib::deserialize("serialization_test_macros.dat") >> t3 >> t4 >> v2 >> uptr3 >> uptr4 >> i2; DLIB_TEST(t1 == t3); DLIB_TEST(t2 == t4); DLIB_TEST(v1 == v2); DLIB_TEST(pointers_values_equal(uptr1, uptr3)); DLIB_TEST(pointers_values_equal(uptr2, uptr4)); DLIB_TEST(i1 == i2); } { std::stringstream ss; dlib::serialize(ss) << t1 << t2 << v1 << uptr1 << uptr2 << i1; dlib::deserialize(ss) >> t3 >> t4 >> v2 >> uptr3 >> uptr4 >> i2; DLIB_TEST(t1 == t3); DLIB_TEST(t2 == t4); DLIB_TEST(v1 == v2); DLIB_TEST(pointers_values_equal(uptr1, uptr3)); DLIB_TEST(pointers_values_equal(uptr2, uptr4)); DLIB_TEST(i1 == i2); } { std::ostringstream sout; dlib::serialize(sout) << t1 << t2 << v1 << uptr1 << uptr2 << i1; std::istringstream sin(sout.str()); dlib::deserialize(sin) >> t3 >> t4 >> v2 >> uptr3 >> uptr4 >> i2; DLIB_TEST(t1 == t3); DLIB_TEST(t2 == t4); DLIB_TEST(v1 == v2); DLIB_TEST(pointers_values_equal(uptr1, uptr3)); DLIB_TEST(pointers_values_equal(uptr2, uptr4)); DLIB_TEST(i1 == i2); } { std::vector<char> buf; dlib::serialize(buf) << t1 << t2 << v1 << uptr1 << uptr2 << i1; dlib::deserialize(buf) >> t3 >> t4 >> v2 >> uptr3 >> uptr4 >> i2; DLIB_TEST(t1 == t3); DLIB_TEST(t2 == t4); DLIB_TEST(v1 == v2); DLIB_TEST(pointers_values_equal(uptr1, uptr3)); DLIB_TEST(pointers_values_equal(uptr2, uptr4)); DLIB_TEST(i1 == i2); } { std::vector<int8_t> buf; dlib::serialize(buf) << t1 << t2 << v1 << uptr1 << uptr2 << i1; dlib::deserialize(buf) >> t3 >> t4 >> v2 >> uptr3 >> uptr4 >> i2; DLIB_TEST(t1 == t3); DLIB_TEST(t2 == t4); DLIB_TEST(v1 == v2); DLIB_TEST(pointers_values_equal(uptr1, uptr3)); DLIB_TEST(pointers_values_equal(uptr2, uptr4)); DLIB_TEST(i1 == i2); } { std::vector<uint8_t> buf; dlib::serialize(buf) << t1 << t2 << v1 << uptr1 << uptr2 << i1; dlib::deserialize(buf) >> t3 >> t4 >> v2 >> uptr3 >> uptr4 >> i2; DLIB_TEST(t1 == t3); DLIB_TEST(t2 == t4); DLIB_TEST(v1 == v2); DLIB_TEST(pointers_values_equal(uptr1, uptr3)); DLIB_TEST(pointers_values_equal(uptr2, uptr4)); DLIB_TEST(i1 == i2); } { std::vector<char> buf1; dlib::serialize(buf1) << t1 << t2 << v1 << uptr1 << uptr2 << i1; std::vector<int8_t> buf2(buf1.begin(), buf1.end()); dlib::deserialize(buf2) >> t3 >> t4 >> v2 >> uptr3 >> uptr4 >> i2; DLIB_TEST(t1 == t3); DLIB_TEST(t2 == t4); DLIB_TEST(v1 == v2); DLIB_TEST(pointers_values_equal(uptr1, uptr3)); DLIB_TEST(pointers_values_equal(uptr2, uptr4)); DLIB_TEST(i1 == i2); } { std::vector<char> buf1; dlib::serialize(buf1) << t1 << t2 << v1 << uptr1 << uptr2 << i1; std::vector<uint8_t> buf2(buf1.begin(), buf1.end()); dlib::deserialize(buf2) >> t3 >> t4 >> v2 >> uptr3 >> uptr4 >> i2; DLIB_TEST(t1 == t3); DLIB_TEST(t2 == t4); DLIB_TEST(v1 == v2); DLIB_TEST(pointers_values_equal(uptr1, uptr3)); DLIB_TEST(pointers_values_equal(uptr2, uptr4)); DLIB_TEST(i1 == i2); } { std::vector<int8_t> buf1; dlib::serialize(buf1) << t1 << t2 << v1 << uptr1 << uptr2 << i1; std::vector<uint8_t> buf2(buf1.begin(), buf1.end()); dlib::deserialize(buf2) >> t3 >> t4 >> v2 >> uptr3 >> uptr4 >> i2; DLIB_TEST(t1 == t3); DLIB_TEST(t2 == t4); DLIB_TEST(v1 == v2); DLIB_TEST(pointers_values_equal(uptr1, uptr3)); DLIB_TEST(pointers_values_equal(uptr2, uptr4)); DLIB_TEST(i1 == i2); } } // ---------------------------------------------------------------------------------------- class serialize_tester : public tester { /*! WHAT THIS OBJECT REPRESENTS This object represents a test for the serialization . When it is constructed it adds itself into the testing framework. The command line switch is specified as test_serialize by passing that string to the tester constructor. !*/ public: serialize_tester ( ) : tester ("test_serialize", "Runs tests on the serialization code.") {} void perform_test ( ) { serialize_test(); test_vector<char>(); test_vector<unsigned char>(); test_vector<int>(); test_vector_bool(); test_array2d_and_matrix_serialization(); test_strings(); test_std_array(); test_macros_and_serializers(); } } a; }