• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 // Copyright (C) 2008-2018 Lorenzo Caminiti
3 // Distributed under the Boost Software License, Version 1.0 (see accompanying
4 // file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt).
5 // See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html
6 
7 //[mitchell02_courier
8 #include <boost/contract.hpp>
9 #include <string>
10 #include <cassert>
11 
12 struct package {
13     double weight_kg;
14     std::string location;
15     double accepted_hour;
16     double delivered_hour;
17 
packagepackage18     explicit package(
19         double _weight_kg,
20         std::string const& _location = "",
21         double _accepted_hour = 0.0,
22         double _delivered_hour = 0.0
23     ) :
24         weight_kg(_weight_kg),
25         location(_location),
26         accepted_hour(_accepted_hour),
27         delivered_hour(_delivered_hour)
28     {}
29 };
30 
31 // Courier for package delivery.
32 class courier
33     #define BASES private boost::contract::constructor_precondition<courier>
34     : BASES
35 {
36     friend class boost::contract::access;
37 
38     typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types;
39     #undef BASES
40 
static_invariant()41     static void static_invariant() {
42         // Positive min. insurance.
43         BOOST_CONTRACT_ASSERT(min_insurance_usd >= 0.0);
44     }
45 
invariant() const46     void invariant() const {
47         // Above min. insurance.
48         BOOST_CONTRACT_ASSERT(insurance_cover_usd() >= min_insurance_usd);
49     }
50 
51 public:
52     static double min_insurance_usd;
53 
54     /* Creation */
55 
56     // Create courier with specified insurance value.
courier(double _insurance_cover_usd=min_insurance_usd)57     explicit courier(double _insurance_cover_usd = min_insurance_usd) :
58         boost::contract::constructor_precondition<courier>([&] {
59             // Positive insurance.
60             BOOST_CONTRACT_ASSERT(_insurance_cover_usd >= 0.0);
61         }),
62         insurance_cover_usd_(_insurance_cover_usd)
63     {
64         // Check invariants.
65         boost::contract::check c = boost::contract::constructor(this);
66     }
67 
68     // Destroy courier.
~courier()69     virtual ~courier() {
70         // Check invariants.
71         boost::contract::check c = boost::contract::destructor(this);
72     }
73 
74     /* Queries */
75 
76     // Return insurance cover.
insurance_cover_usd() const77     double insurance_cover_usd() const {
78         // Check invariants.
79         boost::contract::check c = boost::contract::public_function(this);
80         return insurance_cover_usd_;
81     }
82 
83     /* Commands */
84 
85     // Deliver package to destination.
deliver(package & package_delivery,std::string const & destination,boost::contract::virtual_ * v=0)86     virtual void deliver(
87         package& package_delivery,
88         std::string const& destination,
89         boost::contract::virtual_* v = 0
90     ) {
91         boost::contract::check c = boost::contract::public_function(v, this)
92             .precondition([&] {
93                 // Within max weight of this delivery.
94                 BOOST_CONTRACT_ASSERT(package_delivery.weight_kg < 5.0);
95             })
96             .postcondition([&] {
97                 // Within max delivery type.
98                 BOOST_CONTRACT_ASSERT(double(package_delivery.delivered_hour -
99                         package_delivery.accepted_hour) <= 3.0);
100                 // Delivered at destination.
101                 BOOST_CONTRACT_ASSERT(package_delivery.location == destination);
102             })
103         ;
104 
105         package_delivery.location = destination;
106         // Delivery takes 2.5 hours.
107         package_delivery.delivered_hour = package_delivery.accepted_hour + 2.5;
108     }
109 
110 private:
111     double insurance_cover_usd_;
112 };
113 
114 double courier::min_insurance_usd = 10.0e+6;
115 
116 // Different courier for package delivery.
117 class different_courier
118     #define BASES private boost::contract::constructor_precondition< \
119             different_courier>, public courier
120     : BASES
121 {
122     friend class boost::contract::access;
123 
124     typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; // Subcontracting.
125     #undef BASES
126 
static_invariant()127     static void static_invariant() {
128         BOOST_CONTRACT_ASSERT( // Better insurance amount.
129                 different_insurance_usd >= courier::min_insurance_usd);
130     }
131 
invariant() const132     void invariant() const {
133         // Above different insurance value.
134         BOOST_CONTRACT_ASSERT(insurance_cover_usd() >= different_insurance_usd);
135     }
136 
137     BOOST_CONTRACT_OVERRIDE(deliver)
138 
139 public:
140     static double different_insurance_usd;
141 
142     /* Creation */
143 
144     // Create courier with specified insurance value.
different_courier(double insurance_cover_usd=different_insurance_usd)145     explicit different_courier(
146             double insurance_cover_usd = different_insurance_usd) :
147         boost::contract::constructor_precondition<different_courier>([&] {
148             // Positive insurance value.
149             BOOST_CONTRACT_ASSERT(insurance_cover_usd > 0.0);
150         }),
151         courier(insurance_cover_usd)
152     {
153         // Check invariants.
154         boost::contract::check c = boost::contract::constructor(this);
155     }
156 
157     // Destroy courier.
~different_courier()158     virtual ~different_courier() {
159         // Check invariants.
160         boost::contract::check c = boost::contract::destructor(this);
161     }
162 
163     /* Commands */
164 
deliver(package & package_delivery,std::string const & destination,boost::contract::virtual_ * v=0)165     virtual void deliver(
166         package& package_delivery,
167         std::string const& destination,
168         boost::contract::virtual_* v = 0
169     ) /* override */ {
170         boost::contract::check c = boost::contract::public_function<
171             override_deliver
172         >(v, &different_courier::deliver, this, package_delivery, destination)
173             .precondition([&] {
174                 // Package can weight more (weaker precondition).
175                 BOOST_CONTRACT_ASSERT(package_delivery.weight_kg <= 8.0);
176             })
177             .postcondition([&] {
178                 // Faster delivery (stronger postcondition).
179                 BOOST_CONTRACT_ASSERT(double(package_delivery.delivered_hour -
180                         package_delivery.accepted_hour) <= 2.0);
181                 // Inherited "delivery at destination" postcondition.
182             })
183         ;
184 
185         package_delivery.location = destination;
186         // Delivery takes 0.5 hours.
187         package_delivery.delivered_hour = package_delivery.accepted_hour + 0.5;
188     }
189 };
190 
191 double different_courier::different_insurance_usd = 20.0e+6;
192 
main()193 int main() {
194     package cups(3.6, "store");
195     courier c;
196     c.deliver(cups, "home");
197     assert(cups.location == "home");
198 
199     package desk(7.2, "store");
200     different_courier dc;
201     dc.deliver(desk, "office");
202     assert(desk.location == "office");
203 
204     return 0;
205 }
206 //]
207 
208