summaryrefslogtreecommitdiffstats
path: root/src/boost/libs/contract/example/mitchell02/observer
diff options
context:
space:
mode:
Diffstat (limited to 'src/boost/libs/contract/example/mitchell02/observer')
-rw-r--r--src/boost/libs/contract/example/mitchell02/observer/observer.hpp59
-rw-r--r--src/boost/libs/contract/example/mitchell02/observer/subject.hpp165
2 files changed, 224 insertions, 0 deletions
diff --git a/src/boost/libs/contract/example/mitchell02/observer/observer.hpp b/src/boost/libs/contract/example/mitchell02/observer/observer.hpp
new file mode 100644
index 000000000..aa8a91ed0
--- /dev/null
+++ b/src/boost/libs/contract/example/mitchell02/observer/observer.hpp
@@ -0,0 +1,59 @@
+
+// Copyright (C) 2008-2018 Lorenzo Caminiti
+// Distributed under the Boost Software License, Version 1.0 (see accompanying
+// file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt).
+// See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html
+
+//[mitchell02_observer
+#ifndef OBSERVER_HPP_
+#define OBSERVER_HPP_
+
+#include <boost/contract.hpp>
+#include <cassert>
+
+// Observer.
+class observer {
+ friend class subject;
+public:
+ // No inv and no bases so contracts optional if no pre, post, and override.
+
+ /* Creation */
+
+ observer() {
+ // Could have omitted contracts here (nothing to check).
+ boost::contract::check c = boost::contract::constructor(this);
+ }
+
+ virtual ~observer() {
+ // Could have omitted contracts here (nothing to check).
+ boost::contract::check c = boost::contract::destructor(this);
+ }
+
+ /* Commands */
+
+ // If up-to-date with related subject.
+ virtual bool up_to_date_with_subject(boost::contract::virtual_* v = 0)
+ const = 0;
+
+ // Update this observer.
+ virtual void update(boost::contract::virtual_* v = 0) = 0;
+};
+
+bool observer::up_to_date_with_subject(boost::contract::virtual_* v) const {
+ boost::contract::check c = boost::contract::public_function(v, this);
+ assert(false);
+ return false;
+}
+
+void observer::update(boost::contract::virtual_* v) {
+ boost::contract::check c = boost::contract::public_function(v, this)
+ .postcondition([&] {
+ BOOST_CONTRACT_ASSERT(up_to_date_with_subject()); // Up-to-date.
+ })
+ ;
+ assert(false);
+}
+
+#endif // #include guard
+//]
+
diff --git a/src/boost/libs/contract/example/mitchell02/observer/subject.hpp b/src/boost/libs/contract/example/mitchell02/observer/subject.hpp
new file mode 100644
index 000000000..12aeae71b
--- /dev/null
+++ b/src/boost/libs/contract/example/mitchell02/observer/subject.hpp
@@ -0,0 +1,165 @@
+
+// Copyright (C) 2008-2018 Lorenzo Caminiti
+// Distributed under the Boost Software License, Version 1.0 (see accompanying
+// file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt).
+// See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html
+
+//[mitchell02_subject
+#ifndef SUBJECT_HPP_
+#define SUBJECT_HPP_
+
+#include "observer.hpp"
+#include <boost/contract.hpp>
+#include <vector>
+#include <algorithm>
+#include <cassert>
+
+// Subject for observer design pattern.
+class subject {
+ friend class boost::contract::access;
+
+ void invariant() const {
+ BOOST_CONTRACT_ASSERT_AUDIT(all_observers_valid(observers())); // Valid.
+ }
+
+public:
+ /* Creation */
+
+ // Construct subject with no observer.
+ subject() {
+ // Check invariant.
+ boost::contract::check c = boost::contract::constructor(this);
+ }
+
+ // Destroy subject.
+ virtual ~subject() {
+ // Check invariant.
+ boost::contract::check c = boost::contract::destructor(this);
+ }
+
+ /* Queries */
+
+ // If given object is attached.
+ bool attached(observer const* ob) const {
+ boost::contract::check c = boost::contract::public_function(this)
+ .precondition([&] {
+ BOOST_CONTRACT_ASSERT(ob); // Not null.
+ })
+ ;
+
+ return std::find(observers_.cbegin(), observers_.cend(), ob) !=
+ observers_.cend();
+ }
+
+ /* Commands */
+
+ // Attach given object as an observer.
+ void attach(observer* ob) {
+ boost::contract::old_ptr<std::vector<observer const*> > old_observers;
+ #ifdef BOOST_CONTRACT_AUDITS
+ old_observers = BOOST_CONTRACT_OLDOF(observers());
+ #endif
+ boost::contract::check c = boost::contract::public_function(this)
+ .precondition([&] {
+ BOOST_CONTRACT_ASSERT(ob); // Not null.
+ BOOST_CONTRACT_ASSERT(!attached(ob)); // Not already attached.
+ })
+ .postcondition([&] {
+ BOOST_CONTRACT_ASSERT(attached(ob)); // Attached.
+ // Others not changed (frame rule).
+ BOOST_CONTRACT_ASSERT_AUDIT(other_observers_unchanged(
+ *old_observers, observers(), ob));
+ })
+ ;
+
+ observers_.push_back(ob);
+ }
+
+protected:
+ // Contracts could have been omitted for protected/private with no pre/post.
+
+ /* Queries */
+
+ // All observers attached to this subject.
+ std::vector<observer const*> observers() const {
+ std::vector<observer const*> obs;
+ for(std::vector<observer*>::const_iterator i = observers_.cbegin();
+ i != observers_.cend(); ++i) {
+ obs.push_back(*i);
+ }
+ return obs;
+ }
+
+ /* Commands */
+
+ // Update all attached observers.
+ void notify() {
+ // Protected members use `function` (no inv and no subcontracting).
+ boost::contract::check c = boost::contract::function()
+ .postcondition([&] {
+ // All updated.
+ BOOST_CONTRACT_ASSERT_AUDIT(all_observers_updated(observers()));
+ })
+ ;
+
+ for(std::vector<observer*>::iterator i = observers_.begin();
+ i != observers_.end(); ++i) {
+ // Class invariants ensure no null pointers in observers but class
+ // invariants not checked for non-public functions so assert here.
+ assert(*i); // Pointer not null (defensive programming).
+ (*i)->update();
+ }
+ }
+
+private:
+ /* Contract Helpers */
+
+ static bool all_observers_valid(std::vector<observer const*> const& obs) {
+ for(std::vector<observer const*>::const_iterator i = obs.cbegin();
+ i != obs.cend(); ++i) {
+ if(!*i) return false;
+ }
+ return true;
+ }
+
+ static bool other_observers_unchanged(
+ std::vector<observer const*> const& old_obs,
+ std::vector<observer const*> const& new_obs,
+ observer const* ob
+ ) {
+ // Private members use `function` (no inv and no subcontracting).
+ boost::contract::check c = boost::contract::function()
+ .precondition([&] {
+ BOOST_CONTRACT_ASSERT(ob); // Not null.
+ })
+ ;
+
+ std::vector<observer const*> remaining = new_obs;
+ std::remove(remaining.begin(), remaining.end(), ob);
+
+ std::vector<observer const*>::const_iterator remaining_it =
+ remaining.begin();
+ std::vector<observer const*>::const_iterator old_it = old_obs.begin();
+ while(remaining.cend() != remaining_it && old_obs.cend() != old_it) {
+ if(*remaining_it != *old_it) return false;
+ ++remaining_it;
+ ++old_it;
+ }
+ return true;
+ }
+
+ static bool all_observers_updated(std::vector<observer const*> const& obs) {
+ for(std::vector<observer const*>::const_iterator i = obs.cbegin();
+ i != obs.cend(); ++i) {
+ if(!*i) return false;
+ if(!(*i)->up_to_date_with_subject()) return false;
+ }
+ return true;
+ }
+
+ std::vector<observer*> observers_;
+};
+
+#endif // #include guard
+//]
+