// Copyright (C) 2009-2010 Lorenzo Caminiti. // Use, modification, and distribution is subject to the // Contract++ Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt.) // Main documentation example that illustrates most library uses. #ifndef MYVECTOR_HPP_ #define MYVECTOR_HPP_ //[ myvector_cpp // Base classes for subcontracting. #include "pushable.hpp" #include "boundable.hpp" #include "basic_begin.hpp" #include // This library. #include // For `boost::prior()`. #include // STL vector. // Wrapper that adds simple (not complete) contracts to C++ STL illustrating // most library usages. For simplicity, assume T is comparable and copyable. template class myvector: public pushable, public boundable::const_iterator>, private basic_begin::const_iterator> { // Class invariants (checked by any function with a contract). CONTRACT_INVARIANT( (static)({ // Static invariants (optional). // Static class invariants `(static)({ ... })` are optional and they // could have been omitted since they assert nothing in this example. // When present, they can only access static members. }) ({ // Non-static invariants (can access object). CONTRACT_ASSERT( (size() == 0) == empty() ); // More invariants here... }) ) public: typedef typename std::vector::size_type size_type; typedef typename std::vector::iterator iterator; typedef typename std::vector::const_iterator const_iterator; typedef typename std::vector::const_reference const_reference; // Contract for constructor. explicit myvector(size_type count): vector_(count) CONTRACT_CONSTRUCTOR( // Constructor contract macro. (class) (myvector) // Constructor signature. (public) (myvector)( (size_type)(count) ) // Never object `this` in constructor preconditions. (postcondition) ({ // Never `CONTRACT_OLDOF(this)` in constructor postconditions. CONTRACT_ASSERT( size() == count ); }) (body) ({ // Do nothing in this case. }) ) // Contractor for overloaded member (resolved by argumnet name). myvector(const myvector& right) CONTRACT_CONSTRUCTOR( (class) (myvector) (public) (myvector)( (const myvector&)(right) ) (postcondition) ({ CONTRACT_ASSERT( vector_ == right.vector_ ); }) (body) (;) ) // Deferres body definition. // Contract for destructor. virtual ~myvector(void) CONTRACT_DESTRUCTOR( // Destructor contract macro. (class) (myvector) // Destructor signature. // Must use `(void)` for no arguments. (public) (virtual) (myvector)( (void) ) // No preconditions allowed (no arguments). // No postconditions allowed (no object after destructor). (body) (;) ) // Contract for member function. void insert(iterator where, size_type count, const T& element) CONTRACT_FUNCTION( // Function contract macro. (class) (copyable)(myvector) // Function signature. // Old values for object `this` and argument `where`. (public) (void) (insert)( (copyable)(iterator)(where) (size_type)(count) (const T&)(element) ) (precondition) ({ // Function preconditions (optional). CONTRACT_ASSERT( (size() + count) <= max_size() ); // More preconditions here... }) (postcondition) ({ // Function postconditions (optional). // Any C++ code allowed in contracts (but keep it simple). // Old values of types tagged copyable via `CONTRACT_OLDOF()`. if (capacity() == CONTRACT_OLDOF(this)->capacity()) { CONTRACT_ASSERT( all_equals( boost::prior(CONTRACT_OLDOF(where)), boost::prior(CONTRACT_OLDOF(where)) + count, element) ); } // More postconditions here... }) (body) ({ // Function body (mandatory). vector_.insert(where, count, element); }) ) // Contract for constant member. const_iterator begin(void) const CONTRACT_FUNCTION( (class) (myvector) // Subcontracting for multiple inheritance. (inherit)(boundable) (inherit)(basic_begin) (public) (const_iterator) // Non-void result type. (begin)( (void) ) (const) // Constant. (postcondition) (result) ({ // Named result value. if (empty()) CONTRACT_ASSERT( result == end() ); }) (body) ({ return vector_.begin(); }) ) // Contract for overloaded member (resolved because not const). iterator begin(void) CONTRACT_FUNCTION( (class) (myvector) (public) (iterator) (begin)( (void) ) (postcondition) (result) ({ if (empty()) CONTRACT_ASSERT( result == end() ); }) (body) ( ; ) ) // Contract for operator. const_reference operator[](size_type index) const CONTRACT_FUNCTION( (class) (myvector) // Must spell operator name also in words). (public) (const_reference) (operator([], at))( (size_type)(index) ) (const) (precondition) ({ CONTRACT_ASSERT( index < size() ); }) (body) (;) ) // Main function example used in documentation. void push_back(const T& element) CONTRACT_FUNCTION( (class) (copyable)(myvector) (inherit)(pushable) (public) (void) (push_back)( (const T&)(element) ) (precondition) ({ CONTRACT_ASSERT( size() < max_size() ); }) (postcondition) ({ CONTRACT_ASSERT( size() == (CONTRACT_OLDOF(this)->size() + 1) ); }) (body) ({ vector_.push_back(element); }) ) // Contract for template plus static member function. template static bool all_equals(Iter first, Iter last, const T& element) CONTRACT_FUNCTION( (class) (myvector) (public) (template)( (class)(Iter) ) // Function template. (static) (bool) (all_equals)( // Static member. (Iter)(first) (Iter)(last) (const T&)(element) ) (precondition) ({ CONTRACT_ASSERT( first < last ); }) (body) ({ // For simplicity, let's assume T can be compared. for (Iter i = first; i < last; ++i) { if (*i != element) return false; } return true; }) ) // Similarly, complete contracts sketched here and add contracts // for all other functions (see [Crowl2006] vector example). bool empty(void) const { return vector_.empty(); } size_type size(void) const { return vector_.size(); } size_type max_size(void) const { return vector_.max_size(); } size_type capacity(void) const { return vector_.capacity(); } iterator end(void) { return vector_.end(); } const_iterator end(void) const { return vector_.end(); } const_reference back(void) const { return vector_.back(); } private: std::vector vector_; }; // Deferred constructor body definition. template CONTRACT_CONSTRUCTOR_BODY(myvector, myvector)( const myvector& right) { vector_ = right.vector_; } // Deferred destructor body definition. template CONTRACT_DESTRUCTOR_BODY(myvector, myvector)(void) { // Do nothing in this case. } // Deferred member function definition. template typename myvector::iterator myvector::CONTRACT_BODY(begin)( void) { return vector_.begin(); } // Deferred member operator definition. template typename myvector::const_reference myvector:: CONTRACT_BODY(operator([], at))( size_type index) const { return vector_[index]; } // Contract for non-member function. double abs_total(const myvector& vector) CONTRACT_FUNCTION( (double) (abs_total)( (const myvector&)(vector) ) (postcondition) (total) ({ // Result value named `total`. CONTRACT_ASSERT( total >= 0.0 ); }) (body) ({ double total = 0.0; // Block invariants can appear anywhere in code block. CONTRACT_ASSERT_BLOCK_INVARIANT( total == 0.0 ); { // Variant initialized locally to its loop. CONTRACT_INIT_LOOP_VARIANT; for (size_t i = 0; i < vector.size(); ++i) { // Block invariants used to assert loop invariants. CONTRACT_ASSERT_BLOCK_INVARIANT( i < vector.size() ); // Loop variant (can only appear in loops). CONTRACT_ASSERT_LOOP_VARIANT( vector.size() - i ); total += vector[i]; } } return total < 0.0 ? -total : total; }) ) //] #endif // #include guard