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 //[meyer97_stack4 8 // File: stack4.hpp 9 #ifndef STACK4_HPP_ 10 #define STACK4_HPP_ 11 12 #include <boost/contract.hpp> 13 14 // Dispenser with LIFO access policy and fixed max capacity. 15 template<typename T> 16 class stack4 17 #define BASES private boost::contract::constructor_precondition<stack4<T> > 18 : BASES 19 { 20 friend boost::contract::access; 21 typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; 22 #undef BASES 23 invariant() const24 void invariant() const { 25 BOOST_CONTRACT_ASSERT(count() >= 0); // Count non-negative. 26 BOOST_CONTRACT_ASSERT(count() <= capacity()); // Count bounded. 27 BOOST_CONTRACT_ASSERT(empty() == (count() == 0)); // Empty if no elem. 28 } 29 30 public: 31 /* Initialization */ 32 33 // Allocate static from a maximum of n elements. stack4(int n)34 explicit stack4(int n) : 35 boost::contract::constructor_precondition<stack4>([&] { 36 BOOST_CONTRACT_ASSERT(n >= 0); // Non-negative capacity. 37 }) 38 { 39 boost::contract::check c = boost::contract::constructor(this) __anone3f058ba0202null40 .postcondition([&] { 41 BOOST_CONTRACT_ASSERT(capacity() == n); // Capacity set. 42 }) 43 ; 44 45 capacity_ = n; 46 count_ = 0; 47 array_ = new T[n]; 48 } 49 50 // Deep copy via constructor. stack4(stack4 const & other)51 /* implicit */ stack4(stack4 const& other) { 52 boost::contract::check c = boost::contract::constructor(this) 53 .postcondition([&] { 54 BOOST_CONTRACT_ASSERT(capacity() == other.capacity()); 55 BOOST_CONTRACT_ASSERT(count() == other.count()); 56 BOOST_CONTRACT_ASSERT_AXIOM(*this == other); 57 }) 58 ; 59 60 capacity_ = other.capacity_; 61 count_ = other.count_; 62 array_ = new T[other.capacity_]; 63 for(int i = 0; i < other.count_; ++i) array_[i] = other.array_[i]; 64 } 65 66 // Deep copy via assignment. operator =(stack4 const & other)67 stack4& operator=(stack4 const& other) { 68 boost::contract::check c = boost::contract::public_function(this) 69 .postcondition([&] { 70 BOOST_CONTRACT_ASSERT(capacity() == other.capacity()); 71 BOOST_CONTRACT_ASSERT(count() == other.count()); 72 BOOST_CONTRACT_ASSERT_AXIOM(*this == other); 73 }) 74 ; 75 76 delete[] array_; 77 capacity_ = other.capacity_; 78 count_ = other.count_; 79 array_ = new T[other.capacity_]; 80 for(int i = 0; i < other.count_; ++i) array_[i] = other.array_[i]; 81 return *this; 82 } 83 84 // Destroy this stack. ~stack4()85 virtual ~stack4() { 86 // Check invariants. 87 boost::contract::check c = boost::contract::destructor(this); 88 delete[] array_; 89 } 90 91 /* Access */ 92 93 // Max number of stack elements. capacity() const94 int capacity() const { 95 // Check invariants. 96 boost::contract::check c = boost::contract::public_function(this); 97 return capacity_; 98 } 99 100 // Number of stack elements. count() const101 int count() const { 102 // Check invariants. 103 boost::contract::check c = boost::contract::public_function(this); 104 return count_; 105 } 106 107 // Top element. item() const108 T const& item() const { 109 boost::contract::check c = boost::contract::public_function(this) 110 .precondition([&] { 111 BOOST_CONTRACT_ASSERT(!empty()); // Not empty (i.e., count > 0). 112 }) 113 ; 114 115 return array_[count_ - 1]; 116 } 117 118 /* Status Report */ 119 120 // Is stack empty? empty() const121 bool empty() const { 122 bool result; 123 boost::contract::check c = boost::contract::public_function(this) 124 .postcondition([&] { 125 // Empty definition. 126 BOOST_CONTRACT_ASSERT(result == (count() == 0)); 127 }) 128 ; 129 130 return result = (count_ == 0); 131 } 132 133 // Is stack full? full() const134 bool full() const { 135 bool result; 136 boost::contract::check c = boost::contract::public_function(this) 137 .postcondition([&] { 138 BOOST_CONTRACT_ASSERT( // Full definition. 139 result == (count() == capacity())); 140 }) 141 ; 142 143 return result = (count_ == capacity_); 144 } 145 146 /* Element Change */ 147 148 // Add x on top. put(T const & x)149 void put(T const& x) { 150 boost::contract::old_ptr<int> old_count = BOOST_CONTRACT_OLDOF(count()); 151 boost::contract::check c = boost::contract::public_function(this) 152 .precondition([&] { 153 BOOST_CONTRACT_ASSERT(!full()); // Not full. 154 }) 155 .postcondition([&] { 156 BOOST_CONTRACT_ASSERT(!empty()); // Not empty. 157 BOOST_CONTRACT_ASSERT(item() == x); // Added to top. 158 BOOST_CONTRACT_ASSERT(count() == *old_count + 1); // One more. 159 }) 160 ; 161 162 array_[count_++] = x; 163 } 164 165 // Remove top element. remove()166 void remove() { 167 boost::contract::old_ptr<int> old_count = BOOST_CONTRACT_OLDOF(count()); 168 boost::contract::check c = boost::contract::public_function(this) 169 .precondition([&] { 170 BOOST_CONTRACT_ASSERT(!empty()); // Not empty (i.e., count > 0). 171 }) 172 .postcondition([&] { 173 BOOST_CONTRACT_ASSERT(!full()); // Not full. 174 BOOST_CONTRACT_ASSERT(count() == *old_count - 1); // One less. 175 }) 176 ; 177 178 --count_; 179 } 180 181 /* Friend Helpers */ 182 operator ==(stack4 const & left,stack4 const & right)183 friend bool operator==(stack4 const& left, stack4 const& right) { 184 boost::contract::check inv1 = boost::contract::public_function(&left); 185 boost::contract::check inv2 = boost::contract::public_function(&right); 186 if(left.count_ != right.count_) return false; 187 for(int i = 0; i < left.count_; ++i) { 188 if(left.array_[i] != right.array_[i]) return false; 189 } 190 return true; 191 } 192 193 private: 194 int capacity_; 195 int count_; 196 T* array_; // Internally use C-style array. 197 }; 198 199 #endif // #include guard 200 //] 201 202