stack4.hpp 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. // Copyright (C) 2008-2018 Lorenzo Caminiti
  2. // Distributed under the Boost Software License, Version 1.0 (see accompanying
  3. // file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt).
  4. // See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html
  5. //[meyer97_stack4
  6. // File: stack4.hpp
  7. #ifndef STACK4_HPP_
  8. #define STACK4_HPP_
  9. #include <boost/contract.hpp>
  10. // Dispenser with LIFO access policy and fixed max capacity.
  11. template<typename T>
  12. class stack4
  13. #define BASES private boost::contract::constructor_precondition<stack4<T> >
  14. : BASES
  15. {
  16. friend boost::contract::access;
  17. typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types;
  18. #undef BASES
  19. void invariant() const {
  20. BOOST_CONTRACT_ASSERT(count() >= 0); // Count non-negative.
  21. BOOST_CONTRACT_ASSERT(count() <= capacity()); // Count bounded.
  22. BOOST_CONTRACT_ASSERT(empty() == (count() == 0)); // Empty if no elem.
  23. }
  24. public:
  25. /* Initialization */
  26. // Allocate static from a maximum of n elements.
  27. explicit stack4(int n) :
  28. boost::contract::constructor_precondition<stack4>([&] {
  29. BOOST_CONTRACT_ASSERT(n >= 0); // Non-negative capacity.
  30. })
  31. {
  32. boost::contract::check c = boost::contract::constructor(this)
  33. .postcondition([&] {
  34. BOOST_CONTRACT_ASSERT(capacity() == n); // Capacity set.
  35. })
  36. ;
  37. capacity_ = n;
  38. count_ = 0;
  39. array_ = new T[n];
  40. }
  41. // Deep copy via constructor.
  42. /* implicit */ stack4(stack4 const& other) {
  43. boost::contract::check c = boost::contract::constructor(this)
  44. .postcondition([&] {
  45. BOOST_CONTRACT_ASSERT(capacity() == other.capacity());
  46. BOOST_CONTRACT_ASSERT(count() == other.count());
  47. BOOST_CONTRACT_ASSERT_AXIOM(*this == other);
  48. })
  49. ;
  50. capacity_ = other.capacity_;
  51. count_ = other.count_;
  52. array_ = new T[other.capacity_];
  53. for(int i = 0; i < other.count_; ++i) array_[i] = other.array_[i];
  54. }
  55. // Deep copy via assignment.
  56. stack4& operator=(stack4 const& other) {
  57. boost::contract::check c = boost::contract::public_function(this)
  58. .postcondition([&] {
  59. BOOST_CONTRACT_ASSERT(capacity() == other.capacity());
  60. BOOST_CONTRACT_ASSERT(count() == other.count());
  61. BOOST_CONTRACT_ASSERT_AXIOM(*this == other);
  62. })
  63. ;
  64. delete[] array_;
  65. capacity_ = other.capacity_;
  66. count_ = other.count_;
  67. array_ = new T[other.capacity_];
  68. for(int i = 0; i < other.count_; ++i) array_[i] = other.array_[i];
  69. return *this;
  70. }
  71. // Destroy this stack.
  72. virtual ~stack4() {
  73. // Check invariants.
  74. boost::contract::check c = boost::contract::destructor(this);
  75. delete[] array_;
  76. }
  77. /* Access */
  78. // Max number of stack elements.
  79. int capacity() const {
  80. // Check invariants.
  81. boost::contract::check c = boost::contract::public_function(this);
  82. return capacity_;
  83. }
  84. // Number of stack elements.
  85. int count() const {
  86. // Check invariants.
  87. boost::contract::check c = boost::contract::public_function(this);
  88. return count_;
  89. }
  90. // Top element.
  91. T const& item() const {
  92. boost::contract::check c = boost::contract::public_function(this)
  93. .precondition([&] {
  94. BOOST_CONTRACT_ASSERT(!empty()); // Not empty (i.e., count > 0).
  95. })
  96. ;
  97. return array_[count_ - 1];
  98. }
  99. /* Status Report */
  100. // Is stack empty?
  101. bool empty() const {
  102. bool result;
  103. boost::contract::check c = boost::contract::public_function(this)
  104. .postcondition([&] {
  105. // Empty definition.
  106. BOOST_CONTRACT_ASSERT(result == (count() == 0));
  107. })
  108. ;
  109. return result = (count_ == 0);
  110. }
  111. // Is stack full?
  112. bool full() const {
  113. bool result;
  114. boost::contract::check c = boost::contract::public_function(this)
  115. .postcondition([&] {
  116. BOOST_CONTRACT_ASSERT( // Full definition.
  117. result == (count() == capacity()));
  118. })
  119. ;
  120. return result = (count_ == capacity_);
  121. }
  122. /* Element Change */
  123. // Add x on top.
  124. void put(T const& x) {
  125. boost::contract::old_ptr<int> old_count = BOOST_CONTRACT_OLDOF(count());
  126. boost::contract::check c = boost::contract::public_function(this)
  127. .precondition([&] {
  128. BOOST_CONTRACT_ASSERT(!full()); // Not full.
  129. })
  130. .postcondition([&] {
  131. BOOST_CONTRACT_ASSERT(!empty()); // Not empty.
  132. BOOST_CONTRACT_ASSERT(item() == x); // Added to top.
  133. BOOST_CONTRACT_ASSERT(count() == *old_count + 1); // One more.
  134. })
  135. ;
  136. array_[count_++] = x;
  137. }
  138. // Remove top element.
  139. void remove() {
  140. boost::contract::old_ptr<int> old_count = BOOST_CONTRACT_OLDOF(count());
  141. boost::contract::check c = boost::contract::public_function(this)
  142. .precondition([&] {
  143. BOOST_CONTRACT_ASSERT(!empty()); // Not empty (i.e., count > 0).
  144. })
  145. .postcondition([&] {
  146. BOOST_CONTRACT_ASSERT(!full()); // Not full.
  147. BOOST_CONTRACT_ASSERT(count() == *old_count - 1); // One less.
  148. })
  149. ;
  150. --count_;
  151. }
  152. /* Friend Helpers */
  153. friend bool operator==(stack4 const& left, stack4 const& right) {
  154. boost::contract::check inv1 = boost::contract::public_function(&left);
  155. boost::contract::check inv2 = boost::contract::public_function(&right);
  156. if(left.count_ != right.count_) return false;
  157. for(int i = 0; i < left.count_; ++i) {
  158. if(left.array_[i] != right.array_[i]) return false;
  159. }
  160. return true;
  161. }
  162. private:
  163. int capacity_;
  164. int count_;
  165. T* array_; // Internally use C-style array.
  166. };
  167. #endif // #include guard
  168. //]