• 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_simple_queue
8 #include <boost/contract.hpp>
9 #include <boost/optional.hpp>
10 #include <vector>
11 #include <cassert>
12 
13 template<typename T>
14 class simple_queue
15     #define BASES private boost::contract::constructor_precondition< \
16             simple_queue<T> >
17     : BASES
18 {
19     friend class boost::contract::access;
20 
21     typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types;
22     #undef BASES
23 
invariant() const24     void invariant() const {
25         BOOST_CONTRACT_ASSERT(count() >= 0); // Non-negative count.
26     }
27 
28 public:
29     /* Creation */
30 
31     // Create empty queue.
simple_queue(int a_capacity)32     explicit simple_queue(int a_capacity) :
33         boost::contract::constructor_precondition<simple_queue>([&] {
34             BOOST_CONTRACT_ASSERT(a_capacity > 0); // Positive capacity.
35         })
36     {
37         boost::contract::check c = boost::contract::constructor(this)
__anon1d9f74c00202null38             .postcondition([&] {
39                 // Capacity set.
40                 BOOST_CONTRACT_ASSERT(capacity() == a_capacity);
41                 BOOST_CONTRACT_ASSERT(is_empty()); // Empty.
42             })
43         ;
44 
45         items_.reserve(a_capacity);
46     }
47 
48     // Destroy queue.
~simple_queue()49     virtual ~simple_queue() {
50         // Check invariants.
51         boost::contract::check c = boost::contract::destructor(this);
52     }
53 
54     /* Basic Queries */
55 
56     // Items in queue (in their order).
57     // (Somewhat exposes implementation but allows to check more contracts.)
items() const58     std::vector<T> const& items() const {
59         // Check invariants.
60         boost::contract::check c = boost::contract::public_function(this);
61         return items_;
62     }
63 
64     // Max number of items queue can hold.
capacity() const65     int capacity() const {
66         // Check invariants.
67         boost::contract::check c = boost::contract::public_function(this);
68         return items_.capacity();
69     }
70 
71     /* Derived Queries */
72 
73     // Number of items.
count() const74     int count() const {
75         int result;
76         boost::contract::check c = boost::contract::public_function(this)
77             .postcondition([&] {
78                 // Return items count.
79                 BOOST_CONTRACT_ASSERT(result == int(items().size()));
80             })
81         ;
82 
83         return result = items_.size();
84     }
85 
86     // Item at head.
head() const87     T const& head() const {
88         boost::optional<T const&> result;
89         boost::contract::check c = boost::contract::public_function(this)
90             .precondition([&] {
91                 BOOST_CONTRACT_ASSERT(!is_empty()); // Not empty.
92             })
93             .postcondition([&] {
94                 // Return item on top.
95                 BOOST_CONTRACT_ASSERT(*result == items().at(0));
96             })
97         ;
98 
99         return *(result = items_.at(0));
100     }
101 
102     // If queue contains no item.
is_empty() const103     bool is_empty() const {
104         bool result;
105         boost::contract::check c = boost::contract::public_function(this)
106             .postcondition([&] {
107                 // Consistent with count.
108                 BOOST_CONTRACT_ASSERT(result == (count() == 0));
109             })
110         ;
111 
112         return result = (items_.size() == 0);
113     }
114 
115     // If queue has no room for another item.
is_full() const116     bool is_full() const {
117         bool result;
118         boost::contract::check c = boost::contract::public_function(this)
119             .postcondition([&] {
120                 BOOST_CONTRACT_ASSERT( // Consistent with size and capacity.
121                         result == (capacity() == int(items().size())));
122             })
123         ;
124 
125         return result = (items_.size() == items_.capacity());
126     }
127 
128     /* Commands */
129 
130     // Remove head itme and shift all other items.
remove()131     void remove() {
132         // Expensive all_equal postcond. and old_items copy might be skipped.
133         boost::contract::old_ptr<std::vector<T> > old_items;
134             #ifdef BOOST_CONTRACT_AUDIITS
135                 = BOOST_CONTRACT_OLDOF(items())
136             #endif // Else, leave old pointer null...
137         ;
138         boost::contract::old_ptr<int> old_count = BOOST_CONTRACT_OLDOF(count());
139         boost::contract::check c = boost::contract::public_function(this)
140             .precondition([&] {
141                 BOOST_CONTRACT_ASSERT(!is_empty()); // Not empty.
142             })
143             .postcondition([&] {
144                 BOOST_CONTRACT_ASSERT(count() == *old_count - 1); // Count dec.
145                 // ...following skipped #ifndef AUDITS.
146                 if(old_items) all_equal(items(), *old_items, /* shifted = */ 1);
147             })
148         ;
149 
150         items_.erase(items_.begin());
151     }
152 
153     // Add item to tail.
put(T const & item)154     void put(T const& item) {
155         // Expensive all_equal postcond. and old_items copy might be skipped.
156         boost::contract::old_ptr<std::vector<T> > old_items;
157             #ifdef BOOST_CONTRACT_AUDITS
158                 = BOOST_CONTRACT_OLDOF(items())
159             #endif // Else, leave old pointer null...
160         ;
161         boost::contract::old_ptr<int> old_count = BOOST_CONTRACT_OLDOF(count());
162         boost::contract::check c = boost::contract::public_function(this)
163             .precondition([&] {
164                 BOOST_CONTRACT_ASSERT(count() < capacity()); // Room for add.
165             })
166             .postcondition([&] {
167                 BOOST_CONTRACT_ASSERT(count() == *old_count + 1); // Count inc.
168                 // Second to last item.
169                 BOOST_CONTRACT_ASSERT(items().at(count() - 1) == item);
170                 // ...following skipped #ifndef AUDITS.
171                 if(old_items) all_equal(items(), *old_items);
172             })
173         ;
174 
175         items_.push_back(item);
176     }
177 
178 private:
179     // Contract helper.
all_equal(std::vector<T> const & left,std::vector<T> const & right,unsigned offset=0)180     static bool all_equal(std::vector<T> const& left,
181             std::vector<T> const& right, unsigned offset = 0) {
182         boost::contract::check c = boost::contract::function()
183             .precondition([&] {
184                 // Correct offset.
185                 BOOST_CONTRACT_ASSERT(right.size() == left.size() + offset);
186             })
187         ;
188 
189         for(unsigned i = offset; i < right.size(); ++i) {
190             if(left.at(i - offset) != right.at(i)) return false;
191         }
192         return true;
193     }
194 
195     std::vector<T> items_;
196 };
197 
main()198 int main() {
199     simple_queue<int> q(10);
200     q.put(123);
201     q.put(456);
202 
203     assert(q.capacity() == 10);
204     assert(q.head() == 123);
205 
206     assert(!q.is_empty());
207     assert(!q.is_full());
208 
209     std::vector<int> const& items = q.items();
210     assert(items.at(0) == 123);
211     assert(items.at(1) == 456);
212 
213     q.remove();
214     assert(q.count() == 1);
215 
216     return 0;
217 }
218 //]
219 
220