From be3a974847a5b6e4bf071fc13ce7222e69d1a328 Mon Sep 17 00:00:00 2001 From: Lorenzo Caminiti Date: Sat, 13 Jun 2015 21:19:20 -0700 Subject: [PATCH] implemented call_if --- Jamroot | 3 +- example/Jamfile.v2 | 39 +- example/n1962/vector.cpp | 600 +++++++++++++++++++++++++++++ example/n1962/vector_n1962.hpp | 499 ++++++++++++++++++++++++ include/boost/contract.hpp | 1 + include/boost/contract/call_if.hpp | 127 ++++++ test/Jamfile.v2 | 77 ++-- test/call_if/equal_to.cpp | 75 ++++ test/call_if/equal_to_cxx14.cpp | 48 +++ test/call_if/false_.cpp | 57 +++ test/call_if/false_void.cpp | 47 +++ test/call_if/myadvance_cxx14.cpp | 115 ++++++ test/call_if/true_.cpp | 59 +++ test/call_if/true_void.cpp | 56 +++ 14 files changed, 1764 insertions(+), 39 deletions(-) create mode 100644 example/n1962/vector.cpp create mode 100644 example/n1962/vector_n1962.hpp create mode 100644 include/boost/contract/call_if.hpp create mode 100644 test/call_if/equal_to.cpp create mode 100644 test/call_if/equal_to_cxx14.cpp create mode 100644 test/call_if/false_.cpp create mode 100644 test/call_if/false_void.cpp create mode 100644 test/call_if/myadvance_cxx14.cpp create mode 100644 test/call_if/true_.cpp create mode 100644 test/call_if/true_void.cpp diff --git a/Jamroot b/Jamroot index c7b354c..97dfc3d 100644 --- a/Jamroot +++ b/Jamroot @@ -2,6 +2,8 @@ import testing ; import os ; +# Following `subdir-...` create targets named "subdir_name-file_name". + rule subdir-run ( subdir : cpp_fname : requirements * ) { run $(subdir)/$(cpp_fname).cpp : : : $(subdir) $(requirements) : @@ -19,7 +21,6 @@ if ! [ os.environ BOOST_ROOT ] { } local BOOST_ROOT = [ os.environ BOOST_ROOT ] ; echo "Using Boost libraries from (see $BOOST_ROOT): $(BOOST_ROOT)" ; - use-project boost : $(BOOST_ROOT) ; project diff --git a/example/Jamfile.v2 b/example/Jamfile.v2 index 3af9d3f..841d486 100644 --- a/example/Jamfile.v2 +++ b/example/Jamfile.v2 @@ -1,18 +1,29 @@ -subdir-run meyer97 : stack4_main ; -subdir-run meyer97 : stack3 ; +test-suite meyer97 : + [ subdir-run meyer97 : stack4_main ] + [ subdir-run meyer97 : stack3 ] +; -subdir-run mitchell02 : stack ; -subdir-run mitchell02 : simple_queue ; -subdir-run mitchell02 : dictionary ; -subdir-run mitchell02 : customer_manager ; -subdir-run mitchell02 : name_list ; -subdir-run mitchell02 : courier ; -subdir-run mitchell02 : observer_main ; -subdir-run mitchell02 : counter_main ; +test-suite mitchell02 : + [ subdir-run mitchell02 : stack ] + [ subdir-run mitchell02 : simple_queue ] + [ subdir-run mitchell02 : dictionary ] + [ subdir-run mitchell02 : customer_manager ] + [ subdir-run mitchell02 : name_list ] + [ subdir-run mitchell02 : courier ] + [ subdir-run mitchell02 : observer_main ] + [ subdir-run mitchell02 : counter_main ] +; -subdir-run cline90 : stack ; -subdir-run cline90 : vector_main ; -subdir-run cline90 : vstack ; -subdir-run cline90 : calendar ; +test-suite cline90 : + [ subdir-run cline90 : stack ] + [ subdir-run cline90 : vector_main ] + [ subdir-run cline90 : vstack ] + [ subdir-run cline90 : calendar ] +; + +test-suite n1962 : + [ subdir-run n1962 : vector ] +; +explicit n1962 ; # TODO: Remove this... diff --git a/example/n1962/vector.cpp b/example/n1962/vector.cpp new file mode 100644 index 0000000..9da3c98 --- /dev/null +++ b/example/n1962/vector.cpp @@ -0,0 +1,600 @@ + +#include +#include +#include +#include +#include +#include + +template > +class vector { +public: + typedef typename std::vector::allocator_type allocator_type; + typedef typename std::vector::pointer pointer; + typedef typename std::vector::const_pointer const_pointer; + typedef typename std::vector::reference reference; + typedef typename std::vector::const_reference const_reference; + typedef typename std::vector::value_type value_type; + typedef typename std::vector::iterator iterator; + typedef typename std::vector::const_iterator const_iterator; + typedef typename std::vector::size_type size_type; + typedef typename std::vector::difference_type difference_type; + typedef typename std::vector::reverse_iterator reverse_iterator; + typedef typename std::vector::const_reverse_iterator + const_reverse_iterator; + + void invariant() const { + BOOST_CONTRACT_ASSERT(empty() == (size() == 0)); + BOOST_CONTRACT_ASSERT(std::distance(cbegin(), cend()) == int(size())); + BOOST_CONTRACT_ASSERT(std::distance(rcbegin(), rcend()) == int(size())); + BOOST_CONTRACT_ASSERT(size() <= capacity()); + BOOST_CONTRACT_ASSERT(capacity() <= max_size()); + } + + vector() : vect_() { + auto c = boost::contract::constructor(this) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(!empty()); + }) + ; + } + + explicit vector(Alloc const& allocator) : vect_(allocator) { + auto c = boost::contract::constructor(this) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(empty()); + BOOST_CONTRACT_ASSERT(get_allocator() == allocator); + }) + ; + } + + explicit vector(size_type count) : vect_(count) { + auto c = boost::contract::constructor(this) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(size() == count); +// BOOST_CONTRACT_ASSERT( +// boost::contract::check_if >( +// boost::bind(&boost::algorithm::all_of_equal, cbegin(), +// cend(), boost::cref(T())) +// ) +// ); + }) + ; + } + + vector(size_type count, T const& value) : vect_(count, value) { + auto c = boost::contract::constructor(this) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(size() == count); + BOOST_CONTRACT_ASSERT( + boost::contract::check_if >( + boost::bind(&boost::algorithm::all_of_equal, cbegin(), + cend(), boost::cref(value)) + ) + ); + }) + ; + } + + template + vector(InputIter first, InputIter last) : vect_(first, last) { + auto c = boost::contract::construcotr(this) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(std::distance(first, last) == + int(size())); + }) + ; + } + + template + vector(InputIter first, InputIter last, Alloc const& allocator) : + vect_(first, last, allocator) { + auto c = boost::contract::construcotr(this) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(std::distance(first, last) == + int(size())); + BOOST_CONTRACT_ASSERT(get_allocator() == allocator); + }) + ; + } + + /* implicit */ vector(vector const& other) : vect_(other.vect_) { + auto c = boost::contract::constructor(this) + .postcondition([&] { + BOOST_CONTRACT_ASSERT( + boost::contract::check_if >( + boost::bind(&std::equal_to, boost::cref(*this), + boost::cref(other)) + ) + ); + }) + ; + } + + vector& operator=(vector const& other) { + boost::optional result; + auto c = boost::contract::public_function(this) + .postcondition([&] { + BOOST_CONTRACT_ASSERT( + boost::contract::check_if >( + boost::bind(&std::equal_to, boost::cref(*this), + boost::cref(other)) + ) + ); + BOOST_CONTRACT_ASSERT( + boost::contract::check_if >( + boost::bind(&std::equal_to, boost::cref(*result), + boost::cref(*this)) + ) + ); + }) + ; + if(this != &other) vect_ = other.vect_; + return *(result = *this); + } + + virtual ~vector() { auto c = boost::contract::destructor(this); } + + void reserve(size_type count) { + auto c = boost::contract::public_function(this) + .precondition([&] { + BOOST_CONTRACT_ASSERT(count < max_size()); + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(capacity() >= count); + }) + ; + + vect_.reserve(count); + } + + size_type capacity() const { + size_type result; + auto c = boost::contract::public_function(this) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(result >= size()); + }) + ; + + return result = vect_.capacity(); + } + + iterator begin() { + itetator result; + auto c = boost::contract::public_function(this) + .postcondition([&] { + if(empty()) BOOST_CONTRACT_ASSERT(result == end()); + }) + ; + + return result = vect_.begin(); + } + + const_iterator begin() const { + const_itetator result; + auto c = boost::contract::public_function(this) + .postcondition([&] { + if(empty()) BOOST_CONTRACT_ASSERT(result == end()); + }) + ; + + return result = vect_.begin(); + } + + iterator end() { + auto c = boost::contract::public_function(this); + return vect_.end(); + } + + const_iterator end() const { + auto c = boost::contract::public_function(this); + return vect_.end(); + } + + reverse_iterator rbegin() { + itetator result; + auto c = boost::contract::public_function(this) + .postcondition([&] { + if(empty()) BOOST_CONTRACT_ASSERT(result == rend()); + }) + ; + + return result = vect_.rbegin(); + } + + const_reverse_iterator rbegin() const { + const_itetator result; + auto c = boost::contract::public_function(this) + .postcondition([&] { + if(empty()) BOOST_CONTRACT_ASSERT(result == rend()); + }) + ; + + return result = vect_.rbegin(); + } + + reverse_iterator rend() { + auto c = boost::contract::public_function(this); + return vect_.rend(); + } + + const_reverse_iterator rend() const { + auto c = boost::contract::public_function(this); + return vect_.rend(); + } + + void resize(size_type count, T const& value = T()) { + auto old_size = BOOST_CONTRACT_OLDOF(size()); + auto c = boost::contract::public_function(this) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(size() == count); + if(count > *old_size) { + BOOST_CONTRACT_ASSERT( + boost::contract::check_if >( + boost::bind(&boost::algorithm::all_of_equal, + begin() + *old_size, + end(), + boost::cref(value) + ) + ) + ); + } + }) + ; + + vect_.resize(count, value); + } + + size_type size() const { + size_type result; + auto c = boost::contract::public_function(this) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(result <= capacity()); + }) + ; + + return result = vect_.size(); + } + + size_type max_size() const { + size_type result; + auto c = boost::contract::public_function(this) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(result >= capacity()); + }) + ; + + return result = vect_.max_size(); + } + + bool empty() const { + bool result; + auto c = boost::contract::public_function(this) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(result == (size() == 0)); + }) + ; + + return vect_.empty(); + } + + Alloc get_allocator() const { + auto c = boost::contract::public_function(this); + return vect_.get_allocator(); + } + + reference at(size_type index) { + // No precondition because throws out_of_range for invalid index. + auto c = boost::contract::public_function(this); + return vect_.at(index); + } + + const_reference at(size_type index) const { + // No precondition because throws out_of_range for invalid index. + auto c = boost::contract::public_function(this); + return vect_.at(index); + } + + reference operator[](size_type index) { + auto c = boost::contract::public_function(this) + .precondition([&] { + BOOST_CONTRACT_ASSERT(index < size()); + }) + ; + + return vect_[index]; + } + + const_reference operator[](size_type index) const { + auto c = boost::contract::public_function(this) + .precondition([&] { + BOOST_CONTRACT_ASSERT(index < size()); + }) + ; + + return vect_[index]; + } + + reference front() { + auto c = boost::contract::public_function(this) + .precondition([&] { + BOOST_CONTRACT_ASSERT(!empty()); + }) + ; + + return vect_.front(); + } + + const_reference front() const { + auto c = boost::contract::public_function(this) + .precondition([&] { + BOOST_CONTRACT_ASSERT(!empty()); + }) + ; + + return vect_.front(); + } + + reference back() { + auto c = boost::contract::public_function(this) + .precondition([&] { + BOOST_CONTRACT_ASSERT(!empty()); + }) + ; + + return vect_.back(); + } + + const_reference back() const { + auto c = boost::contract::public_function(this) + .precondition([&] { + BOOST_CONTRACT_ASSERT(!empty()); + }) + ; + + return vect_.back(); + } + + void push_back(T const& value) { + auto old_size = BOOST_CONTRACT_OLDOF(size()); + auto old_capacity = BOOST_CONTRACT_OLDOF(capacity()); + auto c = boost::contract::public_function(this) + .precondition([&] { + BOOST_CONTRACT_ASSERT(size() < max_size()); + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(size() == *old_size + 1); + BOOST_CONTRACT_ASSERT(capacity() >= *old_capacity); + using namespace boost::contract; + BOOST_CONTRACT_ASSERT( + call_if >( + boost::bind(callable(), + boost::cref(back()), boost::cref(value)) + ).else_(true) + ); + }) + ; + + vect_.push_back(value); + } + + void pop_back() { + auto old_size = BOOST_CONTRACT_OLDOF(size()); + auto c = boost::contract::public_function(this) + .precondition([&] { + BOOST_CONTRACT_ASSERT(!empty()); + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(size() == *old_size - 1); + }) + ; + + vect_.pop_back(); + } + + template + void assign(InputIter first, InputIter last) { + auto c = boost::contract::public_function(this) + // Precondition: [begin(), end()) does not contain [first, last). + .postcondition([&] { + BOOST_CONTRACT_ASSERT(std::distance(first, last) == + int(size())); + }) + ; + + vect_.assign(first, last); + } + + void assign(size_type count, T const& value) { + auto c = boost::contract::public_function(this) + .precondition([&] { + BOOST_CONTRACT_ASSERT(count <= max_size()); + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT( + boost::contract;:check_if >( + boost::bind(&boost::algorithm::all_of_equal, + begin(), end(), boost::cref(value)) + ) + ); + }) + ; + + vect_.assign(count, value); + } + + iterator insert(iterator where, T const& value) { + iterator result; + auto old_size = BOOST_CONTRACT_OLDOF(size()); + auto c = boost::contract::public_function(this) + .precondition([&] { + BOOST_CONTRACT_ASSERT(size() < max_size()); + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(size() == *old_size + 1); + BOOST_CONTRACT_ASSERT( + boost::contract::check_if >( + boost::bind(&std::equal_to, boost::cref(*result), + boost::cref(value)) + ) + // if(capacity() > oldof capacity()) + // [begin(), end()) is invalid + // else + // [where, end()) is invalid + ); + }) + ; + + return result = vect_.insert(where, value); + } + + void insert(iterator where, size_type count, T const& value) { + auto old_size = BOOST_CONTRACT_OLDOF(size()); + auto old_capacity = BOOST_CONTRACT_OLDOF(capacity()); + auto old_where = BOOST_CONTRACT_OLDOF(where); + auto c = boost::contract::public_function(this) + .precondition([&] { + BOOST_CONTRACT_ASSERT(size() + count < max_size()); + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(size() == *old_size + count); + BOOST_CONTRACT_ASSERT(capacity() >= *old_capacity); + if(capacity() == *old_capacity) { + BOOST_CONTRACT_ASSERT( + boost::contract::check_if >( + boost::bind(&boost::algorithm::all_of_equal( + boost::prior(*old_where), + boost::prior(*old_where) + count, + boost::cref(value) + ) + ) + ); + } + }) + ; + + vect_.insert(where, count, value); + } + + template + void insert(iterator where, InputIter first, InputIter last) { + auto old_size = BOOST_CONTRACT_OLDOF(size()); + auto old_capacity = BOOST_CONTRACT_OLDOF(capacity()); + auto c = boost::contract::public_functon(this) + .precondition([&] { + BOOST_CONTRACT_ASSERT(size() + std::distance(fist, last) < + max_size()); + // [first, last) not contained in [begin(), end()) + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(size() == *old_size() + + std::distance(first, last)); + BOOST_CONTRACT_ASSERT(capacity() >= *old_capacity); + }) + ; + + vect_.insert(where, first, last); + } + + iterator erase(iterator where) { + iterator result; + auto old_size = BOOST_CONTRACT_OLDOF(size()); + auto c = boost::contract::public_function(this) + .precondition([&] { + BOOST_CONTRACT_ASSERT(!empty()); + BOOST_CONTRACT_ASSERT(where != end()); + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(size() == *old_size + 1); + if(empty()) BOOST_CONTRACT_ASSERT(result == end()); + // [where, end()) is invalid + }) + ; + + return result = vect_.erase(where); + } + + iterator erase(iterator first, iterator last) { + iterator result; + auto old_size = + auto c = boost::contract::public_function(this) + .precondition([&] { + BOOST_CONTRACT_ASSERT(size() >= std::distance(first, last)); + }) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(size() == *old_size + + std::distance(first, last)); + if(empty()) BOOST_CONTRACT_ASSERT(result == end()); + // [first, last) is invalid + }) + ; + + return result = vect_.erase(first, last); + } + + void clear() { + auto c = boost::contract::public_function(this) + .postcondition([&] { + BOOST_CONTRACT_ASSERT(empty()); + }) + ; + + vect_.clear(); + } + + void swap(vecotr& other) { + auto old_me = BOOST_CONTRACT_OLDOF(*this); + auto old_other = BOOST_CONTRACT_OLDOF(other); + auto c = boost::contract::public_function(this) + .postcondition([&] { + BOOST_CONTRACT_ASSERT( + boost::contract::check_if >( + boost::bind(&std::equal_to, boost::cref(*this), + boost::cref(*old_other)) + ) + ); + BOOST_CONTRACT_ASSERT( + boost::contract::check_if >( + boost::bind(&std::equal_to, boost::cref(other), + boost::cref(*old_me)) + ) + ); + }) + ; + + vect_.swap(other); + } + + friend bool operator==(vector const& left, vector const& right) { + return left.vect_ == right.vect_; + } + +private: + std::vector vect_; +}; + +int main() { + vector v(3); + BOOST_TEST_EQ(v.size(), 3); + BOOST_TEST(boost::algorithm::all_of_equal(v, '\0')); + vector const& cv = v; + + vector w(v); + BOOST_TEST_EQ(w, v); + + vector::iterator b = v.begin(); + BOOST_TEST_EQ(*b, '\0'); + + vector::const_iterator cb = cv.begin(); + BOOST_TEST_EQ(*cb, '\0'); + + v.insert(b, 2, 'a'); + BOOST_TEST_EQ(v[0], 'a'); + BOOST_TEST_EQ(v[1], 'a'); + + v.push_back('b'); + BOOST_TEST_EQ(v.back(), 'b'); + + return boost::report_errors(); +} + diff --git a/example/n1962/vector_n1962.hpp b/example/n1962/vector_n1962.hpp new file mode 100644 index 0000000..287df85 --- /dev/null +++ b/example/n1962/vector_n1962.hpp @@ -0,0 +1,499 @@ + +// Copyright (C) 2008-2012 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) +// Home at http://sourceforge.net/projects/contractpp + +//[n1962_vector_npaper +// File: vector_npaper.cpp +// Extra spaces, newlines, etc used to align text with this library code. + +#include +#include +#include +#include +#include + + +template< class T, class Allocator = std::allocator > +class vector +{ + invariant { + empty() == (size() == 0); + std::distance(begin(), end()) == int(size()); + std::distance(rbegin(), rend()) == int(size()); + size() <= capacity(); + capacity() <= max_size(); + } + + public: typedef typename std::vector::allocator_type + allocator_type; + public: typedef typename std::vector::pointer pointer; + public: typedef typename std::vector::const_pointer + const_pointer; + public: typedef typename std::vector::reference reference; + public: typedef typename std::vector::const_reference + const_reference; + public: typedef typename std::vector::value_type value_type; + public: typedef typename std::vector::iterator iterator; + public: typedef typename std::vector::const_iterator + const_iterator; + public: typedef typename std::vector::size_type size_type; + public: typedef typename std::vector::difference_type + difference_type; + public: typedef typename std::vector::reverse_iterator + reverse_iterator; + public: typedef typename std::vector::const_reverse_iterator + const_reverse_iterator; + + + public: vector ( void ) + postcondition { not empty(); } + : vector_() + {} + + + public: explicit vector ( const Allocator& alllocator ) + postcondition { + empty(); + allocator == get_allocator(); + } + : vector_(allocator) + {} + + + public: explicit vector ( size_type count ) + postcondition { + size() == count; + boost::algorithm::all_of_equal(begin(), end(), T()); + // Assertion requirements not supported by [N1962]. + } + : vector_(count) + {} + + + public: vector ( size_type count, const T& value ) + postcondition { + size() == count; + boost::algorithm::all_of_equal(begin(), end(), value); + + } + : vector_(count, value) + {} + + + public: vector ( size_type count, const T& value, + const Allocator& allocator ) + postcondition { + size() == count; + boost::algorithm::all_of_equal(begin(), end(), value); + + allocator == get_allocator(); + } + : vector_(count, value, allocator) + {} + + + public: template< class Iterator > + requires std::InputIterator + vector ( Iterator first, Iterator last ) + postcondition { std::distance(first, last) == int(size()); } + : vector_(first, last) + {} + + + public: template< class Iterator > + requires std::InputIterator + vector ( Iterator first, Iterator last, + const Allocator& allocator ) + postcondition { + std::distance(first, last) == int(size()); + allocator == get_allocator(); + } + : vector_(first, last, allocator) + {} + + + public: vector ( const vector& right ) + postcondition { + right == *this; + } + : vector_(right.vector_) + {} + + + public: vector& operator= ( const vector& right ) + postcondition(result) { + + right == *this; + result == *this; + } + { + return vect_ = right.vect_; + } + + + public: virtual ~vector ( void ) + {} + + + + public: void reserve ( size_type count ) + precondition { count < max_size(); } + postcondition { capacity() >= count; } + { + vector_.reserve(count); + } + + + public: size_type capacity ( void ) const + postcondition(result) { result >= size(); } + { + return vector_.capacity(); + } + + + public: iterator begin ( void ) + postcondition { + + if(empty()) { + result == end(); + } + } + { + return vector_.begin(); + } + + + public: const_iterator begin ( void ) const + postcondition(result) { + + if(empty()) { result == end(); } + } + { + return vector_.begin(); + } + + + public: iterator end ( void ) + { + return vector_.end(); + } + + + public: const_iterator end ( void ) const + { + return vector_.end(); + } + + + public: reverse_iterator rbegin ( void ) + postcondition(result) { + + if(empty()) { result == rend(); } + } + { + return vector_.rbegin(); + } + + + public: const_reverse_iterator rbegin ( void ) const + postcondition(result) { + + if(empty()) { result == rend(); } + } + { + return vector_.rbegin(); + } + + + public: reverse_iterator rend ( void ) + { + return vector_.rend(); + } + + + public: const_reverse_iterator rend ( void ) const + { + return vector_.rend(); + } + + + public: void resize ( size_type count ) + postcondition { + + size() == count; + if(count > oldof size()) { + boost::algorithm::all_of_equal(begin() + oldof size(), end(), + T()); + } + } + { + vectcor_.resize(count); + } + + + public: void resize ( size_type count, T value ) + postcondition { + + size() == count; + count > oldof size() ? + boost::algorithm::all_of_equal(begin() + oldof size(), end(), + value) + : + true + ; + } + { + vector_.resize(count, value); + } + + + public: size_type size ( void ) const + postcondition(result) { result <= capacity(); } + { + return vector_.size(); + } + + + public: size_type max_size ( void ) const + postcondition(result) { result >= capacity(); } + { + return vector_.max_size(); + } + + + public: bool empty ( void ) const + postcondition(result) { + + result == (size() == 0); + } + { + return vector_.empty(); + } + + + public: Alloctor get_allocator ( void ) const + { + return vector_.get_allocator(); + } + + + public: reference at ( size_type index ) + precondition { index < size(); } + { + return vectcor_.at(index); + } + + + public: const_reference at ( size_type index ) const + precondition { index < size(); } + { + return vector_.at(index); + } + + + public: reference operator[] ( size_type index ) + precondition { index < size(); } + { + return vector_[index]; + } + + + public: const_reference operator[] ( size_type index ) const + precondition { index < size(); } + { + return vectcor_[index]; + } + + + public: reference front ( void ) + precondition { not empty(); } + { + return vectcor_.front(); + } + + + public: const_reference front ( void ) const + precondition { bool(!empty()); } + { + return vector_.front(); + } + + + public: reference back ( void ) + precondition { not empty(); } + { + return vector_.back(); + } + + + public: const_reference back ( void ) const + precondition { not empty(); } + { + return vector_.back(); + } + + + public void push_back ( const T& value ) + precondition { size() < max_size() } + postcondition { + + + static if(boost::has_equal_to::value) { back() == value; } + size() == oldof size() + 1; + capacity() >= oldof capacity() + } + { + vector_.push_back(value); + } + + + public: void pop_back ( void ) + precondition { not empty(); } + postcondition { + + size() == oldof size() - 1; + } + { + vector_.pop_back(); + } + + + public: template< class Iterator > + requires std::InputIterator + void assign ( Iterator first, Iterator last ) + // precondition: [begin(), end()) does not contain [first, last) + postcondition { std::distance(first, last) == int(size()); } + { + vector_.assign(first, last); + } + + + public: void assign ( size_type count, const T& vallue ) + precondition { count <= max_size(); } + postcondition { + boost::algorithm::all_of_equal(begin(), end(), value); + + } + { + vector_.assign(count, value); + } + + + public: iterator insert ( iterator where, const T& value ) + precondition { size() < max_size(); } + postcondition(result) { + + + value == *result; + size() == oldof size() + 1; + // if(capacity() > oldof capacity()) + // [begin(), end()) is invalid + // else + // [where, end()) is invalid + } + { + return vector_.insert(where, value); + } + + + public: void insert ( iterator where, size_type count, + const T& value ) + precondition { size() + count < max_size(); } + postcondition { + + + + + size() == oldof size() + count; + capacity() >= oldof capacity(); + if(capacity() == oldof capacity()) { + boost::algorithm::all_of_equal(boost::prior(oldof where), + boost::prior(oldof where) + count, value); + + // [where, end()) is invalid + } // else [begin(), end()) is invalid + } + { + vector_.insert(where, count, value); + } + + + public: template< class Iterator > + requires std::InputIterator + void insert ( iterator where, Iterator first, Iterator last ) + precondition { + // [first, last) is not contained in [begin(), end()) + size() + std::distance(first, last) < max_size(); + } + postcondition { + + + size() == oldof size() + std::distance(first, last); + capacity() >= oldof capacity(); + } + { + vector_.insert(where, first, last); + } + + + public: iterator erase ( iterator where ) + precondition { + not empty(); + where != end(); + } + postcondition(result) { + + + size() == oldod size() - 1; + if(empty()) { result == end(); } + // [where, end()) is invalid + } + { + return vector_.erase(where); + } + + + public: iterator erase ( iterator first, iterator last ) + precondition { size() >= std::distance(first, lasst); } + postcondition(result) { + + + size() == oldof size() - std::distance(first, last); + if(empty()) { result == end(); } + // [first, last) is invalid + } + { + return vector_.erase(first, last); + } + + + public: void clear ( void ) + postcondition( empty() ) + { + vector_.clear(); + } + + + public: void swap ( vector& right ) + postcondition { + + + right == oldof *this; + oldof right == *this; + } + { + vector_.swap(right); + } + + friend bool operator== ( vector const& left, vector const& right ) + { + return left.vector_ == right.vector_; + } + + private: std::vector vector_; +}; +//] + diff --git a/include/boost/contract.hpp b/include/boost/contract.hpp index 4d8b97e..7bec56d 100644 --- a/include/boost/contract.hpp +++ b/include/boost/contract.hpp @@ -6,6 +6,7 @@ #include #include +#include #include #include #include diff --git a/include/boost/contract/call_if.hpp b/include/boost/contract/call_if.hpp new file mode 100644 index 0000000..f17f26a --- /dev/null +++ b/include/boost/contract/call_if.hpp @@ -0,0 +1,127 @@ + +#ifndef BOOST_CONTRACT_CALL_IF_HPP_ +#define BOOST_CONTRACT_CALL_IF_HPP_ + +#include +#include +#include +#include +#include + +/* PRIVATE */ + +// Boost.ResultOf not always able to deduce lambda result type (on MSVC). +#ifndef BOOST_NO_CXX11_DECL_TYPE +# define BOOST_CONTRACT_CALL_IF_ENABLE_IF_UNARY_RESULT_OF_(F) \ + decltype(boost::declval()()) +#else +# define BOOST_CONTRACT_CALL_IF_ENABLE_IF_UNARY_RESULT_OF_(F) \ + typename boost::result_of::type +#endif + +/* CODE */ + +namespace boost { namespace contract { + +template +struct call_if_statement {}; // Empty so cannot be used. + +// Dispatch true condition (then) between non-void and void calls. +// IMPORTANT: result_of can be evaluated only when condition is already +// checked to be true (as Then() is required to be valid only in that case) so +// this extra level of dispatching is necessary to avoid compiler errors. +template +struct call_if_statement : + call_if_statement +{ + explicit call_if_statement(Then f) : call_if_statement(f) {} +}; + +// True condition (then) for non-void call. +template +struct call_if_statement { // Copyable as *. + explicit call_if_statement(Then f) : r_(boost::make_shared(f())) {} + + operator R() const { return *r_; } + + template + R else_(Else const&) const { return *r_; } + + template + call_if_statement else_if_c(ElseIfThen const&) { + return *this; + } + + template + call_if_statement else_if(ElseIfThen const&) { + return *this; + } + +private: + boost::shared_ptr r_; +}; + +// True condition (then) for void call. +template +struct call_if_statement { + explicit call_if_statement(Then f) { f(); } + + // Cannot provide `operator R()` here, because R is void. + + template + void else_(Else const&) const {} + + template + call_if_statement else_if_c(ElseIfThen const&) { + return *this; + } + + template + call_if_statement else_if(ElseIfThen const&) { + return *this; + } +}; + +// False condition (else) for both non-void and void calls. +template +struct call_if_statement { + explicit call_if_statement(Then const&) {} + + // Do not provide `operator result_type()` here, require else_ instead. + + // IMPORTANT: result_of can be evaluated only when condition is + // already checked to be false (as Else() is required to be valid only in + // that case) so this is done lazily only in this template instantiation. + template + BOOST_CONTRACT_CALL_IF_ENABLE_IF_UNARY_RESULT_OF_(Else) else_(Else f) + const { + return f(); + } + + template + call_if_statement else_if_c(ElseIfThen f) { + return call_if_statement(f); + } + + template + call_if_statement else_if(ElseIfThen f) { + return call_if_statement(f); + } +}; + +template +call_if_statement call_if_c(Then f) { + return call_if_statement(f); +} + +template +call_if_statement call_if(Then f) { + return call_if_statement(f); +} + +} } // namespace + +#endif // #include guard + diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 1a94c59..538d962 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -1,31 +1,60 @@ -subdir-run constructor : bases ; -subdir-run constructor : body_throw ; -subdir-compile-fail constructor : no_pre-error ; +test-suite constructor : + [ subdir-run constructor : bases ] + [ subdir-run constructor : body_throw ] + [ subdir-compile-fail constructor : no_pre-error ] +; -subdir-run destructor : bases ; -subdir-run destructor : body_throw ; -subdir-compile-fail destructor : no_pre-error ; +test-suite destructor : + [ subdir-run destructor : bases ] + [ subdir-run destructor : body_throw ] + [ subdir-compile-fail destructor : no_pre-error ] +; -subdir-run public_function : bases ; -subdir-run public_function : bases_virtual ; -subdir-run public_function : bases_branch ; -subdir-run public_function : body_throw ; -subdir-run public_function : static ; -subdir-run public_function : static_body_throw ; +test-suite public_function : + [ subdir-run public_function : bases ] + [ subdir-run public_function : bases_virtual ] + [ subdir-run public_function : bases_branch ] + [ subdir-run public_function : body_throw ] + [ subdir-run public_function : static ] + [ subdir-run public_function : static_body_throw ] +; -subdir-run function : pre_post ; -subdir-run function : body_throw ; +test-suite function : + [ subdir-run function : pre_post ] + [ subdir-run function : body_throw ] +; -subdir-run disable : checking ; +test-suite disable : + [ subdir-run disable : checking ] +; -subdir-run set : nothing ; -subdir-run set : pre_only ; -subdir-run set : post_only ; -subdir-run set : pre_post ; -subdir-run set : post_pre ; -subdir-compile-fail set : pre_pre-error ; -subdir-compile-fail set : post_post-error ; -subdir-compile-fail set : pre_post_pre-error ; -subdir-compile-fail set : post_pre_post-error ; +test-suite set : + [ subdir-run set : nothing ] + [ subdir-run set : pre_only ] + [ subdir-run set : post_only ] + [ subdir-run set : pre_post ] + [ subdir-run set : post_pre ] + [ subdir-compile-fail set : pre_pre-error ] + [ subdir-compile-fail set : post_post-error ] + [ subdir-compile-fail set : pre_post_pre-error ] + [ subdir-compile-fail set : post_pre_post-error ] +; + +test-suite call_if : + [ subdir-run call_if : true_ ] + [ subdir-run call_if : false_ ] + [ subdir-run call_if : true_void ] + [ subdir-run call_if : false_void ] + [ subdir-run call_if : equal_to ] +; + +# C++14 supported only by Clang... so in its own suite and explicit. +test-suite cxx14 : + [ subdir-run call_if : equal_to_cxx14 : + clang:-std=c++1y ] + [ subdir-run call_if : myadvance_cxx14 : + clang:-std=c++1y ] +; +explicit cxx14 ; diff --git a/test/call_if/equal_to.cpp b/test/call_if/equal_to.cpp new file mode 100644 index 0000000..3f6ac1e --- /dev/null +++ b/test/call_if/equal_to.cpp @@ -0,0 +1,75 @@ + +// Test STL equal_to with call_if. + +#include "../aux_/oteststream.hpp" +#include +#include +#include +#include +#include +#include + +boost::contract::aux::test::oteststream out; + +template +struct void_equal_to { + typedef void result_type; // Test void result type. + + void operator()(T const& left, T const& right) const { + out << (left == right) << std::endl; + } +}; + +struct x {}; // Doest not have operator==. + +int main() { + std::ostringstream ok; + x x1, x2;; + + out.str(""); + out << // Test on true condition with non-void result type. + boost::contract::call_if >( + boost::bind(std::equal_to(), 123, 123) // True. + ).else_( + // Compiler-error... but not called. + boost::bind(std::equal_to(), x1, x2) + ) + << std::endl; + ok.str(""); ok << true << std::endl; + BOOST_TEST(out.eq(ok.str())); + + out.str(""); + out << // Test on false condition with non-void result type. + boost::contract::call_if >( + // Compiler-error... but not called. + boost::bind(std::equal_to(), x1, x2) + ).else_([] { return true; }) + << std::endl; + ok.str(""); ok << true << std::endl; + BOOST_TEST(out.eq(ok.str())); + + out.str(""); + // Test on true condition void result type. + boost::contract::call_if >( + boost::bind(void_equal_to(), 123, 456) // False. + ).else_( + // Compiler-error... but not called. + boost::bind(void_equal_to(), x1, x1) + ); + ok.str(""); ok << false << std::endl; + BOOST_TEST(out.eq(ok.str())); + + out.str(""); + // Test on false condition with void result type. + boost::contract::call_if >( + // Compiler-error... but not called. + boost::bind(void_equal_to(), x1, x1) + ).else_( + boost::bind(void_equal_to(), 123, 456) // False. + ); + ok.str(""); ok << false << std::endl; + BOOST_TEST(out.eq(ok.str())); + + return boost::report_errors(); +} + diff --git a/test/call_if/equal_to_cxx14.cpp b/test/call_if/equal_to_cxx14.cpp new file mode 100644 index 0000000..8eac42e --- /dev/null +++ b/test/call_if/equal_to_cxx14.cpp @@ -0,0 +1,48 @@ + +// Test call_if equality check with C++14 generic lambdas. + +#include "../aux_/oteststream.hpp" +#include +#include +#include +#include // std::bind for generic lambdas. +#include + +boost::contract::aux::test::oteststream out; + +struct x {}; // Does not have operator==. + +int main() { + std::ostringstream ok; + x x1, x2; + + out.str(""); + out << + boost::contract::call_if >( + std::bind([] (auto a, auto b) { return a == b; }, 123, 456) + ).else_([] { return true; }) + << std::endl; + ok.str(""); ok << false << std::endl; + BOOST_TEST(out.eq(ok.str())); + + out.str(""); + out << + boost::contract::call_if >( + std::bind([] (auto a, auto b) { return a == b; }, x1, x2) + ).else_([] { return true; }) + << std::endl; + ok.str(""); ok << true << std::endl; + BOOST_TEST(out.eq(ok.str())); + + out.str(""); + out << // Test explicit result, cannot deduce from lambda missing `-> bool`. + boost::contract::call_if >( + std::bind([] (auto a, auto b) { return a == b; }, x1, x2) + ).else_([] { return true; }) + << std::endl; + ok.str(""); ok << true << std::endl; + BOOST_TEST(out.eq(ok.str())); + + return boost::report_errors(); +} + diff --git a/test/call_if/false_.cpp b/test/call_if/false_.cpp new file mode 100644 index 0000000..cb315d6 --- /dev/null +++ b/test/call_if/false_.cpp @@ -0,0 +1,57 @@ + +// Test call_if with false condition and non-void result type. + +#include "../aux_/oteststream.hpp" +#include +#include +#include +#include +#include + +boost::contract::aux::test::oteststream out; + +struct equal { + typedef bool result_type; // Test non-void result type. + + template + result_type operator()(L left, R right) const { + return left == right; // Requires operator==. + } +}; + +struct x {}; // Doest not have operator==. + +int main() { + std::ostringstream ok; + x x1, x2;; + + out.str(""); + out << + boost::contract::call_if >( + boost::bind(equal(), x1, x1) // Compiler-error... but not called. + ).else_([] { return false; }) // Test else. + << std::endl; + ok.str(""); ok << false << std::endl; + BOOST_TEST(out.eq(ok.str())); + + out.str(""); + out << + boost::contract::call_if >( + boost::bind(equal(), x1, x2) // Compiler-error... but not called. + ).else_([] { return true; }) + << std::endl; + ok.str(""); ok << true << std::endl; + BOOST_TEST(out.eq(ok.str())); + + out.str(""); + out << // Test "..._c". + boost::contract::call_if_c::value>( + boost::bind(equal(), x1, x2) // Compiler-error...but not called. + ).else_([] { return true; }) + << std::endl; + ok.str(""); ok << true << std::endl; + BOOST_TEST(out.eq(ok.str())); + + return boost::report_errors(); +} + diff --git a/test/call_if/false_void.cpp b/test/call_if/false_void.cpp new file mode 100644 index 0000000..a571c23 --- /dev/null +++ b/test/call_if/false_void.cpp @@ -0,0 +1,47 @@ + +// Test call_if with false condition and void result type. + +#include "../aux_/oteststream.hpp" +#include +#include +#include +#include +#include + +boost::contract::aux::test::oteststream out; + +struct equal { + typedef void result_type; // Test void result type. + + template + result_type operator()(L left, R right) const { + out << (left == right) << std::endl; // Requires operator==. + } +}; + +struct x {}; // Doest not have operator==. + +int main() { + std::ostringstream ok; + x x1, x2;; + + out.str(""); + boost::contract::call_if >( + boost::bind(equal(), x1, x2) // Compiler-error... but not called. + ); // Test no else. + ok.str(""); + BOOST_TEST(out.eq(ok.str())); + + out.str(""); + // Test "..._c". + boost::contract::call_if_c::value>( + boost::bind(equal(), x1, x2) // Compiler-error...but not called. + ).else_( + [] { out << true << std::endl; } // Test else. + ); + ok.str(""); ok << true << std::endl; + BOOST_TEST(out.eq(ok.str())); + + return boost::report_errors(); +} + diff --git a/test/call_if/myadvance_cxx14.cpp b/test/call_if/myadvance_cxx14.cpp new file mode 100644 index 0000000..40d5797 --- /dev/null +++ b/test/call_if/myadvance_cxx14.cpp @@ -0,0 +1,115 @@ + +// Test possible impl. advance() in single function with C++14 generic lambdas. + +#include "../aux_/oteststream.hpp" +#include +#include +#include +#include +#include // std::bind for generic lambdas. +#include +#include +#include + +boost::contract::aux::test::oteststream out; + +template +struct is_random_access_iterator : std::is_same< + typename std::iterator_traits::iterator_category, + std::random_access_iterator_tag +> {}; + +template +struct is_bidirectional_iterator : std::is_same< + typename std::iterator_traits::iterator_category, + std::bidirectional_iterator_tag +> {}; + +template +struct is_input_iterator : std::is_same< + typename std::iterator_traits::iterator_category, + std::input_iterator_tag +> {}; + +template +void myadvance(Iter& i, Dist n) { + using boost::contract::call_if; + Iter *p = &i; // So captures change actual pointed iterator value. + call_if >( + std::bind([] (auto p, auto n) { + out << "random iterator" << std::endl; + *p += n; + }, p, n) + ).template else_if >( + std::bind([] (auto p, auto n) { + out << "bidirectional iterator" << std::endl; + if(n >= 0) while(n--) ++*p; + else while(n++) --*p; + }, p, n) + ).template else_if >( + std::bind([] (auto p, auto n) { + out << "input iterator" << std::endl; + while(n--) ++*p; + }, p, n) + ).else_( + std::bind([] (auto false_) { + static_assert(false_, "requires input iter"); + }, std::false_type()) // Use constexpr value. + ); +} + +struct x {}; // Test not an iterator (static_assert failure in else_ above). + +namespace std { + template<> + struct iterator_traits { + typedef void iterator_category; + }; +} + +int main() { + std::ostringstream ok; + + std::vector v; + v.push_back('a'); + v.push_back('b'); + v.push_back('c'); + v.push_back('d'); + std::vector::iterator r = v.begin(); // Random iterator. + out.str(""); + myadvance(r, 1); + out << *r << std::endl; + ok.str(""); ok + << "random iterator" << std::endl + << "b" << std::endl + ; + BOOST_TEST(out.eq(ok.str())); + + std::list l(v.begin(), v.end()); + std::list::iterator b = l.begin(); // Bidirectional iterator. + out.str(""); + myadvance(b, 2); + out << *b << std::endl; + ok.str(""); ok + << "bidirectional iterator" << std::endl + << "c" << std::endl + ; + BOOST_TEST(out.eq(ok.str())); + + std::istringstream s("a b c d"); + std::istream_iterator i(s); + out.str(""); + myadvance(i, 3); + out << *i << std::endl; + ok.str(""); ok + << "input iterator" << std::endl + << "d" << std::endl + ; + BOOST_TEST(out.eq(ok.str())); + + // x xx; + // myadvance(xx, 0); // Error (correctly because x not even input iter). + + return boost::report_errors(); +} + diff --git a/test/call_if/true_.cpp b/test/call_if/true_.cpp new file mode 100644 index 0000000..e860254 --- /dev/null +++ b/test/call_if/true_.cpp @@ -0,0 +1,59 @@ + +// Test call_if with true condition and non-void result type. + +#include "../aux_/oteststream.hpp" +#include +#include +#include +#include +#include + +boost::contract::aux::test::oteststream out; + +struct equal { + typedef bool result_type; // Test non-void result type. + + template + result_type operator()(L left, R right) const { + return left == right; // Requires operator==. + } +}; + +struct x {}; // Doest not have operator==. + +int main() { + std::ostringstream ok; + x x1, x2;; + + out.str(""); + out << + boost::contract::call_if >( + boost::bind(equal(), 123, 456) // False. + ) // Test no else (not called). + << std::endl; + ok.str(""); ok << false << std::endl; + BOOST_TEST(out.eq(ok.str())); + + out.str(""); + out << + boost::contract::call_if >( + boost::bind(equal(), 123, 123) // True. + ).else_([] { return false; }) // Test else not called. + << std::endl; + ok.str(""); ok << true << std::endl; + BOOST_TEST(out.eq(ok.str())); + + out.str(""); + out << // Test "..._c". + boost::contract::call_if_c::value>( + boost::bind(equal(), 123, 123) // True. + ).else_( // Test else not called. + boost::bind(equal(), x1, x2) // Compiler-error... but not called. + ) + << std::endl; + ok.str(""); ok << true << std::endl; + BOOST_TEST(out.eq(ok.str())); + + return boost::report_errors(); +} + diff --git a/test/call_if/true_void.cpp b/test/call_if/true_void.cpp new file mode 100644 index 0000000..d6b9a01 --- /dev/null +++ b/test/call_if/true_void.cpp @@ -0,0 +1,56 @@ + +// Test call_if with true condition and void result type. + +#include "../aux_/oteststream.hpp" +#include +#include +#include +#include +#include + +boost::contract::aux::test::oteststream out; + +struct equal { + typedef void result_type; // Test void result type. + + template + result_type operator()(L left, R right) const { + out << (left == right) << std::endl; // Requires operator==. + } +}; + +struct x {}; // Doest not have operator==. + +int main() { + std::ostringstream ok; + x x1, x2;; + + out.str(""); + boost::contract::call_if >( + boost::bind(equal(), 123, 456) // False. + ); // Test no else (not called). + ok.str(""); ok << false << std::endl; + BOOST_TEST(out.eq(ok.str())); + + out.str(""); + boost::contract::call_if >( + boost::bind(equal(), 123, 123) // True. + ).else_( + [] { return false; } + ); // Test else (not called). + ok.str(""); ok << true << std::endl; + BOOST_TEST(out.eq(ok.str())); + + out.str(""); + // Test "..._c". + boost::contract::call_if_c::value>( + boost::bind(equal(), 123, 123) // True. + ).else_( // Test else (not called). + boost::bind(equal(), x1, x2) // Compiler-error... but not called. + ); + ok.str(""); ok << true << std::endl; + BOOST_TEST(out.eq(ok.str())); + + return boost::report_errors(); +} +