dlib C++ Library - serialize.cpp

    // Copyright (C) 2008  Davis E. King (davisking@users.sourceforge.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 "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;

            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;

            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;

                i1_0 = 0;
                i2_0 = 0;
                i3_0 = 0;
                i4_0 = 0;
                i5_0 = 0;
                i6_0 = 0;
                i7_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;

                i1_0 = 5;
                i2_0 = 6;
                i3_0 = 7;
                i4_0 = 8;
                i5_0 = 9;
                i6_0 = 10;
                i7_0 = 11;

                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_CASSERT (i1 == 1,"");
                DLIB_CASSERT (i2 == 2,"");
                DLIB_CASSERT (i3 == 3,"");
                DLIB_CASSERT (i4 == 4,"");
                DLIB_CASSERT (i5 == 5,"");
                DLIB_CASSERT (i6 == 6,"");
                DLIB_CASSERT (i7 == 7,"");

                DLIB_CASSERT (i1_0 == 0,"");
                DLIB_CASSERT (i2_0 == 0,"");
                DLIB_CASSERT (i3_0 == 0,"");
                DLIB_CASSERT (i4_0 == 0,"");
                DLIB_CASSERT (i5_0 == 0,"");
                DLIB_CASSERT (i6_0 == 0,"");
                DLIB_CASSERT (i7_0 == 0,"");

                DLIB_CASSERT (i1_n == -1,"");
                DLIB_CASSERT (i2_n == -2,"");
                DLIB_CASSERT (i3_n == -3,"");

                DLIB_CASSERT (abs(f1 -123.456) < 1e-5,"");
                DLIB_CASSERT (abs(f2 - 543.341) < 1e-10,"");
                DLIB_CASSERT (abs(f3 - 5234234.23) < 1e-10,"");

                DLIB_CASSERT (f1_inf == numeric_limits<float>::infinity(),"");
                DLIB_CASSERT (f2_inf == numeric_limits<double>::infinity(),"");
                DLIB_CASSERT (f3_inf == numeric_limits<long double>::infinity(),"");
                DLIB_CASSERT (f1_ninf == -numeric_limits<float>::infinity(),"");
                DLIB_CASSERT (f2_ninf == -numeric_limits<double>::infinity(),"");
                DLIB_CASSERT (f3_ninf == -numeric_limits<long double>::infinity(),"");
                DLIB_CASSERT (!(f1_qnan <= numeric_limits<float>::infinity() && f1_qnan >= -numeric_limits<float>::infinity() ),"");
                DLIB_CASSERT (!(f2_qnan <= numeric_limits<double>::infinity() && f1_qnan >= -numeric_limits<double>::infinity() ),"");
                DLIB_CASSERT (!(f3_qnan <= numeric_limits<long double>::infinity() && f1_qnan >= -numeric_limits<long double>::infinity() ),"");
                DLIB_CASSERT (!(f1_snan <= numeric_limits<float>::infinity() && f1_qnan >= -numeric_limits<float>::infinity() ),"");
                DLIB_CASSERT (!(f2_snan <= numeric_limits<double>::infinity() && f1_qnan >= -numeric_limits<double>::infinity() ),"");
                DLIB_CASSERT (!(f3_snan <= numeric_limits<long double>::infinity() && f1_qnan >= -numeric_limits<long double>::infinity() ),"");

                DLIB_CASSERT (s1 == "davis","");
                DLIB_CASSERT (s2 == L"yo yo yo","");

                for (int i = 0; i < 10; ++i)
                {
                    DLIB_CASSERT (array[i] == i,"");
                }

                DLIB_CASSERT (b_true == true,"");
                DLIB_CASSERT (b_false == false,"");

            }

            void assert_in_state_2 (
            )
            {
                DLIB_CASSERT (i1 == 10,"");
                DLIB_CASSERT (i2 == 20,"");
                DLIB_CASSERT (i3 == 30,"");
                DLIB_CASSERT (i4 == 40,"");
                DLIB_CASSERT (i5 == 50,"");
                DLIB_CASSERT (i6 == 60,"");
                DLIB_CASSERT (i7 == 70,"");

                DLIB_CASSERT (i1_0 == 5,"");
                DLIB_CASSERT (i2_0 == 6,"");
                DLIB_CASSERT (i3_0 == 7,"");
                DLIB_CASSERT (i4_0 == 8,"");
                DLIB_CASSERT (i5_0 == 9,"");
                DLIB_CASSERT (i6_0 == 10,"");
                DLIB_CASSERT (i7_0 == 11,"");

                DLIB_CASSERT (i1_n == -13,"");
                DLIB_CASSERT (i2_n == -25,"");
                DLIB_CASSERT (i3_n == -12,"");

                DLIB_CASSERT (abs(f1 - 45.3) < 1e-5,"");
                DLIB_CASSERT (abs(f2 - 0.001) < 1e-10,"");
                DLIB_CASSERT (abs(f3 - 2.332) < 1e-10,"");
                DLIB_CASSERT (abs(f1_inf - 45.3) < 1e-5,"");
                DLIB_CASSERT (abs(f2_inf - 0.001) < 1e-10,"");
                DLIB_CASSERT (abs(f3_inf - 2.332) < 1e-10,"");
                DLIB_CASSERT (abs(f1_ninf - 45.3) < 1e-5,"");
                DLIB_CASSERT (abs(f2_ninf - 0.001) < 1e-10,"");
                DLIB_CASSERT (abs(f3_ninf - 2.332) < 1e-10,"");
                DLIB_CASSERT (abs(f1_qnan - 45.3) < 1e-5,"");
                DLIB_CASSERT (abs(f2_qnan - 0.001) < 1e-10,"");
                DLIB_CASSERT (abs(f3_qnan - 2.332) < 1e-10,"");
                DLIB_CASSERT (abs(f1_snan - 45.3) < 1e-5,"");
                DLIB_CASSERT (abs(f2_snan - 0.001) < 1e-10,"");
                DLIB_CASSERT (abs(f3_snan - 2.332) < 1e-10,"");

                DLIB_CASSERT (s1 == "","");
                DLIB_CASSERT (s2 == L"","");

                for (int i = 0; i < 10; ++i)
                {
                    DLIB_CASSERT (array[i] == 10-i,"");
                }

                DLIB_CASSERT (b_true == false,"");
                DLIB_CASSERT (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.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.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.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.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);
        }

    // ----------------------------------------------------------------------------------------

        // This function returns the contents of the file 'stuff.bin'
        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 << "AVaifX9zEbXbpgarAlucU9BNkSZXOyTKOGxr7taGvaQqrWOaCnaFVnAkSoI4sZ3Va8+I4DqkUa10";
            sout << "6im2LoQqVlfhtRzCgI93x19uWen15Lk+zylZTc34P6aBwSuYMo957IjLhCcBsxIqIbXnWN/7zQSv";
            sout << "c7Anq5STW+yvKzSohWor56pGXDTtZrm9bFTsaztlavtnauYvgn7RZkp4a9MrbgnDzdzmzAnE7+w1";
            sout << "hl94IKktATHIBtMUJsrENvx+np3m01ygEPIftRmEa4KpW1JkZORjqUR/j211oUweh+LYIMR+s4cX";
            sout << "0L7bwPBmULwA";

            // 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();

            /*
            // 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();
                */

        }

        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();
            }
        } a;

    }