From 3146d3fa3dd414593ca867d52737221588219e85 Mon Sep 17 00:00:00 2001 From: Lorenzo Caminiti Date: Sat, 25 Apr 2015 22:37:35 -0700 Subject: [PATCH] added oldof test, renamed type to scoped --- include/boost/contract/oldof.hpp | 9 +- include/boost/contract/public_member.hpp | 6 +- include/boost/contract/scoped.hpp | 35 ++++++ include/boost/contract/set/nothing.hpp | 4 +- .../boost/contract/set/postcondition_only.hpp | 4 +- .../boost/contract/set/precondition_only.hpp | 4 +- .../set/precondition_postcondition.hpp | 16 +-- include/boost/contract/type.hpp | 35 ------ include/boost/contract/virtual_body.hpp | 19 ++-- test/Jamfile.v2 | 3 + test/function/constructor_bases.cpp | 9 +- test/function/destructor_bases.cpp | 9 +- test/function/free_function.cpp | 3 +- test/function/private_member_bases.cpp | 5 +- test/function/protected_member_bases.cpp | 5 +- test/function/public_member_bases_static.cpp | 5 +- test/function/public_member_bases_virtual.cpp | 17 +-- test/oldof/oldof.cpp | 48 ++++++++ test/oldof/oldof_virtual.cpp | 103 ++++++++++++++++++ 19 files changed, 240 insertions(+), 99 deletions(-) create mode 100644 include/boost/contract/scoped.hpp delete mode 100644 include/boost/contract/type.hpp create mode 100644 test/oldof/oldof.cpp create mode 100644 test/oldof/oldof_virtual.cpp diff --git a/include/boost/contract/oldof.hpp b/include/boost/contract/oldof.hpp index 25c44a1..588e06d 100644 --- a/include/boost/contract/oldof.hpp +++ b/include/boost/contract/oldof.hpp @@ -29,13 +29,14 @@ #include #include +#include /* PUBLIC */ #define BOOST_CONTRACT_OLDOF(...) \ - BOOST_PP_OVERLOAD( \ + BOOST_PP_CAT(BOOST_PP_OVERLOAD( /* CAT(... EMPTY()) workaround for MSVC */ \ BOOST_CONTRACT_ERROR_macro_BOOST_CONTRACT_OLDOF_invalid_number_of_arguments_, \ - __VA_ARGS__)(__VA_ARGS__) + __VA_ARGS__)(__VA_ARGS__), BOOST_PP_EMPTY()) /* PRIVATE */ @@ -114,8 +115,8 @@ bool skip_oldof(boost::contract::virtual_body const v) { #ifdef BOOST_CONTRACT_CONFIG_NO_POSTCONDITIONS return true; // Never check post, so old-of never needed. #else - if(v == boost::contract::virtual_body::user_call || - v == boost::contract::virtual_body::check_post_only) { + if(v.action == boost::contract::virtual_body::user_call || + v.action == boost::contract::virtual_body::check_post_only) { return false; // Checking post, so old-of needed. } return true; // Not checking post, so old-of not needed. diff --git a/include/boost/contract/public_member.hpp b/include/boost/contract/public_member.hpp index be7b57c..e43a0be 100644 --- a/include/boost/contract/public_member.hpp +++ b/include/boost/contract/public_member.hpp @@ -41,8 +41,8 @@ namespace boost { namespace contract { template boost::contract::set::precondition_postcondition public_member( - Class* const object, Function const&, Argument0 argument0, - boost::contract::virtual_body const v + boost::contract::virtual_body const v, Class* const object, Function const&, + Argument0 argument0 ) { return boost::contract::set::precondition_postcondition(boost::make_shared< boost::contract::aux::function::public_member boost::contract::set::precondition_postcondition public_member( - Class* const object, boost::contract::virtual_body const v) { + boost::contract::virtual_body const v, Class* const object) { return boost::contract::set::precondition_postcondition(boost::make_shared< boost::contract::aux::function::public_member >(v, object)); } diff --git a/include/boost/contract/scoped.hpp b/include/boost/contract/scoped.hpp new file mode 100644 index 0000000..bb514af --- /dev/null +++ b/include/boost/contract/scoped.hpp @@ -0,0 +1,35 @@ + +#ifndef BOOST_CONTRACT_SCOPED_HPP_ +#define BOOST_CONTRACT_SCOPED_HPP_ + +#include +#include +#include +#include +#include +#include + +namespace boost { namespace contract { + +class scoped { // Allow (shallow ptr) copy for `scoped c = ...`. +public: + /* implicit */ scoped(boost::contract::set::precondition_postcondition + const& c) : contract_(c.contract_) {} + + /* implicit */ scoped(boost::contract::set::precondition_only + const& c) : contract_(c.contract_) {} + + /* implicit */ scoped(boost::contract::set::postcondition_only + const& c) : contract_(c.contract_) {} + + /* implicit */ scoped(boost::contract::set::nothing + const& c) : contract_(c.contract_) {} + +private: + boost::shared_ptr contract_; +}; + +} } // namespace + +#endif // #include guard + diff --git a/include/boost/contract/set/nothing.hpp b/include/boost/contract/set/nothing.hpp index 5ae00c2..57f3860 100644 --- a/include/boost/contract/set/nothing.hpp +++ b/include/boost/contract/set/nothing.hpp @@ -7,7 +7,7 @@ namespace boost { namespace contract { - class type; + class scoped; namespace set { class precondition_only; @@ -24,7 +24,7 @@ public: private: // Use friendship and deleted constructors to limit public API. - friend class boost::contract::type; + friend class boost::contract::scoped; friend class boost::contract::set::precondition_only; friend class boost::contract::set::postcondition_only; diff --git a/include/boost/contract/set/postcondition_only.hpp b/include/boost/contract/set/postcondition_only.hpp index 04199ce..b9a9260 100644 --- a/include/boost/contract/set/postcondition_only.hpp +++ b/include/boost/contract/set/postcondition_only.hpp @@ -8,7 +8,7 @@ namespace boost { namespace contract { - class type; + class scoped; template boost::contract::set::postcondition_only constructor(Class* const); @@ -34,7 +34,7 @@ public: private: // Use friendship and deleted constructors to limit public API. - friend class boost::contract::type; + friend class boost::contract::scoped; friend class boost::contract::set::precondition_postcondition; template diff --git a/include/boost/contract/set/precondition_only.hpp b/include/boost/contract/set/precondition_only.hpp index c800ae0..7de4cf1 100644 --- a/include/boost/contract/set/precondition_only.hpp +++ b/include/boost/contract/set/precondition_only.hpp @@ -8,7 +8,7 @@ namespace boost { namespace contract { - class type; + class scoped; namespace set { class precondition_postcondition; @@ -28,7 +28,7 @@ public: private: // Use friendship and deleted constructors to limit public API. - friend class boost::contract::type; + friend class boost::contract::scoped; friend class boost::contract::set::precondition_postcondition; explicit precondition_only(boost::shared_ptr boost::contract::set::precondition_postcondition public_member( - Class* const, Function const&, Argument0, - boost::contract::virtual_body const + boost::contract::virtual_body const, Class* const, Function const&, + Argument0 ); template boost::contract::set::precondition_postcondition public_member( - Class* const, boost::contract::virtual_body const); + boost::contract::virtual_body const, Class* const); template boost::contract::set::precondition_postcondition public_member( @@ -61,13 +61,13 @@ public: private: // Use friendship and deleted constructors to limit public API. - friend class boost::contract::type; + friend class boost::contract::scoped; template friend precondition_postcondition boost::contract::public_member( - Class* const, Function const&, Argument0, - boost::contract::virtual_body const + boost::contract::virtual_body const, Class* const, Function const&, + Argument0 ); template friend precondition_postcondition boost::contract::public_member( - Class* const, boost::contract::virtual_body const); + boost::contract::virtual_body const, Class* const); template friend precondition_postcondition boost::contract::public_member( diff --git a/include/boost/contract/type.hpp b/include/boost/contract/type.hpp deleted file mode 100644 index 58d4e6f..0000000 --- a/include/boost/contract/type.hpp +++ /dev/null @@ -1,35 +0,0 @@ - -#ifndef BOOST_CONTRACT_TYPE_HPP_ -#define BOOST_CONTRACT_TYPE_HPP_ - -#include -#include -#include -#include -#include -#include - -namespace boost { namespace contract { - -class type { // Allow (shallow ptr) copy for `type c = ...`. -public: - /* implicit */ type(boost::contract::set::precondition_postcondition const& - c) : contract_(c.contract_) {} - - /* implicit */ type(boost::contract::set::precondition_only const& - c) : contract_(c.contract_) {} - - /* implicit */ type(boost::contract::set::postcondition_only const& - c) : contract_(c.contract_) {} - - /* implicit */ type(boost::contract::set::nothing const& - c) : contract_(c.contract_) {} - -private: - boost::shared_ptr contract_; -}; - -} } // namespace - -#endif // #include guard - diff --git a/include/boost/contract/virtual_body.hpp b/include/boost/contract/virtual_body.hpp index 69bbad8..6d3c892 100644 --- a/include/boost/contract/virtual_body.hpp +++ b/include/boost/contract/virtual_body.hpp @@ -25,6 +25,15 @@ public: /* implicit */ virtual_body(int const) : action(user_call) {} private: + // Use friendship to limit public API. + template + friend class boost::contract::aux::check::subcontracted_pre_post_inv; + + template + friend class boost::contract::aux::function::public_member; + + friend bool skip_oldof(virtual_body const); + enum action_type { user_call, check_inv_only, @@ -36,16 +45,6 @@ private: action(an_action) {} action_type action; - - // Use friendship to limit public API. - - template - friend class boost::contract::aux::check::subcontracted_pre_post_inv; - - template - friend class boost::contract::aux::function::public_member; - - friend bool skip_oldof(virtual_body const); }; } } // namespace diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 1e357fa..a51bd38 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -7,6 +7,9 @@ subdir-run function : protected_member_bases ; subdir-run function : private_member_bases ; subdir-run function : free_function ; +subdir-run oldof : oldof ; +subdir-run oldof : oldof_virtual ; + subdir-run set : creation_set_post_nothing_comb ; subdir-compile-fail set : creation_set_post_post_error ; subdir-compile-fail set : creation_set_post_pre_error ; diff --git a/test/function/constructor_bases.cpp b/test/function/constructor_bases.cpp index 4b0d668..95f762c 100644 --- a/test/function/constructor_bases.cpp +++ b/test/function/constructor_bases.cpp @@ -1,7 +1,6 @@ #include "../aux_/oteststream.hpp" #include -#include #include #include #include @@ -31,7 +30,7 @@ struct d out << "d::ctor::pre" << std::endl; }) { - boost::contract::type c = boost::contract::constructor(this) + auto c = boost::contract::constructor(this) .postcondition([&] { out << "d::ctor::post" << std::endl; }) @@ -62,7 +61,7 @@ struct c }), d(x) { - boost::contract::type c = boost::contract::constructor(this) + auto c = boost::contract::constructor(this) .postcondition([&] { out << "c::ctor::post" << std::endl; }) @@ -91,7 +90,7 @@ struct b out << "b::ctor::pre" << std::endl; }) { - boost::contract::type c = boost::contract::constructor(this) + auto c = boost::contract::constructor(this) .postcondition([&] { out << "b::ctor::post" << std::endl; }) @@ -126,7 +125,7 @@ struct a c(x), value(x) { - boost::contract::type c = boost::contract::constructor(this) + auto c = boost::contract::constructor(this) .postcondition([&] { out << "a::ctor::post" << std::endl; BOOST_CONTRACT_ASSERT(this->value == x); diff --git a/test/function/destructor_bases.cpp b/test/function/destructor_bases.cpp index 0f22479..a0cdc6b 100644 --- a/test/function/destructor_bases.cpp +++ b/test/function/destructor_bases.cpp @@ -1,7 +1,6 @@ #include "../aux_/oteststream.hpp" #include -#include #include #include #include @@ -21,7 +20,7 @@ struct d { // Test inheritance level 0. } ~d() { - boost::contract::type c = boost::contract::destructor(this) + auto c = boost::contract::destructor(this) .postcondition([&] { out << "d::dtor::post" << std::endl; }) @@ -46,7 +45,7 @@ struct c // Test inheritance level 1. } ~c() { - boost::contract::type c = boost::contract::destructor(this) + auto c = boost::contract::destructor(this) .postcondition([&] { out << "c::dtor::post" << std::endl; }) @@ -65,7 +64,7 @@ struct b { // Test inheritance level 0. } ~b() { - boost::contract::type c = boost::contract::destructor(this) + auto c = boost::contract::destructor(this) .postcondition([&] { out << "b::dtor::post" << std::endl; }) @@ -90,7 +89,7 @@ struct a // Test multiple inheritance and inheritance level 2. } ~a() { - boost::contract::type c = boost::contract::destructor(this) + auto c = boost::contract::destructor(this) .postcondition([&] { out << "a::dtor::post" << std::endl; }) diff --git a/test/function/free_function.cpp b/test/function/free_function.cpp index 1fe9685..9d7e96c 100644 --- a/test/function/free_function.cpp +++ b/test/function/free_function.cpp @@ -1,7 +1,6 @@ #include "../aux_/oteststream.hpp" #include -#include #include #include @@ -10,7 +9,7 @@ boost::contract::aux::test::oteststream out; void f() { - boost::contract::type c = boost::contract::free_function() + auto c = boost::contract::free_function() .precondition([&] { out << "f::pre" << std::endl; }) diff --git a/test/function/private_member_bases.cpp b/test/function/private_member_bases.cpp index d46794c..e15b688 100644 --- a/test/function/private_member_bases.cpp +++ b/test/function/private_member_bases.cpp @@ -1,7 +1,6 @@ #include "../aux_/oteststream.hpp" #include -#include #include #include #include @@ -24,7 +23,7 @@ struct b { private: void f() { - boost::contract::type c = boost::contract::private_member() + auto c = boost::contract::private_member() .precondition([&] { out << "b::f::pre" << std::endl; }) @@ -55,7 +54,7 @@ struct a private: void f() { - boost::contract::type c = boost::contract::private_member() + auto c = boost::contract::private_member() .precondition([&] { out << "a::f::pre" << std::endl; }) diff --git a/test/function/protected_member_bases.cpp b/test/function/protected_member_bases.cpp index 59c326f..5c25109 100644 --- a/test/function/protected_member_bases.cpp +++ b/test/function/protected_member_bases.cpp @@ -1,7 +1,6 @@ #include "../aux_/oteststream.hpp" #include -#include #include #include #include @@ -24,7 +23,7 @@ struct b { protected: void f() { - boost::contract::type c = boost::contract::protected_member() + auto c = boost::contract::protected_member() .precondition([&] { out << "b::f::pre" << std::endl; }) @@ -55,7 +54,7 @@ struct a protected: void f() { - boost::contract::type c = boost::contract::protected_member() + auto c = boost::contract::protected_member() .precondition([&] { out << "a::f::pre" << std::endl; }) diff --git a/test/function/public_member_bases_static.cpp b/test/function/public_member_bases_static.cpp index e1875bb..dca0f1b 100644 --- a/test/function/public_member_bases_static.cpp +++ b/test/function/public_member_bases_static.cpp @@ -1,7 +1,6 @@ #include "../aux_/oteststream.hpp" #include -#include #include #include #include @@ -21,7 +20,7 @@ struct b { } static void s() { - boost::contract::type c = boost::contract::public_member() + auto c = boost::contract::public_member() .precondition([&] { out << "b::s::pre" << std::endl; }) @@ -50,7 +49,7 @@ struct a } static void s() { - boost::contract::type c = boost::contract::public_member() + auto c = boost::contract::public_member() .precondition([&] { out << "a::s::pre" << std::endl; }) diff --git a/test/function/public_member_bases_virtual.cpp b/test/function/public_member_bases_virtual.cpp index 6c8f0e3..ac0d03d 100644 --- a/test/function/public_member_bases_virtual.cpp +++ b/test/function/public_member_bases_virtual.cpp @@ -1,7 +1,6 @@ #include "../aux_/oteststream.hpp" #include -#include #include #include #include @@ -29,8 +28,7 @@ struct e { // Test contract allows (but does not require) extra introspection, // function pointer, etc. parameter because class has no bases. void f(T& x, boost::contract::virtual_body v = 0) { - boost::contract::type c = boost::contract::public_member( - this, &e::f, x, v) + auto c = boost::contract::public_member(v, this, &e::f, x) .precondition([&]() { out << "e::f::pre" << std::endl; BOOST_CONTRACT_ASSERT(false); // To check subcontracted pre. @@ -42,8 +40,6 @@ struct e { f_body(x); } virtual void f_body(T& x) = 0; - -private: BOOST_CONTRACT_INTROSPECT(f) }; @@ -63,7 +59,7 @@ struct d { // Test contract does not require (but allows) extra introspection, // function pointer, etc. parameter because class has no bases. void f(T& x, boost::contract::virtual_body v = 0) { - boost::contract::type c = boost::contract::public_member(this, v) + auto c = boost::contract::public_member(v, this) .precondition([&]() { out << "d::f::pre" << std::endl; BOOST_CONTRACT_ASSERT(false); // To check subcontracted pre. @@ -98,8 +94,7 @@ struct c // Test virtual overrides virtual function. void f(T& x, boost::contract::virtual_body v = 0) { - boost::contract::type c = boost::contract::public_member( - this, &c::f, x, v) + auto c = boost::contract::public_member(v, this, &c::f, x) .precondition([&]() { out << "c::f::pre" << std::endl; BOOST_CONTRACT_ASSERT(false); // To check subcontracted pre. @@ -111,12 +106,10 @@ struct c f_body(x); } virtual void f_body(T& x) {} + BOOST_CONTRACT_INTROSPECT(f) // Test non-contracted virtual function in contracted base. virtual void k() = 0; - -private: - BOOST_CONTRACT_INTROSPECT(f) }; // Test a non-contracted base. @@ -149,7 +142,7 @@ struct a // Test non-virtual overrides virtual function. void f(T& x) { - boost::contract::type c = boost::contract::public_member( + auto c = boost::contract::public_member( this, &a::f, x) .precondition([&]() { out << "a::f::pre" << std::endl; diff --git a/test/oldof/oldof.cpp b/test/oldof/oldof.cpp new file mode 100644 index 0000000..02836ae --- /dev/null +++ b/test/oldof/oldof.cpp @@ -0,0 +1,48 @@ + +#include +#include +#include +#include +#include + +// Test old-values evaluated and copied only once. + +unsigned copy_count, eval_count; + +struct num { + int i; + explicit num(int const _i) : i(_i) {} + num(num const& n) : i(n.i) { ++copy_count; } + num& operator=(num const& n) { ++copy_count; i = n.i; return *this; } +}; + +num& eval(num& n) { ++eval_count; return n; } + +void inc(num& n) { + auto old_n = BOOST_CONTRACT_OLDOF(eval(n)); + auto c = boost::contract::free_function() + .precondition([&] {}) // So pre part of this test. + .postcondition([&] { + BOOST_CONTRACT_ASSERT(n.i == old_n->i + 1); + }) + ; + n.i = n.i + 1; +} + +int main() { + copy_count = eval_count = 0; + num n(1); + inc(n); + + BOOST_TEST_EQ(n.i, 2); +#ifdef BOOST_CONTRACT_CONFIG_NO_POSTCONDITIONS + BOOST_TEST_EQ(copy_count, 0); + BOOST_TEST_EQ(eval_count, 0); +#else + BOOST_TEST_EQ(copy_count, 1); + BOOST_TEST_EQ(eval_count, 1); +#endif + + return boost::report_errors(); +} + diff --git a/test/oldof/oldof_virtual.cpp b/test/oldof/oldof_virtual.cpp new file mode 100644 index 0000000..097f125 --- /dev/null +++ b/test/oldof/oldof_virtual.cpp @@ -0,0 +1,103 @@ + +#include +#include +#include +#include +#include +#include +#include + +// Test old-values evaluated and copied only once, in virtual calls. + +unsigned copy_count, eval_count; + +struct num { + int i; + num() : i(0) {} + num(num const& n) : i(n.i) { ++copy_count; } + num& operator=(num const& n) { ++copy_count; i = n.i; return *this; } +}; + +num& eval(num& n) { ++eval_count; return n; } + +struct once { + num n; + + void invariant() const {} // So base inv part of this test. + static void static_invariant() {} // So base static inv part of this test. + + virtual ~once() {} + + void inc_of(int const delta, boost::contract::virtual_body v = 0) { + auto old_n = BOOST_CONTRACT_OLDOF(v, eval(n)); + auto c = boost::contract::public_member(v, this) + .precondition([&] {}) // So base pre part of this test. + .postcondition([&] { // So base post part of this test. + BOOST_CONTRACT_ASSERT(n.i >= old_n->i + delta); + }) + ; + inc_of_body(delta); + } + virtual void inc_of_body(int const delta) { n.i = n.i + delta; } +}; + +struct twice + #define BASES public once + : BASES +{ + typedef BOOST_CONTRACT_BASE_TYPES(BASES) base_types; + #undef BASES + + void invariant() const {} // So derived inv part of this test. + static void static_invariant() {} // So base static inv part of this test. + + virtual ~twice() {} + + void inc_of(int const delta) { + auto c = boost::contract::public_member(this, + &twice::inc_of, delta) + .precondition([&] {}) // So derived pre part of this test. + .postcondition([&] {}) // So derived post part of this test. + ; + inc_of_body(delta); + } + virtual void inc_of_body(int const delta) { n.i = (n.i + delta) * 2; } + BOOST_CONTRACT_INTROSPECT(inc_of) +}; + +int main() { + // Test direct user call. + + copy_count = eval_count = 0; + once x; + x.n.i = 1; + x.inc_of(1); // 1 + 1 = 2 + + BOOST_TEST_EQ(x.n.i, 2); +#ifdef BOOST_CONTRACT_CONFIG_NO_POSTCONDITIONS + BOOST_TEST_EQ(copy_count, 0); + BOOST_TEST_EQ(eval_count, 0); +#else + BOOST_TEST_EQ(copy_count, 1); + BOOST_TEST_EQ(eval_count, 1); +#endif + + // Test call via overridden virtual function. + + copy_count = eval_count = 0; + twice y; + y.n.i = 1; + y.inc_of(1); // (1 + 1) * 2 = 4 + + BOOST_TEST_EQ(y.n.i, 4); +#ifdef BOOST_CONTRACT_CONFIG_NO_POSTCONDITIONS + BOOST_TEST_EQ(copy_count, 0); + BOOST_TEST_EQ(eval_count, 0); +#else + BOOST_TEST_EQ(copy_count, 1); + BOOST_TEST_EQ(eval_count, 1); +#endif + + return boost::report_errors(); +} +