name_list.cpp 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  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. //[mitchell02_name_list
  6. #include <boost/contract.hpp>
  7. #include <string>
  8. #include <vector>
  9. #include <algorithm>
  10. #include <cassert>
  11. // List of names.
  12. class name_list {
  13. friend class boost::contract::access;
  14. void invariant() const {
  15. BOOST_CONTRACT_ASSERT(count() >= 0); // Non-negative count.
  16. }
  17. public:
  18. /* Creation */
  19. // Create an empty list.
  20. name_list() {
  21. boost::contract::check c = boost::contract::constructor(this)
  22. .postcondition([&] {
  23. BOOST_CONTRACT_ASSERT(count() == 0); // Empty list.
  24. })
  25. ;
  26. }
  27. // Destroy list.
  28. virtual ~name_list() {
  29. // Check invariants.
  30. boost::contract::check c = boost::contract::destructor(this);
  31. }
  32. /* Basic Queries */
  33. // Number of names in list.
  34. int count() const {
  35. // Check invariants.
  36. boost::contract::check c = boost::contract::public_function(this);
  37. return names_.size();
  38. }
  39. // Is name in list?
  40. bool has(std::string const& name) const {
  41. bool result;
  42. boost::contract::check c = boost::contract::public_function(this)
  43. .postcondition([&] {
  44. // If empty, has not.
  45. if(count() == 0) BOOST_CONTRACT_ASSERT(!result);
  46. })
  47. ;
  48. return result = names_.cend() != std::find(names_.cbegin(),
  49. names_.cend(), name);
  50. }
  51. /* Commands */
  52. // Add name to list, if name not already in list.
  53. virtual void put(std::string const& name,
  54. boost::contract::virtual_* v = 0) {
  55. boost::contract::old_ptr<bool> old_has_name =
  56. BOOST_CONTRACT_OLDOF(v, has(name));
  57. boost::contract::old_ptr<int> old_count =
  58. BOOST_CONTRACT_OLDOF(v, count());
  59. boost::contract::check c = boost::contract::public_function(v, this)
  60. .precondition([&] {
  61. BOOST_CONTRACT_ASSERT(!has(name)); // Not already in list.
  62. })
  63. .postcondition([&] {
  64. if(!*old_has_name) { // If-guard allows to relax subcontracts.
  65. BOOST_CONTRACT_ASSERT(has(name)); // Name in list.
  66. BOOST_CONTRACT_ASSERT(count() == *old_count + 1); // Inc.
  67. }
  68. })
  69. ;
  70. names_.push_back(name);
  71. }
  72. private:
  73. std::vector<std::string> names_;
  74. };
  75. class relaxed_name_list
  76. #define BASES public name_list
  77. : BASES
  78. {
  79. friend class boost::contract::access;
  80. typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; // Subcontracting.
  81. #undef BASES
  82. BOOST_CONTRACT_OVERRIDE(put);
  83. public:
  84. /* Commands */
  85. // Add name to list, or do nothing if name already in list (relaxed).
  86. void put(std::string const& name,
  87. boost::contract::virtual_* v = 0) /* override */ {
  88. boost::contract::old_ptr<bool> old_has_name =
  89. BOOST_CONTRACT_OLDOF(v, has(name));
  90. boost::contract::old_ptr<int> old_count =
  91. BOOST_CONTRACT_OLDOF(v, count());
  92. boost::contract::check c = boost::contract::public_function<
  93. override_put>(v, &relaxed_name_list::put, this, name)
  94. .precondition([&] { // Relax inherited preconditions.
  95. BOOST_CONTRACT_ASSERT(has(name)); // Already in list.
  96. })
  97. .postcondition([&] { // Inherited post. not checked given if-guard.
  98. if(*old_has_name) {
  99. // Count unchanged if name already in list.
  100. BOOST_CONTRACT_ASSERT(count() == *old_count);
  101. }
  102. })
  103. ;
  104. if(!has(name)) name_list::put(name); // Else, do nothing.
  105. }
  106. };
  107. int main() {
  108. std::string const js = "John Smith";
  109. relaxed_name_list rl;
  110. rl.put(js);
  111. assert(rl.has(js));
  112. rl.put(js); // OK, relaxed contracts allow calling this again (do nothing).
  113. name_list nl;
  114. nl.put(js);
  115. assert(nl.has(js));
  116. // nl.put(js); // Error, contracts do not allow calling this again.
  117. return 0;
  118. }
  119. //]