1 /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
2 // demo.cpp
3 //
4 // (C) Copyright 2002-4 Robert Ramey - http://www.rrsd.com .
5 // Use, modification and distribution is subject to the Boost Software
6 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
7 // http://www.boost.org/LICENSE_1_0.txt)
8 
9 
10 #include <cstddef> // NULL
11 #include <iomanip>
12 #include <iostream>
13 #include <fstream>
14 #include <string>
15 
16 #include <boost/archive/tmpdir.hpp>
17 
18 #include <boost/archive/text_iarchive.hpp>
19 #include <boost/archive/text_oarchive.hpp>
20 
21 #include <boost/serialization/base_object.hpp>
22 #include <boost/serialization/utility.hpp>
23 #include <boost/serialization/list.hpp>
24 #include <boost/serialization/assume_abstract.hpp>
25 
26 /////////////////////////////////////////////////////////////
27 // The intent of this program is to serve as a tutorial for
28 // users of the serialization package.  An attempt has been made
29 // to illustrate most of the facilities of the package.
30 //
31 // The intent is to create an example suffciently complete to
32 // illustrate the usage and utility of the package while
33 // including a minimum of other code.
34 //
35 // This illustration models the bus system of a small city.
36 // This includes, multiple bus stops,  bus routes and schedules.
37 // There are different kinds of stops.  Bus stops in general will
38 // will appear on multiple routes.  A schedule will include
39 // muliple trips on the same route.
40 
41 /////////////////////////////////////////////////////////////
42 // gps coordinate
43 //
44 // llustrates serialization for a simple type
45 //
46 class gps_position
47 {
48     friend std::ostream & operator<<(std::ostream &os, const gps_position &gp);
49     friend class boost::serialization::access;
50     int degrees;
51     int minutes;
52     float seconds;
53     template<class Archive>
serialize(Archive & ar,const unsigned int)54     void serialize(Archive & ar, const unsigned int /* file_version */){
55         ar & degrees & minutes & seconds;
56     }
57 public:
58     // every serializable class needs a constructor
gps_position()59     gps_position(){};
gps_position(int _d,int _m,float _s)60     gps_position(int _d, int _m, float _s) :
61         degrees(_d), minutes(_m), seconds(_s)
62     {}
63 };
operator <<(std::ostream & os,const gps_position & gp)64 std::ostream & operator<<(std::ostream &os, const gps_position &gp)
65 {
66     return os << ' ' << gp.degrees << (unsigned char)186 << gp.minutes << '\'' << gp.seconds << '"';
67 }
68 
69 /////////////////////////////////////////////////////////////
70 // One bus stop
71 //
72 // illustrates serialization of serializable members
73 //
74 
75 class bus_stop
76 {
77     friend class boost::serialization::access;
78     friend std::ostream & operator<<(std::ostream &os, const bus_stop &gp);
79     virtual std::string description() const = 0;
80     gps_position latitude;
81     gps_position longitude;
82     template<class Archive>
serialize(Archive & ar,const unsigned int version)83     void serialize(Archive &ar, const unsigned int version)
84     {
85         ar & latitude;
86         ar & longitude;
87     }
88 protected:
bus_stop(const gps_position & _lat,const gps_position & _long)89     bus_stop(const gps_position & _lat, const gps_position & _long) :
90         latitude(_lat), longitude(_long)
91     {}
92 public:
bus_stop()93     bus_stop(){}
~bus_stop()94     virtual ~bus_stop(){}
95 };
96 
97 BOOST_SERIALIZATION_ASSUME_ABSTRACT(bus_stop)
98 
99 std::ostream & operator<<(std::ostream &os, const bus_stop &bs)
100 {
101     return os << bs.latitude << bs.longitude << ' ' << bs.description();
102 }
103 
104 /////////////////////////////////////////////////////////////
105 // Several kinds of bus stops
106 //
107 // illustrates serialization of derived types
108 //
109 class bus_stop_corner : public bus_stop
110 {
111     friend class boost::serialization::access;
112     std::string street1;
113     std::string street2;
description() const114     virtual std::string description() const
115     {
116         return street1 + " and " + street2;
117     }
118     template<class Archive>
serialize(Archive & ar,const unsigned int version)119     void serialize(Archive &ar, const unsigned int version)
120     {
121         // save/load base class information
122         ar & boost::serialization::base_object<bus_stop>(*this);
123         ar & street1 & street2;
124     }
125 
126 public:
bus_stop_corner()127     bus_stop_corner(){}
bus_stop_corner(const gps_position & _lat,const gps_position & _long,const std::string & _s1,const std::string & _s2)128     bus_stop_corner(const gps_position & _lat, const gps_position & _long,
129         const std::string & _s1, const std::string & _s2
130     ) :
131         bus_stop(_lat, _long), street1(_s1), street2(_s2)
132     {
133     }
134 };
135 
136 class bus_stop_destination : public bus_stop
137 {
138     friend class boost::serialization::access;
139     std::string name;
description() const140     virtual std::string description() const
141     {
142         return name;
143     }
144     template<class Archive>
serialize(Archive & ar,const unsigned int version)145     void serialize(Archive &ar, const unsigned int version)
146     {
147         ar & boost::serialization::base_object<bus_stop>(*this) & name;
148     }
149 public:
150 
bus_stop_destination()151     bus_stop_destination(){}
bus_stop_destination(const gps_position & _lat,const gps_position & _long,const std::string & _name)152     bus_stop_destination(
153         const gps_position & _lat, const gps_position & _long, const std::string & _name
154     ) :
155         bus_stop(_lat, _long), name(_name)
156     {
157     }
158 };
159 
160 /////////////////////////////////////////////////////////////
161 // a bus route is a collection of bus stops
162 //
163 // illustrates serialization of STL collection templates.
164 //
165 // illustrates serialzation of polymorphic pointer (bus stop *);
166 //
167 // illustrates storage and recovery of shared pointers is correct
168 // and efficient.  That is objects pointed to by more than one
169 // pointer are stored only once.  In such cases only one such
170 // object is restored and pointers are restored to point to it
171 //
172 class bus_route
173 {
174     friend class boost::serialization::access;
175     friend std::ostream & operator<<(std::ostream &os, const bus_route &br);
176     typedef bus_stop * bus_stop_pointer;
177     std::list<bus_stop_pointer> stops;
178     template<class Archive>
serialize(Archive & ar,const unsigned int version)179     void serialize(Archive &ar, const unsigned int version)
180     {
181         // in this program, these classes are never serialized directly but rather
182         // through a pointer to the base class bus_stop. So we need a way to be
183         // sure that the archive contains information about these derived classes.
184         //ar.template register_type<bus_stop_corner>();
185         ar.register_type(static_cast<bus_stop_corner *>(NULL));
186         //ar.template register_type<bus_stop_destination>();
187         ar.register_type(static_cast<bus_stop_destination *>(NULL));
188         // serialization of stl collections is already defined
189         // in the header
190         ar & stops;
191     }
192 public:
bus_route()193     bus_route(){}
append(bus_stop * _bs)194     void append(bus_stop *_bs)
195     {
196         stops.insert(stops.end(), _bs);
197     }
198 };
operator <<(std::ostream & os,const bus_route & br)199 std::ostream & operator<<(std::ostream &os, const bus_route &br)
200 {
201     std::list<bus_stop *>::const_iterator it;
202     // note: we're displaying the pointer to permit verification
203     // that duplicated pointers are properly restored.
204     for(it = br.stops.begin(); it != br.stops.end(); it++){
205         os << '\n' << std::hex << "0x" << *it << std::dec << ' ' << **it;
206     }
207     return os;
208 }
209 
210 /////////////////////////////////////////////////////////////
211 // a bus schedule is a collection of routes each with a starting time
212 //
213 // Illustrates serialization of STL objects(pair) in a non-intrusive way.
214 // See definition of operator<< <pair<F, S> >(ar, pair) and others in
215 // serialization.hpp
216 //
217 // illustrates nesting of serializable classes
218 //
219 // illustrates use of version number to automatically grandfather older
220 // versions of the same class.
221 
222 class bus_schedule
223 {
224 public:
225     // note: this structure was made public. because the friend declarations
226     // didn't seem to work as expected.
227     struct trip_info
228     {
229         template<class Archive>
serializebus_schedule::trip_info230         void serialize(Archive &ar, const unsigned int file_version)
231         {
232             // in versions 2 or later
233             if(file_version >= 2)
234                 // read the drivers name
235                 ar & driver;
236             // all versions have the follwing info
237             ar & hour & minute;
238         }
239 
240         // starting time
241         int hour;
242         int minute;
243         // only after system shipped was the driver's name added to the class
244         std::string driver;
245 
trip_infobus_schedule::trip_info246         trip_info(){}
trip_infobus_schedule::trip_info247         trip_info(int _h, int _m, const std::string &_d) :
248             hour(_h), minute(_m), driver(_d)
249         {}
250     };
251 private:
252     friend class boost::serialization::access;
253     friend std::ostream & operator<<(std::ostream &os, const bus_schedule &bs);
254     friend std::ostream & operator<<(std::ostream &os, const bus_schedule::trip_info &ti);
255     std::list<std::pair<trip_info, bus_route *> > schedule;
256     template<class Archive>
serialize(Archive & ar,const unsigned int version)257     void serialize(Archive &ar, const unsigned int version)
258     {
259         ar & schedule;
260     }
261 public:
append(const std::string & _d,int _h,int _m,bus_route * _br)262     void append(const std::string &_d, int _h, int _m, bus_route *_br)
263     {
264         schedule.insert(schedule.end(), std::make_pair(trip_info(_h, _m, _d), _br));
265     }
bus_schedule()266     bus_schedule(){}
267 };
268 BOOST_CLASS_VERSION(bus_schedule::trip_info, 2)
269 
operator <<(std::ostream & os,const bus_schedule::trip_info & ti)270 std::ostream & operator<<(std::ostream &os, const bus_schedule::trip_info &ti)
271 {
272     return os << '\n' << ti.hour << ':' << ti.minute << ' ' << ti.driver << ' ';
273 }
operator <<(std::ostream & os,const bus_schedule & bs)274 std::ostream & operator<<(std::ostream &os, const bus_schedule &bs)
275 {
276     std::list<std::pair<bus_schedule::trip_info, bus_route *> >::const_iterator it;
277     for(it = bs.schedule.begin(); it != bs.schedule.end(); it++){
278         os << it->first << *(it->second);
279     }
280     return os;
281 }
282 
save_schedule(const bus_schedule & s,const char * filename)283 void save_schedule(const bus_schedule &s, const char * filename){
284     // make an archive
285     std::ofstream ofs(filename);
286     boost::archive::text_oarchive oa(ofs);
287     oa << s;
288 }
289 
290 void
restore_schedule(bus_schedule & s,const char * filename)291 restore_schedule(bus_schedule &s, const char * filename)
292 {
293     // open the archive
294     std::ifstream ifs(filename);
295     boost::archive::text_iarchive ia(ifs);
296 
297     // restore the schedule from the archive
298     ia >> s;
299 }
300 
main(int argc,char * argv[])301 int main(int argc, char *argv[])
302 {
303     // make the schedule
304     bus_schedule original_schedule;
305 
306     // fill in the data
307     // make a few stops
308     bus_stop *bs0 = new bus_stop_corner(
309         gps_position(34, 135, 52.560f),
310         gps_position(134, 22, 78.30f),
311         "24th Street", "10th Avenue"
312     );
313     bus_stop *bs1 = new bus_stop_corner(
314         gps_position(35, 137, 23.456f),
315         gps_position(133, 35, 54.12f),
316         "State street", "Cathedral Vista Lane"
317     );
318     bus_stop *bs2 = new bus_stop_destination(
319         gps_position(35, 136, 15.456f),
320         gps_position(133, 32, 15.300f),
321         "White House"
322     );
323     bus_stop *bs3 = new bus_stop_destination(
324         gps_position(35, 134, 48.789f),
325         gps_position(133, 32, 16.230f),
326         "Lincoln Memorial"
327     );
328 
329     // make a  routes
330     bus_route route0;
331     route0.append(bs0);
332     route0.append(bs1);
333     route0.append(bs2);
334 
335     // add trips to schedule
336     original_schedule.append("bob", 6, 24, &route0);
337     original_schedule.append("bob", 9, 57, &route0);
338     original_schedule.append("alice", 11, 02, &route0);
339 
340     // make aother routes
341     bus_route route1;
342     route1.append(bs3);
343     route1.append(bs2);
344     route1.append(bs1);
345 
346     // add trips to schedule
347     original_schedule.append("ted", 7, 17, &route1);
348     original_schedule.append("ted", 9, 38, &route1);
349     original_schedule.append("alice", 11, 47, &route1);
350 
351     // display the complete schedule
352     std::cout << "original schedule";
353     std::cout << original_schedule;
354 
355     std::string filename(boost::archive::tmpdir());
356     filename += "/demofile.txt";
357 
358     // save the schedule
359     save_schedule(original_schedule, filename.c_str());
360 
361     // ... some time later
362     // make  a new schedule
363     bus_schedule new_schedule;
364 
365     restore_schedule(new_schedule, filename.c_str());
366 
367     // and display
368     std::cout << "\nrestored schedule";
369     std::cout << new_schedule;
370     // should be the same as the old one. (except for the pointer values)
371 
372     delete bs0;
373     delete bs1;
374     delete bs2;
375     delete bs3;
376     return 0;
377 }
378