| /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8 |
| // demo.cpp |
| // |
| // (C) Copyright 2002-4 Robert Ramey - http://www.rrsd.com . |
| // Use, modification and distribution is subject to the Boost Software |
| // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at |
| // http://www.boost.org/LICENSE_1_0.txt) |
| |
| |
| #include <cstddef> // NULL |
| #include <iomanip> |
| #include <iostream> |
| #include <fstream> |
| #include <string> |
| |
| #include <boost/archive/tmpdir.hpp> |
| |
| #include <boost/archive/text_iarchive.hpp> |
| #include <boost/archive/text_oarchive.hpp> |
| |
| #include <boost/serialization/base_object.hpp> |
| #include <boost/serialization/utility.hpp> |
| #include <boost/serialization/list.hpp> |
| #include <boost/serialization/assume_abstract.hpp> |
| |
| ///////////////////////////////////////////////////////////// |
| // The intent of this program is to serve as a tutorial for |
| // users of the serialization package. An attempt has been made |
| // to illustrate most of the facilities of the package. |
| // |
| // The intent is to create an example suffciently complete to |
| // illustrate the usage and utility of the package while |
| // including a minimum of other code. |
| // |
| // This illustration models the bus system of a small city. |
| // This includes, multiple bus stops, bus routes and schedules. |
| // There are different kinds of stops. Bus stops in general will |
| // will appear on multiple routes. A schedule will include |
| // muliple trips on the same route. |
| |
| ///////////////////////////////////////////////////////////// |
| // gps coordinate |
| // |
| // llustrates serialization for a simple type |
| // |
| class gps_position |
| { |
| friend std::ostream & operator<<(std::ostream &os, const gps_position &gp); |
| friend class boost::serialization::access; |
| int degrees; |
| int minutes; |
| float seconds; |
| template<class Archive> |
| void serialize(Archive & ar, const unsigned int /* file_version */){ |
| ar & degrees & minutes & seconds; |
| } |
| public: |
| // every serializable class needs a constructor |
| gps_position(){}; |
| gps_position(int _d, int _m, float _s) : |
| degrees(_d), minutes(_m), seconds(_s) |
| {} |
| }; |
| std::ostream & operator<<(std::ostream &os, const gps_position &gp) |
| { |
| return os << ' ' << gp.degrees << (unsigned char)186 << gp.minutes << '\'' << gp.seconds << '"'; |
| } |
| |
| ///////////////////////////////////////////////////////////// |
| // One bus stop |
| // |
| // illustrates serialization of serializable members |
| // |
| |
| class bus_stop |
| { |
| friend class boost::serialization::access; |
| friend std::ostream & operator<<(std::ostream &os, const bus_stop &gp); |
| virtual std::string description() const = 0; |
| gps_position latitude; |
| gps_position longitude; |
| template<class Archive> |
| void serialize(Archive &ar, const unsigned int version) |
| { |
| ar & latitude; |
| ar & longitude; |
| } |
| protected: |
| bus_stop(const gps_position & _lat, const gps_position & _long) : |
| latitude(_lat), longitude(_long) |
| {} |
| public: |
| bus_stop(){} |
| virtual ~bus_stop(){} |
| }; |
| |
| BOOST_SERIALIZATION_ASSUME_ABSTRACT(bus_stop) |
| |
| std::ostream & operator<<(std::ostream &os, const bus_stop &bs) |
| { |
| return os << bs.latitude << bs.longitude << ' ' << bs.description(); |
| } |
| |
| ///////////////////////////////////////////////////////////// |
| // Several kinds of bus stops |
| // |
| // illustrates serialization of derived types |
| // |
| class bus_stop_corner : public bus_stop |
| { |
| friend class boost::serialization::access; |
| std::string street1; |
| std::string street2; |
| virtual std::string description() const |
| { |
| return street1 + " and " + street2; |
| } |
| template<class Archive> |
| void serialize(Archive &ar, const unsigned int version) |
| { |
| // save/load base class information |
| ar & boost::serialization::base_object<bus_stop>(*this); |
| ar & street1 & street2; |
| } |
| |
| public: |
| bus_stop_corner(){} |
| bus_stop_corner(const gps_position & _lat, const gps_position & _long, |
| const std::string & _s1, const std::string & _s2 |
| ) : |
| bus_stop(_lat, _long), street1(_s1), street2(_s2) |
| { |
| } |
| }; |
| |
| class bus_stop_destination : public bus_stop |
| { |
| friend class boost::serialization::access; |
| std::string name; |
| virtual std::string description() const |
| { |
| return name; |
| } |
| template<class Archive> |
| void serialize(Archive &ar, const unsigned int version) |
| { |
| ar & boost::serialization::base_object<bus_stop>(*this) & name; |
| } |
| public: |
| |
| bus_stop_destination(){} |
| bus_stop_destination( |
| const gps_position & _lat, const gps_position & _long, const std::string & _name |
| ) : |
| bus_stop(_lat, _long), name(_name) |
| { |
| } |
| }; |
| |
| ///////////////////////////////////////////////////////////// |
| // a bus route is a collection of bus stops |
| // |
| // illustrates serialization of STL collection templates. |
| // |
| // illustrates serialzation of polymorphic pointer (bus stop *); |
| // |
| // illustrates storage and recovery of shared pointers is correct |
| // and efficient. That is objects pointed to by more than one |
| // pointer are stored only once. In such cases only one such |
| // object is restored and pointers are restored to point to it |
| // |
| class bus_route |
| { |
| friend class boost::serialization::access; |
| friend std::ostream & operator<<(std::ostream &os, const bus_route &br); |
| typedef bus_stop * bus_stop_pointer; |
| std::list<bus_stop_pointer> stops; |
| template<class Archive> |
| void serialize(Archive &ar, const unsigned int version) |
| { |
| // in this program, these classes are never serialized directly but rather |
| // through a pointer to the base class bus_stop. So we need a way to be |
| // sure that the archive contains information about these derived classes. |
| //ar.template register_type<bus_stop_corner>(); |
| ar.register_type(static_cast<bus_stop_corner *>(NULL)); |
| //ar.template register_type<bus_stop_destination>(); |
| ar.register_type(static_cast<bus_stop_destination *>(NULL)); |
| // serialization of stl collections is already defined |
| // in the header |
| ar & stops; |
| } |
| public: |
| bus_route(){} |
| void append(bus_stop *_bs) |
| { |
| stops.insert(stops.end(), _bs); |
| } |
| }; |
| std::ostream & operator<<(std::ostream &os, const bus_route &br) |
| { |
| std::list<bus_stop *>::const_iterator it; |
| // note: we're displaying the pointer to permit verification |
| // that duplicated pointers are properly restored. |
| for(it = br.stops.begin(); it != br.stops.end(); it++){ |
| os << '\n' << std::hex << "0x" << *it << std::dec << ' ' << **it; |
| } |
| return os; |
| } |
| |
| ///////////////////////////////////////////////////////////// |
| // a bus schedule is a collection of routes each with a starting time |
| // |
| // Illustrates serialization of STL objects(pair) in a non-intrusive way. |
| // See definition of operator<< <pair<F, S> >(ar, pair) and others in |
| // serialization.hpp |
| // |
| // illustrates nesting of serializable classes |
| // |
| // illustrates use of version number to automatically grandfather older |
| // versions of the same class. |
| |
| class bus_schedule |
| { |
| public: |
| // note: this structure was made public. because the friend declarations |
| // didn't seem to work as expected. |
| struct trip_info |
| { |
| template<class Archive> |
| void serialize(Archive &ar, const unsigned int file_version) |
| { |
| // in versions 2 or later |
| if(file_version >= 2) |
| // read the drivers name |
| ar & driver; |
| // all versions have the follwing info |
| ar & hour & minute; |
| } |
| |
| // starting time |
| int hour; |
| int minute; |
| // only after system shipped was the driver's name added to the class |
| std::string driver; |
| |
| trip_info(){} |
| trip_info(int _h, int _m, const std::string &_d) : |
| hour(_h), minute(_m), driver(_d) |
| {} |
| }; |
| private: |
| friend class boost::serialization::access; |
| friend std::ostream & operator<<(std::ostream &os, const bus_schedule &bs); |
| friend std::ostream & operator<<(std::ostream &os, const bus_schedule::trip_info &ti); |
| std::list<std::pair<trip_info, bus_route *> > schedule; |
| template<class Archive> |
| void serialize(Archive &ar, const unsigned int version) |
| { |
| ar & schedule; |
| } |
| public: |
| void append(const std::string &_d, int _h, int _m, bus_route *_br) |
| { |
| schedule.insert(schedule.end(), std::make_pair(trip_info(_h, _m, _d), _br)); |
| } |
| bus_schedule(){} |
| }; |
| BOOST_CLASS_VERSION(bus_schedule::trip_info, 2) |
| |
| std::ostream & operator<<(std::ostream &os, const bus_schedule::trip_info &ti) |
| { |
| return os << '\n' << ti.hour << ':' << ti.minute << ' ' << ti.driver << ' '; |
| } |
| std::ostream & operator<<(std::ostream &os, const bus_schedule &bs) |
| { |
| std::list<std::pair<bus_schedule::trip_info, bus_route *> >::const_iterator it; |
| for(it = bs.schedule.begin(); it != bs.schedule.end(); it++){ |
| os << it->first << *(it->second); |
| } |
| return os; |
| } |
| |
| void save_schedule(const bus_schedule &s, const char * filename){ |
| // make an archive |
| std::ofstream ofs(filename); |
| boost::archive::text_oarchive oa(ofs); |
| oa << s; |
| } |
| |
| void |
| restore_schedule(bus_schedule &s, const char * filename) |
| { |
| // open the archive |
| std::ifstream ifs(filename); |
| boost::archive::text_iarchive ia(ifs); |
| |
| // restore the schedule from the archive |
| ia >> s; |
| } |
| |
| int main(int argc, char *argv[]) |
| { |
| // make the schedule |
| bus_schedule original_schedule; |
| |
| // fill in the data |
| // make a few stops |
| bus_stop *bs0 = new bus_stop_corner( |
| gps_position(34, 135, 52.560f), |
| gps_position(134, 22, 78.30f), |
| "24th Street", "10th Avenue" |
| ); |
| bus_stop *bs1 = new bus_stop_corner( |
| gps_position(35, 137, 23.456f), |
| gps_position(133, 35, 54.12f), |
| "State street", "Cathedral Vista Lane" |
| ); |
| bus_stop *bs2 = new bus_stop_destination( |
| gps_position(35, 136, 15.456f), |
| gps_position(133, 32, 15.300f), |
| "White House" |
| ); |
| bus_stop *bs3 = new bus_stop_destination( |
| gps_position(35, 134, 48.789f), |
| gps_position(133, 32, 16.230f), |
| "Lincoln Memorial" |
| ); |
| |
| // make a routes |
| bus_route route0; |
| route0.append(bs0); |
| route0.append(bs1); |
| route0.append(bs2); |
| |
| // add trips to schedule |
| original_schedule.append("bob", 6, 24, &route0); |
| original_schedule.append("bob", 9, 57, &route0); |
| original_schedule.append("alice", 11, 02, &route0); |
| |
| // make aother routes |
| bus_route route1; |
| route1.append(bs3); |
| route1.append(bs2); |
| route1.append(bs1); |
| |
| // add trips to schedule |
| original_schedule.append("ted", 7, 17, &route1); |
| original_schedule.append("ted", 9, 38, &route1); |
| original_schedule.append("alice", 11, 47, &route1); |
| |
| // display the complete schedule |
| std::cout << "original schedule"; |
| std::cout << original_schedule; |
| |
| std::string filename(boost::archive::tmpdir()); |
| filename += "/demofile.txt"; |
| |
| // save the schedule |
| save_schedule(original_schedule, filename.c_str()); |
| |
| // ... some time later |
| // make a new schedule |
| bus_schedule new_schedule; |
| |
| restore_schedule(new_schedule, filename.c_str()); |
| |
| // and display |
| std::cout << "\nrestored schedule"; |
| std::cout << new_schedule; |
| // should be the same as the old one. (except for the pointer values) |
| |
| delete bs0; |
| delete bs1; |
| delete bs2; |
| delete bs3; |
| return 0; |
| } |