1 
2 // Copyright (C) 2006-2009, 2012 Alexander Nasonov
3 // Copyright (C) 2012 Lorenzo Caminiti
4 // Distributed under the Boost Software License, Version 1.0
5 // (see accompanying file LICENSE_1_0.txt or a copy at
6 // http://www.boost.org/LICENSE_1_0.txt)
7 // Home at http://www.boost.org/libs/scope_exit
8 
9 #include <boost/scope_exit.hpp>
10 #include <boost/foreach.hpp>
11 #include <boost/typeof/typeof.hpp>
12 #include <boost/typeof/std/vector.hpp>
13 #include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP()
14 #include <boost/detail/lightweight_test.hpp>
15 #include <vector>
16 #include <sstream>
17 
18 struct person {
19     typedef unsigned int id_t;
20     typedef unsigned int evolution_t;
21 
22     id_t id;
23     evolution_t evolution;
24 
personperson25     person(void) : id(0), evolution(0) {}
26 
operator <<(std::ostream & o,person const & p)27     friend std::ostream& operator<<(std::ostream& o, person const& p) {
28         return o << "person(" << p.id << ", " << p.evolution << ")";
29     }
30 };
31 BOOST_TYPEOF_REGISTER_TYPE(person)
32 
33 struct world {
worldworld34     world(void) : next_id_(1) {}
35     void add_person(person const& a_person);
36 
operator <<(std::ostream & o,world const & w)37     friend std::ostream& operator<<(std::ostream& o, world const& w) {
38         o << "world(" << w.next_id_ << ", {";
39         BOOST_FOREACH(person const& p, w.persons_) {
40             o << " " << p << ", ";
41         }
42         return o << "})";
43     }
44 
45 private:
46     person::id_t next_id_;
47     std::vector<person> persons_;
48 };
BOOST_TYPEOF_REGISTER_TYPE(world)49 BOOST_TYPEOF_REGISTER_TYPE(world)
50 
51 void world::add_person(person const& a_person) {
52     persons_.push_back(a_person);
53 
54     // This block must be no-throw.
55     person& p = persons_.back();
56     person::evolution_t checkpoint = p.evolution;
57     BOOST_SCOPE_EXIT( (checkpoint) (&p) (&persons_) ) {
58         if(checkpoint == p.evolution) persons_.pop_back();
59     } BOOST_SCOPE_EXIT_END
60 
61     // ...
62 
63     checkpoint = ++p.evolution;
64 
65     // Assign new identifier to the person.
66     person::id_t const prev_id = p.id;
67     p.id = next_id_++;
68     BOOST_SCOPE_EXIT( (checkpoint) (&p) (&next_id_) (prev_id) ) {
69         if(checkpoint == p.evolution) {
70             next_id_ = p.id;
71             p.id = prev_id;
72         }
73     } BOOST_SCOPE_EXIT_END
74 
75     // ...
76 
77     checkpoint = ++p.evolution;
78 }
79 
main(void)80 int main(void) {
81     person adam, eva;
82     std::ostringstream oss;
83     oss << adam;
84     BOOST_TEST(oss.str() == "person(0, 0)");
85 
86     oss.str("");
87     oss << eva;
88     BOOST_TEST(oss.str() == "person(0, 0)");
89 
90     world w;
91     w.add_person(adam);
92     w.add_person(eva);
93     oss.str("");
94     oss << w;
95     BOOST_TEST(oss.str() == "world(3, { person(1, 2),  person(2, 2), })");
96 
97     return boost::report_errors();
98 }
99 
100