From 53e53171c4860fd90a4020b9424854f51623a18e Mon Sep 17 00:00:00 2001 From: Andrzej Krzemienski Date: Sat, 22 Nov 2014 01:18:25 +0100 Subject: [PATCH 01/23] none_t is no loner constructible from literal 0 This caused problems because: optional o = 0; always worked. But often it would create an uninitialized optional. --- .../tutorial/relational_operators.html | 2 +- doc/html/index.html | 7 +++--- include/boost/none.hpp | 25 +++++++++++++++++++ include/boost/none_t.hpp | 6 ++++- test/Jamfile.v2 | 1 + test/optional_test_common.cpp | 2 ++ test/optional_test_fail_convert_from_null.cpp | 25 +++++++++++++++++++ 7 files changed, 63 insertions(+), 5 deletions(-) create mode 100644 test/optional_test_fail_convert_from_null.cpp diff --git a/doc/html/boost_optional/tutorial/relational_operators.html b/doc/html/boost_optional/tutorial/relational_operators.html index bc97e7b..683fedc 100644 --- a/doc/html/boost_optional/tutorial/relational_operators.html +++ b/doc/html/boost_optional/tutorial/relational_operators.html @@ -30,7 +30,7 @@

Type optional<T> is EqualityComparable whenever T is EqualityComparable. Two optional - objects containing a value compare in the same as their contained values. + objects containing a value compare in the same way as their contained values. The uninitialized state of optional<T> is treated as a distinct value, equal to itself, and unequal to any value of type T: diff --git a/doc/html/index.html b/doc/html/index.html index 3e4f671..5826320 100644 --- a/doc/html/index.html +++ b/doc/html/index.html @@ -108,8 +108,9 @@ It is possible that this parameter is not specified; such situation is no error. It is valid to not specify the parameter and in that case the program is supposed to behave slightly differently. Also, suppose that any possible value of type - int is a valid value for "MaxValue", so we cannot jut use -1 to represent - the absence of the parameter in the config file. + int is a valid value for "MaxValue", so we cannot just use + -1 + to represent the absence of the parameter in the config file.

@@ -133,7 +134,7 @@ - +

Last revised: September 12, 2014 at 09:54:26 GMT

Last revised: November 21, 2014 at 23:32:40 GMT


diff --git a/include/boost/none.hpp b/include/boost/none.hpp index e9fc062..87a6c70 100644 --- a/include/boost/none.hpp +++ b/include/boost/none.hpp @@ -1,4 +1,5 @@ // Copyright (C) 2003, Fernando Luis Cacciola Carballal. +// Copyright (C) 2014 Andrzej Krzemienski. // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at @@ -20,7 +21,31 @@ namespace boost { +#ifdef BOOST_OPTIONAL_USE_OLD_DEFINITION_OF_NONE none_t const none = (static_cast(0)) ; +#else + +namespace detail { namespace optional_detail { + + // the trick here is to make boost::none defined once as a global but in a header file + template + struct none_instance + { + static const T instance; + }; + + template + const T none_instance::instance = T(); // global, but because 'tis a template, no cpp file required + +} } // namespace detail::optional_detail + + +namespace { + // TU-local + const none_t& none = detail::optional_detail::none_instance::instance; +} + +#endif } // namespace boost diff --git a/include/boost/none_t.hpp b/include/boost/none_t.hpp index 63ad926..13ce455 100644 --- a/include/boost/none_t.hpp +++ b/include/boost/none_t.hpp @@ -1,4 +1,5 @@ // Copyright (C) 2003, Fernando Luis Cacciola Carballal. +// Copyright (C) 2014 Andrzej Krzemienski. // // Use, modification, and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at @@ -14,9 +15,12 @@ namespace boost { +#ifdef BOOST_OPTIONAL_USE_OLD_DEFINITION_OF_NONE namespace detail { struct none_helper{}; } - typedef int detail::none_helper::*none_t ; +#else +class none_t {}; +#endif } // namespace boost diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index aeb0900..aeaef2b 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -41,6 +41,7 @@ import testing ; [ compile-fail optional_test_ref_fail_init_from_Urefref.cpp ] [ compile-fail optional_test_ref_fail_assign_from_Trefref.cpp ] [ compile-fail optional_test_ref_fail_assign_from_Urefref.cpp ] + [ compile-fail optional_test_fail_convert_from_null.cpp ] [ compile-fail optional_test_fail_explicit_convert_in_value_or.cpp ] [ compile-fail optional_test_fail_explicit_convert_in_value_or_call.cpp ] ; diff --git a/test/optional_test_common.cpp b/test/optional_test_common.cpp index 532b74e..a527bd7 100644 --- a/test/optional_test_common.cpp +++ b/test/optional_test_common.cpp @@ -51,6 +51,8 @@ using boost::get_pointer ; // via the safe_bool operator. #if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1300) ) // 1300 == VC++ 7.1 #define BOOST_OPTIONAL_NO_NULL_COMPARE +#else +#define BOOST_OPTIONAL_NO_NULL_COMPARE // Andrzej: I also disable 0 comparison everywhere #endif #define ARG(T) (static_cast< T const* >(0)) diff --git a/test/optional_test_fail_convert_from_null.cpp b/test/optional_test_fail_convert_from_null.cpp new file mode 100644 index 0000000..a454615 --- /dev/null +++ b/test/optional_test_fail_convert_from_null.cpp @@ -0,0 +1,25 @@ +// Copyright (C) 2014, Andrzej Krzemienski. +// +// Use, modification, and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/lib/optional for documentation. +// +// You are welcome to contact the author at: +// akrzemi1@gmail.com +// +#include "boost/optional.hpp" + +// +// THIS TEST SHOULD FAIL TO COMPILE +// + +struct NoInitFromNull{}; + +void test_conversion_from_null() +{ + boost::optional opt = 0; +} + + From 1d3446304bce7ab730448a3b2fdb78945e06f422 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Hunold?= Date: Mon, 24 Nov 2014 15:38:24 +0100 Subject: [PATCH 02/23] Add operator<< for boost::none --- include/boost/optional/optional_io.hpp | 9 +++++++++ test/optional_test_io.cpp | 10 ++++++++++ 2 files changed, 19 insertions(+) diff --git a/include/boost/optional/optional_io.hpp b/include/boost/optional/optional_io.hpp index 4c1c610..e7d1a4c 100644 --- a/include/boost/optional/optional_io.hpp +++ b/include/boost/optional/optional_io.hpp @@ -23,6 +23,15 @@ namespace boost { +template +inline +std::basic_ostream& +operator<<(std::basic_ostream& out, none_t const&) +{ + out << "--"; + return out; +} + template inline std::basic_ostream& diff --git a/test/optional_test_io.cpp b/test/optional_test_io.cpp index d4ee207..3ed0511 100644 --- a/test/optional_test_io.cpp +++ b/test/optional_test_io.cpp @@ -75,12 +75,22 @@ void test( T v, T w ) test2( optional () , make_optional(w)); } +void +test() +{ + stringstream s ; + s << boost::none; + BOOST_ASSERT(s.str() == "--"); +} + + int test_main( int, char* [] ) { try { test(1,2); test(string("hello"),string("buffer")); + test(); } catch ( ... ) { From 0d06d66f5c8c3942df4416680bb975ae928238b4 Mon Sep 17 00:00:00 2001 From: Andrzej Krzemienski Date: Mon, 24 Nov 2014 22:53:59 +0100 Subject: [PATCH 03/23] Improvement to "cout << none" implementation --- include/boost/optional/optional_io.hpp | 10 ++++--- test/optional_test_io.cpp | 37 ++++++++++++++++++++------ 2 files changed, 36 insertions(+), 11 deletions(-) diff --git a/include/boost/optional/optional_io.hpp b/include/boost/optional/optional_io.hpp index e7d1a4c..f0ad8ab 100644 --- a/include/boost/optional/optional_io.hpp +++ b/include/boost/optional/optional_io.hpp @@ -28,8 +28,12 @@ inline std::basic_ostream& operator<<(std::basic_ostream& out, none_t const&) { + if (out.good()) + { out << "--"; - return out; + } + + return out; } template @@ -37,9 +41,9 @@ inline std::basic_ostream& operator<<(std::basic_ostream& out, optional const& v) { - if ( out.good() ) + if (out.good()) { - if ( !v ) + if (!v) out << "--" ; else out << ' ' << *v ; } diff --git a/test/optional_test_io.cpp b/test/optional_test_io.cpp index 3ed0511..a4877d5 100644 --- a/test/optional_test_io.cpp +++ b/test/optional_test_io.cpp @@ -61,8 +61,8 @@ void test2( Opt o, Opt buff ) s << o << " " << markv ; s >> buff >> mark ; - BOOST_ASSERT( buff == o ) ; - BOOST_ASSERT( mark == markv ) ; + BOOST_CHECK( buff == o ) ; + BOOST_CHECK( mark == markv ) ; } @@ -75,12 +75,32 @@ void test( T v, T w ) test2( optional () , make_optional(w)); } -void -test() + +template +void subtest_tag_none_reversibility_with_optional(optional ov) { - stringstream s ; - s << boost::none; - BOOST_ASSERT(s.str() == "--"); + stringstream s; + s << boost::none; + s >> ov; + BOOST_CHECK(!ov); +} + +template +void subtest_tag_none_equivalence_with_optional() +{ + stringstream s, r; + optional ov; + s << boost::none; + r << ov; + BOOST_CHECK(s.str() == r.str()); +} + +template +void test_tag_none(T v) +{ + subtest_tag_none_reversibility_with_optional(optional(v)); + subtest_tag_none_reversibility_with_optional(optional()); + subtest_tag_none_equivalence_with_optional(); } @@ -90,7 +110,8 @@ int test_main( int, char* [] ) { test(1,2); test(string("hello"),string("buffer")); - test(); + test_tag_none(10); + test_tag_none(string("text")); } catch ( ... ) { From 1e2aed827683fbe00508e99d27ad1cf3566fc7cf Mon Sep 17 00:00:00 2001 From: Andrzej Krzemienski Date: Sat, 29 Nov 2014 22:51:45 +0100 Subject: [PATCH 04/23] unit test improvements I have split tests for conversions from uptional and from U to optional. I have split the optional refs tests that are expected to pass on all compilers. I started using lightweight_test instead of Boost.Test (now only in some files). --- test/Jamfile.v2 | 2 + test/optional_test.cpp | 37 ----- test/optional_test_conversions_from_U.cpp | 111 +++++++++++++++ test/optional_test_equals_none.cpp | 47 ++----- test/optional_test_ref_portable_minimum.cpp | 147 ++++++++++++++++++++ 5 files changed, 271 insertions(+), 73 deletions(-) create mode 100644 test/optional_test_conversions_from_U.cpp create mode 100644 test/optional_test_ref_portable_minimum.cpp diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index aeaef2b..49d6df0 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -17,8 +17,10 @@ import testing ; { test-suite optional : [ run optional_test.cpp ] + [ run optional_test_conversions_from_U.cpp ] [ run optional_test_tie.cpp ] [ run optional_test_ref.cpp ] + [ run optional_test_ref_portable_minimum.cpp ] [ run optional_test_inplace.cpp ] [ run optional_test_io.cpp ] [ run optional_test_move.cpp ] diff --git a/test/optional_test.cpp b/test/optional_test.cpp index e34ce7e..1247965 100644 --- a/test/optional_test.cpp +++ b/test/optional_test.cpp @@ -906,41 +906,6 @@ void test_no_implicit_conversions() test_no_implicit_conversions_impl(p); } -struct A {} ; -void test_conversions1() -{ - TRACE( std::endl << BOOST_CURRENT_FUNCTION ); - -#ifndef BOOST_OPTIONAL_NO_CONVERTING_COPY_CTOR - char c = 20 ; - optional opt0(c); - optional opt1(opt0); - BOOST_CHECK(*opt1 == static_cast(c)); -#endif - -#ifndef BOOST_OPTIONAL_NO_CONVERTING_ASSIGNMENT - float f = 21.22f ; - double d = f ; - optional opt2(f) ; - optional opt3 ; - opt3 = opt2 ; - BOOST_CHECK(*opt3 == d); -#endif -} - -void test_conversions2() -{ - TRACE( std::endl << BOOST_CURRENT_FUNCTION ); - - char c = 20 ; - optional opt(c); - BOOST_CHECK( get(opt) == static_cast(c)); - - float f = 21.22f ; - optional opt1; - opt1 = f ; - BOOST_CHECK(*get(&opt1) == static_cast(f)); -} namespace optional_swap_test @@ -1307,8 +1272,6 @@ int test_main( int, char* [] ) test_with_class_type(); test_with_builtin_types(); test_no_implicit_conversions(); - test_conversions1(); - test_conversions2(); test_swap_tweaking(); test_custom_addressof_operator(); } diff --git a/test/optional_test_conversions_from_U.cpp b/test/optional_test_conversions_from_U.cpp new file mode 100644 index 0000000..57d8215 --- /dev/null +++ b/test/optional_test_conversions_from_U.cpp @@ -0,0 +1,111 @@ +// Copyright (C) 2014 Andrzej Krzemienski. +// +// Use, modification, and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/lib/optional for documentation. +// +// You are welcome to contact the author at: akrzemi1@gmail.com + + +#include "boost/optional/optional.hpp" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#include "boost/core/lightweight_test.hpp" + +using boost::optional; + + +// testing types: +// X is convertible to Y +// ADeriv is convertible to ABase +struct X +{ + int val; + explicit X(int v) : val(v) {} +}; + +struct Y +{ + int yval; + Y(X const& x) : yval(x.val) {} + friend bool operator==(Y const& l, Y const& r) { return l.yval == r.yval; } +}; + +struct ABase +{ + int val; + explicit ABase(int v) : val(v) {} + friend bool operator==(ABase const& l, ABase const& r) { return l.val == r.val; } +}; + +struct ADeriv : ABase +{ + explicit ADeriv(int v) : ABase(v) {} +}; + + +template +void test_convert_optional_U_to_optional_T_for() +{ +#ifndef BOOST_OPTIONAL_NO_CONVERTING_COPY_CTOR + { + optional ou(U(8)); + optional ot1(ou); + BOOST_TEST(ot1); + BOOST_TEST(*ot1 == T(*ou)); + } +#endif + +#ifndef BOOST_OPTIONAL_NO_CONVERTING_ASSIGNMENT + { + optional ou(U(8)); + optional ot2; + ot2 = ou; + BOOST_TEST(ot2); + BOOST_TEST(*ot2 == T(*ou)); + } +#endif +} + +void test_convert_optional_U_to_optional_T() +{ + test_convert_optional_U_to_optional_T_for(); + test_convert_optional_U_to_optional_T_for(); + test_convert_optional_U_to_optional_T_for(); + test_convert_optional_U_to_optional_T_for(); +} + +template +void test_convert_U_to_optional_T_for() +{ + U u(8); + optional ot1(u); + BOOST_TEST(ot1); + BOOST_TEST(*ot1 == T(u)); + + optional ot2; + ot2 = u; + BOOST_TEST(ot2); + BOOST_TEST(*ot2 == T(u)); +} + +void test_convert_U_to_optional_T() +{ + test_convert_U_to_optional_T_for(); + test_convert_U_to_optional_T_for(); + test_convert_U_to_optional_T_for(); + test_convert_U_to_optional_T_for(); +} + +int main() +{ + test_convert_optional_U_to_optional_T(); + test_convert_U_to_optional_T(); + + return boost::report_errors(); +} diff --git a/test/optional_test_equals_none.cpp b/test/optional_test_equals_none.cpp index aed7771..1c8c5d8 100644 --- a/test/optional_test_equals_none.cpp +++ b/test/optional_test_equals_none.cpp @@ -8,18 +8,6 @@ // // You are welcome to contact the author at: // akrzemi1@gmail.com -// -// Revisions: -// -#include -#include -#include - -#define BOOST_ENABLE_ASSERT_HANDLER - -#include "boost/bind/apply.hpp" // Included just to test proper interaction with boost::apply<> as reported by Daniel Wallin -#include "boost/mpl/bool.hpp" -#include "boost/mpl/bool_fwd.hpp" // For mpl::true_ and mpl::false_ #include "boost/optional/optional.hpp" @@ -27,11 +15,9 @@ #pragma hdrstop #endif +#include "boost/core/lightweight_test.hpp" #include "boost/none.hpp" -#include "boost/test/minimal.hpp" - -#include "optional_test_common.cpp" struct SemiRegular // no operator== { @@ -41,28 +27,17 @@ private: void operator!=(SemiRegular const&) const {} void test_equal_to_none_of_noncomparable_T() { - optional i = SemiRegular(); - optional o; - - BOOST_CHECK(i != boost::none); - BOOST_CHECK(boost::none != i); - BOOST_CHECK(o == boost::none); - BOOST_CHECK(boost::none == o); + boost::optional i = SemiRegular(); + boost::optional o; + + BOOST_TEST(i != boost::none); + BOOST_TEST(boost::none != i); + BOOST_TEST(o == boost::none); + BOOST_TEST(boost::none == o); } -int test_main( int, char* [] ) +int main() { - try - { - test_equal_to_none_of_noncomparable_T(); - - } - catch ( ... ) - { - BOOST_ERROR("Unexpected Exception caught!"); - } - - return 0; + test_equal_to_none_of_noncomparable_T(); + return boost::report_errors(); } - - diff --git a/test/optional_test_ref_portable_minimum.cpp b/test/optional_test_ref_portable_minimum.cpp new file mode 100644 index 0000000..8555723 --- /dev/null +++ b/test/optional_test_ref_portable_minimum.cpp @@ -0,0 +1,147 @@ +// Copyright (C) 2014 Andrzej Krzemienski. +// +// Use, modification, and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/lib/optional for documentation. +// +// You are welcome to contact the author at: akrzemi1@gmail.com + + +#include "boost/optional/optional.hpp" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#include "boost/core/addressof.hpp" +#include "boost/core/lightweight_test.hpp" +#include "boost/none.hpp" + +using boost::optional; +using boost::none; + +// testable classes +struct ScopeGuard // no copy/move ctor/assign +{ + int val; + explicit ScopeGuard(int v) : val(v) {} + +private: + ScopeGuard(ScopeGuard const&); + void operator=(ScopeGuard const&); +}; + +struct Abstract +{ + virtual int& val() = 0; + virtual ~Abstract() {} + Abstract(){} +private: + Abstract(Abstract const&); + void operator=(Abstract const&); +}; + +struct Impl : Abstract +{ + int val_; + Impl(int v) : val_(v) {} + int& val() { return val_; } +}; + +template +struct concrete_type_of +{ + typedef T type; +}; + +template <> +struct concrete_type_of +{ + typedef Impl type; +}; + +int& val(int& i) { return i; } +int& val(Abstract& a) { return a.val(); } +int& val(ScopeGuard& g) { return g.val; } + +template +void test_not_containing_value_for() +{ + optional o1; + optional o2 = none; + optional o3 = o1; + + BOOST_TEST(!o1); + BOOST_TEST(!o2); + BOOST_TEST(!o3); + + BOOST_TEST(o1 == none); + BOOST_TEST(o2 == none); + BOOST_TEST(o3 == none); +} + +template +void test_direct_init_for() +{ + typename concrete_type_of::type v(2); + optional o(v); + + BOOST_TEST(o); + BOOST_TEST(o != none); + BOOST_TEST(boost::addressof(*o) == boost::addressof(v)); + BOOST_TEST(val(*o) == val(v)); + + val(v) = 9; + BOOST_TEST(boost::addressof(*o) == boost::addressof(v)); + BOOST_TEST(val(*o) == val(v)); + BOOST_TEST(val(*o) == 9); + + val(*o) = 7; + BOOST_TEST(boost::addressof(*o) == boost::addressof(v)); + BOOST_TEST(val(*o) == val(v)); + BOOST_TEST(val(*o) == 7); +} + +template +void test_copy_assignment_for() +{ + typename concrete_type_of::type v(2); + optional o; + o = optional(v); + + BOOST_TEST(o); + BOOST_TEST(o != none); + BOOST_TEST(boost::addressof(*o) == boost::addressof(v)); + BOOST_TEST(val(*o) == val(v)); + BOOST_TEST(val(*o) == 2); + + val(v) = 9; + BOOST_TEST(boost::addressof(*o) == boost::addressof(v)); + BOOST_TEST(val(*o) == val(v)); + BOOST_TEST(val(*o) == 9); + + val(*o) = 7; + BOOST_TEST(boost::addressof(*o) == boost::addressof(v)); + BOOST_TEST(val(*o) == val(v)); + BOOST_TEST(val(*o) == 7); +} + + +template +void test_optional_ref() +{ + test_not_containing_value_for(); + test_direct_init_for(); + test_copy_assignment_for(); +} + +int main() +{ + test_optional_ref(); + test_optional_ref(); + test_optional_ref(); + + return boost::report_errors(); +} From 4df589686c387612ba102c75eb9833a2610e93ea Mon Sep 17 00:00:00 2001 From: Andrzej Krzemienski Date: Mon, 1 Dec 2014 18:03:46 +0100 Subject: [PATCH 05/23] refactoring optional ref tests --- test/Jamfile.v2 | 1 + test/optional_test_move.cpp | 40 ------- test/optional_test_noexcept_move.cpp | 86 ++++++++++++++ test/optional_test_ref.cpp | 41 ------- test/optional_test_ref_portable_minimum.cpp | 125 +++++++++++++++++--- test/optional_test_value_access.cpp | 116 ++++++------------ 6 files changed, 235 insertions(+), 174 deletions(-) create mode 100644 test/optional_test_noexcept_move.cpp diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 49d6df0..46ed39c 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -24,6 +24,7 @@ import testing ; [ run optional_test_inplace.cpp ] [ run optional_test_io.cpp ] [ run optional_test_move.cpp ] + [ run optional_test_noexcept_move.cpp ] [ run optional_test_equals_none.cpp ] [ run optional_test_value_access.cpp ] [ run optional_test_emplace.cpp ] diff --git a/test/optional_test_move.cpp b/test/optional_test_move.cpp index affa07f..779e0c7 100644 --- a/test/optional_test_move.cpp +++ b/test/optional_test_move.cpp @@ -343,46 +343,6 @@ void test_optional_ref_to_movables() BOOST_CHECK(orm2->val == 4); } -// these 4 classes have different noexcept signatures in move operations -struct NothrowBoth { - NothrowBoth(NothrowBoth&&) BOOST_NOEXCEPT_IF(true) {}; - void operator=(NothrowBoth&&) BOOST_NOEXCEPT_IF(true) {}; -}; -struct NothrowCtor { - NothrowCtor(NothrowCtor&&) BOOST_NOEXCEPT_IF(true) {}; - void operator=(NothrowCtor&&) BOOST_NOEXCEPT_IF(false) {}; -}; -struct NothrowAssign { - NothrowAssign(NothrowAssign&&) BOOST_NOEXCEPT_IF(false) {}; - void operator=(NothrowAssign&&) BOOST_NOEXCEPT_IF(true) {}; -}; -struct NothrowNone { - NothrowNone(NothrowNone&&) BOOST_NOEXCEPT_IF(false) {}; - void operator=(NothrowNone&&) BOOST_NOEXCEPT_IF(false) {}; -}; - -#ifndef BOOST_NO_NOEXCEPT - -void test_noexcept() // this is a compile-time test -{ - BOOST_STATIC_ASSERT(::boost::is_nothrow_move_constructible >::value); - BOOST_STATIC_ASSERT(::boost::is_nothrow_move_assignable >::value); - BOOST_STATIC_ASSERT(BOOST_NOEXCEPT_EXPR(optional())); - - BOOST_STATIC_ASSERT(::boost::is_nothrow_move_constructible >::value); - BOOST_STATIC_ASSERT(!::boost::is_nothrow_move_assignable >::value); - BOOST_STATIC_ASSERT(BOOST_NOEXCEPT_EXPR(optional())); - - BOOST_STATIC_ASSERT(!::boost::is_nothrow_move_constructible >::value); - BOOST_STATIC_ASSERT(!::boost::is_nothrow_move_assignable >::value); - BOOST_STATIC_ASSERT(BOOST_NOEXCEPT_EXPR(optional())); - - BOOST_STATIC_ASSERT(!::boost::is_nothrow_move_constructible >::value); - BOOST_STATIC_ASSERT(!::boost::is_nothrow_move_assignable >::value); - BOOST_STATIC_ASSERT(BOOST_NOEXCEPT_EXPR(optional())); -} -#endif // !defned BOOST_NO_NOEXCEPT - #endif int test_main( int, char* [] ) diff --git a/test/optional_test_noexcept_move.cpp b/test/optional_test_noexcept_move.cpp new file mode 100644 index 0000000..e072785 --- /dev/null +++ b/test/optional_test_noexcept_move.cpp @@ -0,0 +1,86 @@ +// Copyright (C) 2014 Andrzej Krzemienski. +// +// Use, modification, and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/lib/optional for documentation. +// +// You are welcome to contact the author at: +// akrzemi1@gmail.com + +#include "boost/static_assert.hpp" +#include "boost/optional/optional.hpp" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + + +using boost::optional; + + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +#ifndef BOOST_NO_NOEXCEPT + +// these 4 classes have different noexcept signatures in move operations +struct NothrowBoth { + NothrowBoth(NothrowBoth&&) BOOST_NOEXCEPT_IF(true) {}; + void operator=(NothrowBoth&&) BOOST_NOEXCEPT_IF(true) {}; +}; +struct NothrowCtor { + NothrowCtor(NothrowCtor&&) BOOST_NOEXCEPT_IF(true) {}; + void operator=(NothrowCtor&&) BOOST_NOEXCEPT_IF(false) {}; +}; +struct NothrowAssign { + NothrowAssign(NothrowAssign&&) BOOST_NOEXCEPT_IF(false) {}; + void operator=(NothrowAssign&&) BOOST_NOEXCEPT_IF(true) {}; +}; +struct NothrowNone { + NothrowNone(NothrowNone&&) BOOST_NOEXCEPT_IF(false) {}; + void operator=(NothrowNone&&) BOOST_NOEXCEPT_IF(false) {}; +}; + +void test_noexcept_as_defined() // this is a compile-time test +{ + BOOST_STATIC_ASSERT(::boost::is_nothrow_move_constructible::value); + BOOST_STATIC_ASSERT(::boost::is_nothrow_move_assignable::value); + + BOOST_STATIC_ASSERT(::boost::is_nothrow_move_constructible::value); + BOOST_STATIC_ASSERT(!::boost::is_nothrow_move_assignable::value); + + BOOST_STATIC_ASSERT(!::boost::is_nothrow_move_constructible::value); + BOOST_STATIC_ASSERT(::boost::is_nothrow_move_assignable::value); + + BOOST_STATIC_ASSERT(!::boost::is_nothrow_move_constructible::value); + BOOST_STATIC_ASSERT(!::boost::is_nothrow_move_assignable::value); +} + +void test_noexcept_on_optional() // this is a compile-time test +{ + BOOST_STATIC_ASSERT(::boost::is_nothrow_move_constructible >::value); + BOOST_STATIC_ASSERT(::boost::is_nothrow_move_assignable >::value); + BOOST_STATIC_ASSERT(BOOST_NOEXCEPT_EXPR(optional())); + + BOOST_STATIC_ASSERT(::boost::is_nothrow_move_constructible >::value); + BOOST_STATIC_ASSERT(!::boost::is_nothrow_move_assignable >::value); + BOOST_STATIC_ASSERT(BOOST_NOEXCEPT_EXPR(optional())); + + BOOST_STATIC_ASSERT(!::boost::is_nothrow_move_constructible >::value); + BOOST_STATIC_ASSERT(!::boost::is_nothrow_move_assignable >::value); + BOOST_STATIC_ASSERT(BOOST_NOEXCEPT_EXPR(optional())); + + BOOST_STATIC_ASSERT(!::boost::is_nothrow_move_constructible >::value); + BOOST_STATIC_ASSERT(!::boost::is_nothrow_move_assignable >::value); + BOOST_STATIC_ASSERT(BOOST_NOEXCEPT_EXPR(optional())); +} + +#endif // !defned BOOST_NO_NOEXCEPT +#endif // !defined BOOST_NO_CXX11_RVALUE_REFERENCES + +int main() +{ + return 0; +} + + diff --git a/test/optional_test_ref.cpp b/test/optional_test_ref.cpp index c01b08e..830840b 100644 --- a/test/optional_test_ref.cpp +++ b/test/optional_test_ref.cpp @@ -278,51 +278,12 @@ void test_relops( T const* ) BOOST_CHECK ( opt1 >= opt0 ) ; } -template -void test_none( T const* ) -{ - TRACE( std::endl << BOOST_CURRENT_FUNCTION ); - - using boost::none ; - - T a(1234); - - optional def0 ; - optional def1(none) ; - optional non_def(a) ; - - BOOST_CHECK ( def0 == none ) ; - BOOST_CHECK ( non_def != none ) ; - BOOST_CHECK ( !def1 ) ; - - non_def = none ; - BOOST_CHECK ( !non_def ) ; -} - -template -void test_arrow( T const* ) -{ - TRACE( std::endl << BOOST_CURRENT_FUNCTION ); - - T a(1234); - - optional oa(a) ; - optional const coa(a) ; - - BOOST_CHECK ( coa->V() == 1234 ) ; - - oa->V() = 4321 ; - - BOOST_CHECK ( a.V() = 4321 ) ; -} - void test_with_builtin_types() { TRACE( std::endl << BOOST_CURRENT_FUNCTION ); test_basics( ARG(double) ); test_relops( ARG(double) ) ; - test_none ( ARG(double) ) ; } void test_with_class_type() @@ -331,8 +292,6 @@ void test_with_class_type() test_basics( ARG(X) ); test_relops( ARG(X) ) ; - test_none ( ARG(X) ) ; - test_arrow ( ARG(X) ) ; BOOST_CHECK ( X::count == 0 ) ; } diff --git a/test/optional_test_ref_portable_minimum.cpp b/test/optional_test_ref_portable_minimum.cpp index 8555723..4439d8c 100644 --- a/test/optional_test_ref_portable_minimum.cpp +++ b/test/optional_test_ref_portable_minimum.cpp @@ -16,8 +16,8 @@ #endif #include "boost/core/addressof.hpp" +#include "boost/core/enable_if.hpp" #include "boost/core/lightweight_test.hpp" -#include "boost/none.hpp" using boost::optional; using boost::none; @@ -25,8 +25,9 @@ using boost::none; // testable classes struct ScopeGuard // no copy/move ctor/assign { - int val; - explicit ScopeGuard(int v) : val(v) {} + int val_; + explicit ScopeGuard(int v) : val_(v) {} + int& val() { return val_; } private: ScopeGuard(ScopeGuard const&); @@ -38,6 +39,7 @@ struct Abstract virtual int& val() = 0; virtual ~Abstract() {} Abstract(){} + private: Abstract(Abstract const&); void operator=(Abstract const&); @@ -62,9 +64,44 @@ struct concrete_type_of typedef Impl type; }; +template +struct has_arrow +{ + static const bool value = true; +}; + +template <> +struct has_arrow +{ + static const bool value = false; +}; + int& val(int& i) { return i; } int& val(Abstract& a) { return a.val(); } -int& val(ScopeGuard& g) { return g.val; } +int& val(ScopeGuard& g) { return g.val(); } + +// end testable classes + +template +typename boost::enable_if< has_arrow >::type +test_arrow() +{ + typename concrete_type_of::type v(2); + optional o(v); + BOOST_TEST(o); + BOOST_TEST_EQ(o->val(), 2); + + o->val() = 3; + BOOST_TEST(o); + BOOST_TEST_EQ(o->val(), 3); + BOOST_TEST_EQ(v.val(), 3); +} + +template +typename boost::disable_if< has_arrow >::type +test_arrow() +{ +} template void test_not_containing_value_for() @@ -91,17 +128,41 @@ void test_direct_init_for() BOOST_TEST(o); BOOST_TEST(o != none); BOOST_TEST(boost::addressof(*o) == boost::addressof(v)); - BOOST_TEST(val(*o) == val(v)); + BOOST_TEST_EQ(val(*o), val(v)); + BOOST_TEST_EQ(val(*o), 2); val(v) = 9; BOOST_TEST(boost::addressof(*o) == boost::addressof(v)); - BOOST_TEST(val(*o) == val(v)); - BOOST_TEST(val(*o) == 9); + BOOST_TEST_EQ(val(*o), val(v)); + BOOST_TEST_EQ(val(*o), 9); + BOOST_TEST_EQ(val(v), 9); val(*o) = 7; BOOST_TEST(boost::addressof(*o) == boost::addressof(v)); - BOOST_TEST(val(*o) == val(v)); - BOOST_TEST(val(*o) == 7); + BOOST_TEST_EQ(val(*o), val(v)); + BOOST_TEST_EQ(val(*o), 7); + BOOST_TEST_EQ(val(v), 7); +} + +template +void test_clearing_the_value() +{ + typename concrete_type_of::type v(2); + optional o1(v), o2(v); + + BOOST_TEST(o1); + BOOST_TEST(o1 != none); + BOOST_TEST(o2); + BOOST_TEST(o2 != none); + + o1 = none; + BOOST_TEST(!o1); + BOOST_TEST(o1 == none); + BOOST_TEST(o2); + BOOST_TEST(o2 != none); + BOOST_TEST_EQ(val(*o2), 2); + BOOST_TEST(boost::addressof(*o2) == boost::addressof(v)); + BOOST_TEST_EQ(val(v), 2); } template @@ -119,13 +180,46 @@ void test_copy_assignment_for() val(v) = 9; BOOST_TEST(boost::addressof(*o) == boost::addressof(v)); - BOOST_TEST(val(*o) == val(v)); - BOOST_TEST(val(*o) == 9); + BOOST_TEST_EQ(val(*o), val(v)); + BOOST_TEST_EQ(val(*o), 9); + BOOST_TEST_EQ(val(v), 9); val(*o) = 7; BOOST_TEST(boost::addressof(*o) == boost::addressof(v)); - BOOST_TEST(val(*o) == val(v)); - BOOST_TEST(val(*o) == 7); + BOOST_TEST_EQ(val(*o), val(v)); + BOOST_TEST_EQ(val(*o), 7); + BOOST_TEST_EQ(val(v), 7); +} + +template +void test_rebinding_assignment_semantics() +{ + typename concrete_type_of::type v(2), w(7); + optional o(v); + + BOOST_TEST(o); + BOOST_TEST(boost::addressof(*o) == boost::addressof(v)); + BOOST_TEST_EQ(val(*o), val(v)); + BOOST_TEST_EQ(val(*o), 2); + + o = optional(w); + BOOST_TEST_EQ(val(v), 2); + + BOOST_TEST(o); + BOOST_TEST(boost::addressof(*o) != boost::addressof(v)); + BOOST_TEST_NE(val(*o), val(v)); + BOOST_TEST_NE(val(*o), 2); + + BOOST_TEST(boost::addressof(*o) == boost::addressof(w)); + BOOST_TEST_EQ(val(*o), val(w)); + BOOST_TEST_EQ(val(*o), 7); + + val(*o) = 8; + BOOST_TEST(boost::addressof(*o) == boost::addressof(w)); + BOOST_TEST_EQ(val(*o), val(w)); + BOOST_TEST_EQ(val(*o), 8); + BOOST_TEST_EQ(val(w), 8); + BOOST_TEST_EQ(val(v), 2); } @@ -135,13 +229,16 @@ void test_optional_ref() test_not_containing_value_for(); test_direct_init_for(); test_copy_assignment_for(); + test_rebinding_assignment_semantics(); + test_clearing_the_value(); + test_arrow(); } int main() { test_optional_ref(); test_optional_ref(); - test_optional_ref(); + //test_optional_ref(); return boost::report_errors(); } diff --git a/test/optional_test_value_access.cpp b/test/optional_test_value_access.cpp index 63d65b9..1759588 100644 --- a/test/optional_test_value_access.cpp +++ b/test/optional_test_value_access.cpp @@ -8,18 +8,6 @@ // // You are welcome to contact the author at: // akrzemi1@gmail.com -// -// Revisions: -// -#include -#include -#include - -#define BOOST_ENABLE_ASSERT_HANDLER - -#include "boost/bind/apply.hpp" // Included just to test proper interaction with boost::apply<> as reported by Daniel Wallin -#include "boost/mpl/bool.hpp" -#include "boost/mpl/bool_fwd.hpp" // For mpl::true_ and mpl::false_ #include "boost/optional/optional.hpp" @@ -27,11 +15,10 @@ #pragma hdrstop #endif -#include "boost/none.hpp" +#include "boost/core/ignore_unused.hpp" +#include "boost/core/lightweight_test.hpp" -#include "boost/test/minimal.hpp" - -#include "optional_test_common.cpp" +using boost::optional; struct IntWrapper { @@ -48,10 +35,10 @@ void test_function_value_or_for() optional oM1(1); const optional oC2(2); - BOOST_CHECK(oM0.value_or(5) == 5); - BOOST_CHECK(oC0.value_or(5) == 5); - BOOST_CHECK(oM1.value_or(5) == 1); - BOOST_CHECK(oC2.value_or(5) == 2); + BOOST_TEST(oM0.value_or(5) == 5); + BOOST_TEST(oC0.value_or(5) == 5); + BOOST_TEST(oM1.value_or(5) == 1); + BOOST_TEST(oC2.value_or(5) == 2); } template @@ -64,36 +51,24 @@ void test_function_value_for() try { T& v = o1.value(); - BOOST_CHECK(v == 1); + BOOST_TEST(v == 1); } catch(...) { - BOOST_CHECK(false); + BOOST_TEST(false); } try { T const& v = oC.value(); - BOOST_CHECK(v == 2); + BOOST_TEST(v == 2); } catch(...) { - BOOST_CHECK(false); + BOOST_TEST(false); } - try - { - T& v = o0.value(); - BOOST_CHECK(false); - boost::ignore_unused(v); - } - catch(boost::bad_optional_access const&) - { - } - catch(...) - { - BOOST_CHECK(false); - } + BOOST_TEST_THROWS(o0.value(), boost::bad_optional_access); } void test_function_value() @@ -120,12 +95,12 @@ void test_function_value_or() test_function_value_or_for(); optional oi(1); - BOOST_CHECK(oi.value_or(FatToIntConverter(2)) == 1); - BOOST_CHECK(FatToIntConverter::conversions == 0); + BOOST_TEST(oi.value_or(FatToIntConverter(2)) == 1); + BOOST_TEST(FatToIntConverter::conversions == 0); oi = boost::none; - BOOST_CHECK(oi.value_or(FatToIntConverter(2)) == 2); - BOOST_CHECK(FatToIntConverter::conversions == 1); + BOOST_TEST(oi.value_or(FatToIntConverter(2)) == 2); + BOOST_TEST(FatToIntConverter::conversions == 1); } @@ -156,42 +131,34 @@ void test_function_value_or_eval() FunM funM; FunC funC; - BOOST_CHECK(o1.value_or_eval(funM) == 1); - BOOST_CHECK(oN.value_or_eval(funM) == 5); - BOOST_CHECK(o1.value_or_eval(FunM()) == 1); - BOOST_CHECK(oN.value_or_eval(FunM()) == 5); + BOOST_TEST_EQ(o1.value_or_eval(funM), 1); + BOOST_TEST_EQ(oN.value_or_eval(funM), 5); + BOOST_TEST_EQ(o1.value_or_eval(FunM()), 1); + BOOST_TEST_EQ(oN.value_or_eval(FunM()), 5); - BOOST_CHECK(o1.value_or_eval(funC) == 1); - BOOST_CHECK(oN.value_or_eval(funC) == 6); - BOOST_CHECK(o1.value_or_eval(FunC()) == 1); - BOOST_CHECK(oN.value_or_eval(FunC()) == 6); + BOOST_TEST_EQ(o1.value_or_eval(funC), 1); + BOOST_TEST_EQ(oN.value_or_eval(funC), 6); + BOOST_TEST_EQ(o1.value_or_eval(FunC()), 1); + BOOST_TEST_EQ(oN.value_or_eval(FunC()), 6); - BOOST_CHECK(o1.value_or_eval(funP) == 1); - BOOST_CHECK(oN.value_or_eval(funP) == 7); + BOOST_TEST_EQ(o1.value_or_eval(funP), 1); + BOOST_TEST_EQ(oN.value_or_eval(funP), 7); #ifndef BOOST_NO_CXX11_LAMBDAS - BOOST_CHECK(o1.value_or_eval([](){return 8;}) == 1); - BOOST_CHECK(oN.value_or_eval([](){return 8;}) == 8); + BOOST_TEST_EQ(o1.value_or_eval([](){return 8;}), 1); + BOOST_TEST_EQ(oN.value_or_eval([](){return 8;}), 8); #endif try { - BOOST_CHECK(o1.value_or_eval(throw_) == 1); + BOOST_TEST_EQ(o1.value_or_eval(throw_), 1); } catch(...) { - BOOST_CHECK(false); + BOOST_TEST(false); } - try - { - BOOST_CHECK(oN.value_or_eval(throw_) == 1); - BOOST_CHECK(false); - } - catch(...) - { - BOOST_CHECK(true); - } + BOOST_TEST_THROWS(oN.value_or_eval(throw_), int); } const optional makeConstOptVal() @@ -244,21 +211,12 @@ void test_move_only_getters() #endif // !defined BOOST_NO_CXX11_REF_QUALIFIERS -int test_main( int, char* [] ) +int main() { - try - { - test_function_value(); - test_function_value_or(); - test_function_value_or_eval(); - test_const_move(); - } - catch ( ... ) - { - BOOST_ERROR("Unexpected Exception caught!"); - } + test_function_value(); + test_function_value_or(); + test_function_value_or_eval(); + test_const_move(); - return 0; + return boost::report_errors(); } - - From b5ae4bf78ddccd867021f216af265501076acdac Mon Sep 17 00:00:00 2001 From: Andrzej Krzemienski Date: Sat, 6 Dec 2014 19:27:53 +0100 Subject: [PATCH 06/23] Added performance notes to documentation --- doc/00_optional.qbk | 1 + doc/19_on_performance.qbk | 131 ++++++++++ .../tutorial/performance_considerations.html | 223 ++++++++++++++++++ .../tutorial/type_requirements.html | 6 +- doc/html/images/opt_align1.png | Bin 0 -> 417 bytes doc/html/images/opt_align2.png | Bin 0 -> 472 bytes doc/html/images/opt_align3.png | Bin 0 -> 468 bytes doc/html/images/opt_align4.png | Bin 0 -> 428 bytes doc/html/index.html | 4 +- doc/html/optional/reference.html | 6 +- doc/html/optional/tutorial.html | 2 + 11 files changed, 366 insertions(+), 7 deletions(-) create mode 100644 doc/19_on_performance.qbk create mode 100644 doc/html/boost_optional/tutorial/performance_considerations.html create mode 100644 doc/html/images/opt_align1.png create mode 100644 doc/html/images/opt_align2.png create mode 100644 doc/html/images/opt_align3.png create mode 100644 doc/html/images/opt_align4.png diff --git a/doc/00_optional.qbk b/doc/00_optional.qbk index 0693237..95c982f 100644 --- a/doc/00_optional.qbk +++ b/doc/00_optional.qbk @@ -85,6 +85,7 @@ This is how you solve it with `boost::optional`: [include 16_optional_bool.qbk] [include 17_exception_safety.qbk] [include 18_type_requirements.qbk] +[include 19_on_performance.qbk] [endsect] [section Reference] [include 20_reference.qbk] diff --git a/doc/19_on_performance.qbk b/doc/19_on_performance.qbk new file mode 100644 index 0000000..841190f --- /dev/null +++ b/doc/19_on_performance.qbk @@ -0,0 +1,131 @@ + +[section Performance considerations] + +Technical details aside, the memory layout of `optional` is more-less this: + + template + class optional + { + bool _initialized; + std::aligned_storage_t _storage; + }; + +But for the purpose of this analysis, considering memory layouts, we can think of it as: + + template + class optional + { + bool _initialized; + T _storage; + }; + +Given type `optional`, and assuming that `sizeof(int) == 4`, we will get `sizeof(optional) == 8`. This is so because of the alignment rules, for our two members we get the following alignment: + +[$images/opt_align1.png] + +This means you can fit twice as many `int`s as `optional`s into the same space of memory. Therefore, if the size of the objects is critical for your application (e.g., because you want to utilize your CPU cache in order to gain performance) and you have determined you are willing to trade the code clarity, it is recommended that you simply go with type `int` and use some 'magic value' to represent ['not-an-int]. + +Even if you cannot spare any value of `int` to represent ['not-an-int] (e.g., because every value is useful, or you do want to signal ['not-an-int] explicitly), at least for `Trivial` types you should consider storing the value and the `bool` flag representing the ['null-state] separately. Consider the following class: + + struct Record + { + optional _min; + optional _max; + }; + +Its memory layout can be depicted as follows: + +[$images/opt_align2.png] + +This is exactly the same as if we had the following members: + + struct Record + { + bool _has_min; + int _min; + bool _has_max; + int _max; + }; + +But when they are stored separately, we at least have an option to reorder them like this: + + struct Record + { + bool _has_min; + bool _has_max; + int _min; + int _max; + }; + +Which gives us the following layout (and smaller total size): + +[$images/opt_align3.png] + +Sometimes it requires detailed consideration what data we make optional. In our case above, if we determine that both minimum and maximum value can be provided or not provided together, but one is never provided without the other, we can make only one optional memebr: + + struct Limits + { + int _min; + int _max; + }; + + struct Record + { + optional _limits; + }; + +This would give us the following layout: + +[$images/opt_align4.png] + +[heading Optional function parameters] + +Having function parameters of type `const optional&` may incur certain unexpected run-time cost connected to copy construction of `T`. Consider the following code. + + void fun(const optional& v) + { + if (v) doSomethingWith(*v); + else doSomethingElse(); + } + + int main() + { + optional ov; + Big v; + fun(none); + fun(ov); // no copy + fun(v); // copy constructor of Big + } + +No copy elision or move semantics can save us from copying type `Big` here. Not that we need any copy, but this is how `optional` works. In order to avoid copying in this case, one could provide second overload of `fun`: + + void fun(const Big& v) + { + doSomethingWith(v); + } + + int main() + { + optional ov; + Big v; + fun(ov); // no copy + fun(v); // no copy: second overload selected + } + +Alternatively, you could consider using an optional reference instead: + + void fun(optional v) // note where the reference is + { + if (v) doSomethingWith(*v); + else doSomethingElse(); + } + + int main() + { + optional ov; + Big v; + fun(none); + fun(ov); // doesn't compile + fun(v); // no copy + } +[endsect] diff --git a/doc/html/boost_optional/tutorial/performance_considerations.html b/doc/html/boost_optional/tutorial/performance_considerations.html new file mode 100644 index 0000000..d054e01 --- /dev/null +++ b/doc/html/boost_optional/tutorial/performance_considerations.html @@ -0,0 +1,223 @@ + + + +Performance considerations + + + + + + + + + + + + + + + +
Boost C++ LibrariesHomeLibrariesPeopleFAQMore
+
+
+PrevUpHomeNext +
+
+ +

+ Technical details aside, the memory layout of optional<T> + is more-less this: +

+
template <typename T>
+class optional
+{
+  bool _initialized;
+  std::aligned_storage_t<sizeof(t), alignof(T)> _storage;
+};
+
+

+ But for the purpose of this analysis, considering memory layouts, we can + think of it as: +

+
template <typename T>
+class optional
+{
+  bool _initialized;
+  T _storage;
+};
+
+

+ Given type optional<int>, and + assuming that sizeof(int) == + 4, we will get sizeof(optional<int>) + == 8. + This is so because of the alignment rules, for our two members we get the + following alignment: +

+

+ opt_align1 +

+

+ This means you can fit twice as many ints + as optional<int>s into + the same space of memory. Therefore, if the size of the objects is critical + for your application (e.g., because you want to utilize your CPU cache in + order to gain performance) and you have determined you are willing to trade + the code clarity, it is recommended that you simply go with type int and use some 'magic value' to represent + not-an-int. +

+

+ Even if you cannot spare any value of int + to represent not-an-int (e.g., because every value is + useful, or you do want to signal not-an-int explicitly), + at least for Trivial types + you should consider storing the value and the bool + flag representing the null-state separately. Consider + the following class: +

+
struct Record
+{
+  optional<int> _min;
+  optional<int> _max;
+};
+
+

+ Its memory layout can be depicted as follows: +

+

+ opt_align2 +

+

+ This is exactly the same as if we had the following members: +

+
struct Record
+{
+  bool _has_min;
+  int  _min;
+  bool _has_max;
+  int  _max;
+};
+
+

+ But when they are stored separately, we at least have an option to reorder + them like this: +

+
struct Record
+{
+  bool _has_min;
+  bool _has_max;
+  int  _min;
+  int  _max;
+};
+
+

+ Which gives us the following layout (and smaller total size): +

+

+ opt_align3 +

+

+ Sometimes it requires detailed consideration what data we make optional. + In our case above, if we determine that both minimum and maximum value can + be provided or not provided together, but one is never provided without the + other, we can make only one optional memebr: +

+
struct Limits
+{
+  int  _min;
+  int  _max;
+};
+
+struct Record
+{
+  optional<Limits> _limits;
+};
+
+

+ This would give us the following layout: +

+

+ opt_align4 +

+
+ + Optional + function parameters +
+

+ Having function parameters of type const + optional<T>& + may incur certain unexpected run-time cost connected to copy construction + of T. Consider the following + code. +

+
void fun(const optional<Big>& v)
+{
+  if (v) doSomethingWith(*v);
+  else   doSomethingElse();
+}
+
+int main()
+{
+  optional<Big> ov;
+  Big v;
+  fun(none);
+  fun(ov); // no copy
+  fun(v);  // copy constructor of Big
+}
+
+

+ No copy elision or move semantics can save us from copying type Big here. Not that we need any copy, but + this is how optional works. + In order to avoid copying in this case, one could provide second overload + of fun: +

+
void fun(const Big& v)
+{
+  doSomethingWith(v);
+}
+
+int main()
+{
+  optional<Big> ov;
+  Big v;
+  fun(ov); // no copy
+  fun(v);  // no copy: second overload selected
+}
+
+

+ Alternatively, you could consider using an optional reference instead: +

+
void fun(optional<const Big&> v) // note where the reference is
+{
+  if (v) doSomethingWith(*v);
+  else   doSomethingElse();
+}
+
+int main()
+{
+  optional<Big> ov;
+  Big v;
+  fun(none);
+  fun(ov); // doesn't compile
+  fun(v);  // no copy
+}
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/boost_optional/tutorial/type_requirements.html b/doc/html/boost_optional/tutorial/type_requirements.html index 38a106d..8612ea0 100644 --- a/doc/html/boost_optional/tutorial/type_requirements.html +++ b/doc/html/boost_optional/tutorial/type_requirements.html @@ -7,7 +7,7 @@ - + @@ -20,7 +20,7 @@

-PrevUpHomeNext +PrevUpHomeNext

@@ -103,7 +103,7 @@
-PrevUpHomeNext +PrevUpHomeNext
diff --git a/doc/html/images/opt_align1.png b/doc/html/images/opt_align1.png new file mode 100644 index 0000000000000000000000000000000000000000..50e0205eab4aef06bdc02ac4490dd20ca50e887b GIT binary patch literal 417 zcmeAS@N?(olHy`uVBq!ia0y~yV9aD-U=ZM7V_;yoqS*JDfq{XsILO_JVcj{ImkbOH zEa{HEjtmSN`?>!lvNA9*a29w(7BevL9RXp+soH$f3=E8Bo-U3d6>)FxY|LeH6kxqz ztEHg4WrEKOzH^hL7g|XAYLN=ZX%yGzD5lhv*6XZ9!Fn`d{E@3Kj3_xZzI zd;Y&!RW^HDeCW?N1#kD=++W^Vxp(eGA#3}~#%=p2$sIS`^4aFR>o>byVPS_K#@N{> z{Xd+4d|}M@*}uj1{0!^=9p`sH_3tOCTiZjo9XHPUn)k)3T(nBLl|w+mLBZ9*bGd=E zQv*ZejD|^lJ3R&ICHCOI*q$k#Z6<;%_U_ueJ=-Ardv1}(ROf2z#ivT=>;2=F-52}K USWrxcfq{X+)78&qol`;+0CoSNbpQYW literal 0 HcmV?d00001 diff --git a/doc/html/images/opt_align2.png b/doc/html/images/opt_align2.png new file mode 100644 index 0000000000000000000000000000000000000000..fd7c079c9303f4797523b7ef10c775d2b42f959f GIT binary patch literal 472 zcmeAS@N?(olHy`uVBq!ia0y~yV9aD-U=ZM7V_;yoqS*JDfq{XsILO_JVcj{ImkbOH zEa{HEjtmSN`?>!lvNA9*a29w(7BevL9RXp+soH$f3=E99o-U3d6>)Fx82T|eN*w(d zsjskb<6(}7TM_F!)wVhLI%a&}nbVjo!Cjr}YjSh#)(s&^clz22npFdWa__0+H~kEL ze>;EQeYO6)O^Y;M9e97AE9UP!_qSnlYTcjSeR!kx?(^Qc*KOyy?R~V+w)@oX!;`Px zu{HX+Cnx$+5{>LL*?yoHM_{ ijqs^v%dBp&o1YI$tl-G1?_ywJVDNPHb6Mw<&;$UeS-J!O literal 0 HcmV?d00001 diff --git a/doc/html/images/opt_align3.png b/doc/html/images/opt_align3.png new file mode 100644 index 0000000000000000000000000000000000000000..7ca6ec800eb037540b8598efab9014c68701e4ad GIT binary patch literal 468 zcmeAS@N?(olHy`uVBq!ia0y~yV9aD-U=ZM7V_;yoqS*JDfq{XsILO_JVcj{ImkbOH zEa{HEjtmSN`?>!lvNA9*a29w(7BevL9RXp+soH$fAR|0o978JN-rg}>=jbSM?Bh~9_! zDDwTt^K8~%&)4nQURJA?KL6nTV~3`MADZ@8>+>SxYsOu1`;F`$#c96&6QWiBZ P7#KWV{an^LB{Ts5JQBDO literal 0 HcmV?d00001 diff --git a/doc/html/images/opt_align4.png b/doc/html/images/opt_align4.png new file mode 100644 index 0000000000000000000000000000000000000000..c7f9b72422ce3c1d6d1c475a531e533b61b19c73 GIT binary patch literal 428 zcmeAS@N?(olHy`uVBq!ia0y~yV9aD-U=ZM7V_;yoqS*JDfq{XsILO_JVcj{ImkbOH zEa{HEjtmSN`?>!lvNA9*a29w(7BevL9RXp+soH$f3=E8po-U3d6>)Fx80H;v5MaGf z>gOdL>K=aoN8B&;PWu z_b>ncx9vs0D)!|cT)n#L&iC)XBf?($X50_E`PsP3?ta+!7~}27jU#_YS8&bsP-J4^ z5bzKTxTJZeO+djxL2bd3Exception Safety Guarantees
Type requirements
+
Performance + considerations
Reference
@@ -134,7 +136,7 @@

- +

Last revised: November 21, 2014 at 23:32:40 GMT

Last revised: December 06, 2014 at 18:09:45 GMT


diff --git a/doc/html/optional/reference.html b/doc/html/optional/reference.html index 9c157df..4a16c15 100644 --- a/doc/html/optional/reference.html +++ b/doc/html/optional/reference.html @@ -6,7 +6,7 @@ - + @@ -20,7 +20,7 @@
-PrevUpHomeNext +PrevUpHomeNext

@@ -181,7 +181,7 @@
-PrevUpHomeNext +PrevUpHomeNext
diff --git a/doc/html/optional/tutorial.html b/doc/html/optional/tutorial.html index 7b84efd..b5b8c50 100644 --- a/doc/html/optional/tutorial.html +++ b/doc/html/optional/tutorial.html @@ -44,6 +44,8 @@
Exception Safety Guarantees
Type requirements
+
Performance + considerations

From 8bc63106d32f43a579eba4856453081a1ef76f7f Mon Sep 17 00:00:00 2001 From: Andrzej Krzemienski Date: Sat, 6 Dec 2014 21:08:58 +0100 Subject: [PATCH 07/23] Relocated images to QBK section --- doc/Jamfile.v2 | 10 ++++++++++ doc/html/index.html | 2 +- doc/images/opt_align1.png | Bin 0 -> 417 bytes doc/images/opt_align2.png | Bin 0 -> 472 bytes doc/images/opt_align3.png | Bin 0 -> 468 bytes doc/images/opt_align4.png | Bin 0 -> 428 bytes 6 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 doc/images/opt_align1.png create mode 100644 doc/images/opt_align2.png create mode 100644 doc/images/opt_align3.png create mode 100644 doc/images/opt_align4.png diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 index debb1b4..fc30664 100644 --- a/doc/Jamfile.v2 +++ b/doc/Jamfile.v2 @@ -20,6 +20,16 @@ xml optional 00_optional.qbk ; +install images + : + images/opt_align1.png + images/opt_align2.png + images/opt_align3.png + images/opt_align4.png + : + html/images + ; + boostbook standalone : optional diff --git a/doc/html/index.html b/doc/html/index.html index 5395150..58b2183 100644 --- a/doc/html/index.html +++ b/doc/html/index.html @@ -136,7 +136,7 @@

- +

Last revised: December 06, 2014 at 18:09:45 GMT

Last revised: December 06, 2014 at 20:01:35 GMT


diff --git a/doc/images/opt_align1.png b/doc/images/opt_align1.png new file mode 100644 index 0000000000000000000000000000000000000000..50e0205eab4aef06bdc02ac4490dd20ca50e887b GIT binary patch literal 417 zcmeAS@N?(olHy`uVBq!ia0y~yV9aD-U=ZM7V_;yoqS*JDfq{XsILO_JVcj{ImkbOH zEa{HEjtmSN`?>!lvNA9*a29w(7BevL9RXp+soH$f3=E8Bo-U3d6>)FxY|LeH6kxqz ztEHg4WrEKOzH^hL7g|XAYLN=ZX%yGzD5lhv*6XZ9!Fn`d{E@3Kj3_xZzI zd;Y&!RW^HDeCW?N1#kD=++W^Vxp(eGA#3}~#%=p2$sIS`^4aFR>o>byVPS_K#@N{> z{Xd+4d|}M@*}uj1{0!^=9p`sH_3tOCTiZjo9XHPUn)k)3T(nBLl|w+mLBZ9*bGd=E zQv*ZejD|^lJ3R&ICHCOI*q$k#Z6<;%_U_ueJ=-Ardv1}(ROf2z#ivT=>;2=F-52}K USWrxcfq{X+)78&qol`;+0CoSNbpQYW literal 0 HcmV?d00001 diff --git a/doc/images/opt_align2.png b/doc/images/opt_align2.png new file mode 100644 index 0000000000000000000000000000000000000000..fd7c079c9303f4797523b7ef10c775d2b42f959f GIT binary patch literal 472 zcmeAS@N?(olHy`uVBq!ia0y~yV9aD-U=ZM7V_;yoqS*JDfq{XsILO_JVcj{ImkbOH zEa{HEjtmSN`?>!lvNA9*a29w(7BevL9RXp+soH$f3=E99o-U3d6>)Fx82T|eN*w(d zsjskb<6(}7TM_F!)wVhLI%a&}nbVjo!Cjr}YjSh#)(s&^clz22npFdWa__0+H~kEL ze>;EQeYO6)O^Y;M9e97AE9UP!_qSnlYTcjSeR!kx?(^Qc*KOyy?R~V+w)@oX!;`Px zu{HX+Cnx$+5{>LL*?yoHM_{ ijqs^v%dBp&o1YI$tl-G1?_ywJVDNPHb6Mw<&;$UeS-J!O literal 0 HcmV?d00001 diff --git a/doc/images/opt_align3.png b/doc/images/opt_align3.png new file mode 100644 index 0000000000000000000000000000000000000000..7ca6ec800eb037540b8598efab9014c68701e4ad GIT binary patch literal 468 zcmeAS@N?(olHy`uVBq!ia0y~yV9aD-U=ZM7V_;yoqS*JDfq{XsILO_JVcj{ImkbOH zEa{HEjtmSN`?>!lvNA9*a29w(7BevL9RXp+soH$fAR|0o978JN-rg}>=jbSM?Bh~9_! zDDwTt^K8~%&)4nQURJA?KL6nTV~3`MADZ@8>+>SxYsOu1`;F`$#c96&6QWiBZ P7#KWV{an^LB{Ts5JQBDO literal 0 HcmV?d00001 diff --git a/doc/images/opt_align4.png b/doc/images/opt_align4.png new file mode 100644 index 0000000000000000000000000000000000000000..c7f9b72422ce3c1d6d1c475a531e533b61b19c73 GIT binary patch literal 428 zcmeAS@N?(olHy`uVBq!ia0y~yV9aD-U=ZM7V_;yoqS*JDfq{XsILO_JVcj{ImkbOH zEa{HEjtmSN`?>!lvNA9*a29w(7BevL9RXp+soH$f3=E8po-U3d6>)Fx80H;v5MaGf z>gOdL>K=aoN8B&;PWu z_b>ncx9vs0D)!|cT)n#L&iC)XBf?($X50_E`PsP3?ta+!7~}27jU#_YS8&bsP-J4^ z5bzKTxTJZeO+djxL2bd3 Date: Sat, 6 Dec 2014 23:03:39 +0100 Subject: [PATCH 08/23] Fixed noexcept tests, added opt ref tests --- test/optional_test_noexcept_move.cpp | 32 +++- test/optional_test_ref_portable_minimum.cpp | 198 ++++++++++++++++++++ 2 files changed, 229 insertions(+), 1 deletion(-) diff --git a/test/optional_test_noexcept_move.cpp b/test/optional_test_noexcept_move.cpp index e072785..b0c2220 100644 --- a/test/optional_test_noexcept_move.cpp +++ b/test/optional_test_noexcept_move.cpp @@ -41,6 +41,7 @@ struct NothrowNone { void operator=(NothrowNone&&) BOOST_NOEXCEPT_IF(false) {}; }; +#if 0 // these also test type_traits, which are wrong void test_noexcept_as_defined() // this is a compile-time test { BOOST_STATIC_ASSERT(::boost::is_nothrow_move_constructible::value); @@ -56,7 +57,7 @@ void test_noexcept_as_defined() // this is a compile-time test BOOST_STATIC_ASSERT(!::boost::is_nothrow_move_assignable::value); } -void test_noexcept_on_optional() // this is a compile-time test +void test_noexcept_on_optional_with_type_traits() // this is a compile-time test { BOOST_STATIC_ASSERT(::boost::is_nothrow_move_constructible >::value); BOOST_STATIC_ASSERT(::boost::is_nothrow_move_assignable >::value); @@ -74,6 +75,35 @@ void test_noexcept_on_optional() // this is a compile-time test BOOST_STATIC_ASSERT(!::boost::is_nothrow_move_assignable >::value); BOOST_STATIC_ASSERT(BOOST_NOEXCEPT_EXPR(optional())); } +#endif + +void test_noexcept_optional_with_operator() // compile-time test +{ + typedef optional ONx2; + typedef optional ONxC; + typedef optional ONxA; + typedef optional ONx0; + ONx2 onx2; + ONxC onxC; + ONxA onxA; + ONx0 onx0; + + BOOST_STATIC_ASSERT( BOOST_NOEXCEPT_EXPR( ONx2() )); + BOOST_STATIC_ASSERT( BOOST_NOEXCEPT_EXPR( ONx2(boost::move(onx2)) )); + BOOST_STATIC_ASSERT( BOOST_NOEXCEPT_EXPR( onx2 = ONx2() )); + + BOOST_STATIC_ASSERT( BOOST_NOEXCEPT_EXPR( ONxC() )); + BOOST_STATIC_ASSERT( BOOST_NOEXCEPT_EXPR( ONxC(boost::move(onxC)) )); + BOOST_STATIC_ASSERT(!BOOST_NOEXCEPT_EXPR( onxC = ONxC() )); + + BOOST_STATIC_ASSERT( BOOST_NOEXCEPT_EXPR( ONxA() )); + BOOST_STATIC_ASSERT(!BOOST_NOEXCEPT_EXPR( ONxA(boost::move(onxA)) )); + BOOST_STATIC_ASSERT(!BOOST_NOEXCEPT_EXPR( onxA = ONxA() )); + + BOOST_STATIC_ASSERT( BOOST_NOEXCEPT_EXPR( ONx0() )); + BOOST_STATIC_ASSERT(!BOOST_NOEXCEPT_EXPR( ONx0(boost::move(onx0)) )); + BOOST_STATIC_ASSERT(!BOOST_NOEXCEPT_EXPR( onx0 = ONx0() )); +} #endif // !defned BOOST_NO_NOEXCEPT #endif // !defined BOOST_NO_CXX11_RVALUE_REFERENCES diff --git a/test/optional_test_ref_portable_minimum.cpp b/test/optional_test_ref_portable_minimum.cpp index 4439d8c..6f4ed9a 100644 --- a/test/optional_test_ref_portable_minimum.cpp +++ b/test/optional_test_ref_portable_minimum.cpp @@ -28,6 +28,7 @@ struct ScopeGuard // no copy/move ctor/assign int val_; explicit ScopeGuard(int v) : val_(v) {} int& val() { return val_; } + const int& val() const { return val_; } private: ScopeGuard(ScopeGuard const&); @@ -37,6 +38,7 @@ private: struct Abstract { virtual int& val() = 0; + virtual const int& val() const = 0; virtual ~Abstract() {} Abstract(){} @@ -50,6 +52,7 @@ struct Impl : Abstract int val_; Impl(int v) : val_(v) {} int& val() { return val_; } + const int& val() const { return val_; } }; template @@ -80,6 +83,11 @@ int& val(int& i) { return i; } int& val(Abstract& a) { return a.val(); } int& val(ScopeGuard& g) { return g.val(); } +bool operator==(const Abstract& l, const Abstract& r) { return l.val() == r.val(); } +bool operator==(const ScopeGuard& l, const ScopeGuard& r) { return l.val() == r.val(); } + +bool operator<(const Abstract& l, const Abstract& r) { return l.val() < r.val(); } +bool operator<(const ScopeGuard& l, const ScopeGuard& r) { return l.val() < r.val(); } // end testable classes template @@ -222,6 +230,193 @@ void test_rebinding_assignment_semantics() BOOST_TEST_EQ(val(v), 2); } +template +void test_equality() +{ + typename concrete_type_of::type v1(1), v2(2), v2_(2), v3(3); + optional o1(v1), o2(v2), o2_(v2_), o3(v3), o3_(v3), oN, oN_; + // o2 and o2_ point to different objects; o3 and o3_ point to the same object + + BOOST_TEST(oN == oN); + BOOST_TEST(oN == oN_); + BOOST_TEST(oN_ == oN); + BOOST_TEST(o1 == o1); + BOOST_TEST(o2 == o2); + BOOST_TEST(o2 == o2_); + BOOST_TEST(o2_ == o2); + BOOST_TEST(o3 == o3); + BOOST_TEST(o3 == o3_); + BOOST_TEST(!(oN == o1)); + BOOST_TEST(!(o1 == oN)); + BOOST_TEST(!(o2 == o1)); + BOOST_TEST(!(o2 == oN)); + + BOOST_TEST(!(oN != oN)); + BOOST_TEST(!(oN != oN_)); + BOOST_TEST(!(oN_ != oN)); + BOOST_TEST(!(o1 != o1)); + BOOST_TEST(!(o2 != o2)); + BOOST_TEST(!(o2 != o2_)); + BOOST_TEST(!(o2_ != o2)); + BOOST_TEST(!(o3 != o3)); + BOOST_TEST(!(o3 != o3_)); + BOOST_TEST( (oN != o1)); + BOOST_TEST( (o1 != oN)); + BOOST_TEST( (o2 != o1)); + BOOST_TEST( (o2 != oN)); +} + +template +void test_order() +{ + typename concrete_type_of::type v1(1), v2(2), v2_(2), v3(3); + optional o1(v1), o2(v2), o2_(v2_), o3(v3), o3_(v3), oN, oN_; + // o2 and o2_ point to different objects; o3 and o3_ point to the same object + + BOOST_TEST(!(oN < oN)); + BOOST_TEST(!(oN < oN_)); + BOOST_TEST(!(oN_ < oN)); + BOOST_TEST(!(o1 < o1)); + BOOST_TEST(!(o2 < o2)); + BOOST_TEST(!(o2 < o2_)); + BOOST_TEST(!(o2_ < o2)); + BOOST_TEST(!(o3 < o3)); + BOOST_TEST(!(o3 < o3_)); + + BOOST_TEST( (oN <= oN)); + BOOST_TEST( (oN <= oN_)); + BOOST_TEST( (oN_ <= oN)); + BOOST_TEST( (o1 <= o1)); + BOOST_TEST( (o2 <= o2)); + BOOST_TEST( (o2 <= o2_)); + BOOST_TEST( (o2_ <= o2)); + BOOST_TEST( (o3 <= o3)); + BOOST_TEST( (o3 <= o3_)); + + BOOST_TEST(!(oN > oN)); + BOOST_TEST(!(oN > oN_)); + BOOST_TEST(!(oN_ > oN)); + BOOST_TEST(!(o1 > o1)); + BOOST_TEST(!(o2 > o2)); + BOOST_TEST(!(o2 > o2_)); + BOOST_TEST(!(o2_ > o2)); + BOOST_TEST(!(o3 > o3)); + BOOST_TEST(!(o3 > o3_)); + + BOOST_TEST( (oN >= oN)); + BOOST_TEST( (oN >= oN_)); + BOOST_TEST( (oN_ >= oN)); + BOOST_TEST( (o1 >= o1)); + BOOST_TEST( (o2 >= o2)); + BOOST_TEST( (o2 >= o2_)); + BOOST_TEST( (o2_ >= o2)); + BOOST_TEST( (o3 >= o3)); + BOOST_TEST( (o3 >= o3_)); + + BOOST_TEST( (oN < o1)); + BOOST_TEST( (oN_ < o1)); + BOOST_TEST( (oN < o2)); + BOOST_TEST( (oN_ < o2)); + BOOST_TEST( (oN < o2_)); + BOOST_TEST( (oN_ < o2_)); + BOOST_TEST( (oN < o3)); + BOOST_TEST( (oN_ < o3)); + BOOST_TEST( (oN < o3_)); + BOOST_TEST( (oN_ < o3_)); + BOOST_TEST( (o1 < o2)); + BOOST_TEST( (o1 < o2_)); + BOOST_TEST( (o1 < o3)); + BOOST_TEST( (o1 < o3_)); + BOOST_TEST( (o2 < o3)); + BOOST_TEST( (o2_ < o3)); + BOOST_TEST( (o2 < o3_)); + BOOST_TEST( (o2_ < o3_)); + + BOOST_TEST( (oN <= o1)); + BOOST_TEST( (oN_ <= o1)); + BOOST_TEST( (oN <= o2)); + BOOST_TEST( (oN_ <= o2)); + BOOST_TEST( (oN <= o2_)); + BOOST_TEST( (oN_ <= o2_)); + BOOST_TEST( (oN <= o3)); + BOOST_TEST( (oN_ <= o3)); + BOOST_TEST( (oN <= o3_)); + BOOST_TEST( (oN_ <= o3_)); + BOOST_TEST( (o1 <= o2)); + BOOST_TEST( (o1 <= o2_)); + BOOST_TEST( (o1 <= o3)); + BOOST_TEST( (o1 <= o3_)); + BOOST_TEST( (o2 <= o3)); + BOOST_TEST( (o2_ <= o3)); + BOOST_TEST( (o2 <= o3_)); + BOOST_TEST( (o2_ <= o3_)); + + BOOST_TEST(!(oN > o1)); + BOOST_TEST(!(oN_ > o1)); + BOOST_TEST(!(oN > o2)); + BOOST_TEST(!(oN_ > o2)); + BOOST_TEST(!(oN > o2_)); + BOOST_TEST(!(oN_ > o2_)); + BOOST_TEST(!(oN > o3)); + BOOST_TEST(!(oN_ > o3)); + BOOST_TEST(!(oN > o3_)); + BOOST_TEST(!(oN_ > o3_)); + BOOST_TEST(!(o1 > o2)); + BOOST_TEST(!(o1 > o2_)); + BOOST_TEST(!(o1 > o3)); + BOOST_TEST(!(o1 > o3_)); + BOOST_TEST(!(o2 > o3)); + BOOST_TEST(!(o2_ > o3)); + BOOST_TEST(!(o2 > o3_)); + BOOST_TEST(!(o2_ > o3_)); + + BOOST_TEST(!(oN >= o1)); + BOOST_TEST(!(oN_ >= o1)); + BOOST_TEST(!(oN >= o2)); + BOOST_TEST(!(oN_ >= o2)); + BOOST_TEST(!(oN >= o2_)); + BOOST_TEST(!(oN_ >= o2_)); + BOOST_TEST(!(oN >= o3)); + BOOST_TEST(!(oN_ >= o3)); + BOOST_TEST(!(oN >= o3_)); + BOOST_TEST(!(oN_ >= o3_)); + BOOST_TEST(!(o1 >= o2)); + BOOST_TEST(!(o1 >= o2_)); + BOOST_TEST(!(o1 >= o3)); + BOOST_TEST(!(o1 >= o3_)); + BOOST_TEST(!(o2 >= o3)); + BOOST_TEST(!(o2_ >= o3)); + BOOST_TEST(!(o2 >= o3_)); + BOOST_TEST(!(o2_ >= o3_)); + + BOOST_TEST(!(o1 < oN)); + BOOST_TEST(!(o1 < oN_)); + BOOST_TEST(!(o2 < oN)); + BOOST_TEST(!(o2 < oN_)); + BOOST_TEST(!(o2_ < oN)); + BOOST_TEST(!(o2_ < oN_)); + BOOST_TEST(!(o3 < oN)); + BOOST_TEST(!(o3 < oN_)); + BOOST_TEST(!(o3_ < oN)); + BOOST_TEST(!(o3_ < oN_)); + BOOST_TEST(!(o2 < oN)); + BOOST_TEST(!(o2_ < oN_)); + BOOST_TEST(!(o3 < oN)); + BOOST_TEST(!(o3_ < oN_)); + BOOST_TEST(!(o3 < oN)); + BOOST_TEST(!(o3 < oN_)); + BOOST_TEST(!(o3_ < oN)); + BOOST_TEST(!(o3_ < oN_)); +} + +template +void test_swap() +{ + typename concrete_type_of::type v1(1), v2(2); + optional o1(v1), o1_(v1), o2(v2), o2_(v2), oN, oN_; + + // swap(o1, o1); DOESN'T WORK +} template void test_optional_ref() @@ -232,6 +427,9 @@ void test_optional_ref() test_rebinding_assignment_semantics(); test_clearing_the_value(); test_arrow(); + test_equality(); + test_order(); + test_swap(); } int main() From 26ab338c8358c0af882782c242550366af1ba562 Mon Sep 17 00:00:00 2001 From: Andrzej Krzemienski Date: Sat, 6 Dec 2014 23:06:49 +0100 Subject: [PATCH 09/23] Removed redundant tests --- test/optional_test_ref.cpp | 60 -------------------------------------- 1 file changed, 60 deletions(-) diff --git a/test/optional_test_ref.cpp b/test/optional_test_ref.cpp index 830840b..6525ed3 100644 --- a/test/optional_test_ref.cpp +++ b/test/optional_test_ref.cpp @@ -219,71 +219,12 @@ void test_basics( T const* ) check_ref_uninitialized(ob); } -// -// This verifies relational operators. -// -template -void test_relops( T const* ) -{ - TRACE( std::endl << BOOST_CURRENT_FUNCTION ); - - reset_throw_on_copy( ARG(T) ) ; - - T v0(18); - T v1(19); - T v2(19); - - optional def0 ; - optional def1 ; - optional opt0(v0); - optional opt1(v1); - optional opt2(v2); - - // Check identity - BOOST_CHECK ( def0 == def0 ) ; - BOOST_CHECK ( opt0 == opt0 ) ; - BOOST_CHECK ( !(def0 != def0) ) ; - BOOST_CHECK ( !(opt0 != opt0) ) ; - - // Check when both are uininitalized. - BOOST_CHECK ( def0 == def1 ) ; // both uninitialized compare equal - BOOST_CHECK ( !(def0 < def1) ) ; // uninitialized is never less than uninitialized - BOOST_CHECK ( !(def0 > def1) ) ; // uninitialized is never greater than uninitialized - BOOST_CHECK ( !(def0 != def1) ) ; - BOOST_CHECK ( def0 <= def1 ) ; - BOOST_CHECK ( def0 >= def1 ) ; - - // Check when only lhs is uninitialized. - BOOST_CHECK ( def0 != opt0 ) ; // uninitialized is never equal to initialized - BOOST_CHECK ( !(def0 == opt0) ) ; - BOOST_CHECK ( def0 < opt0 ) ; // uninitialized is always less than initialized - BOOST_CHECK ( !(def0 > opt0) ) ; - BOOST_CHECK ( def0 <= opt0 ) ; - BOOST_CHECK ( !(def0 >= opt0) ) ; - - // Check when only rhs is uninitialized. - BOOST_CHECK ( opt0 != def0 ) ; // initialized is never equal to uninitialized - BOOST_CHECK ( !(opt0 == def0) ) ; - BOOST_CHECK ( !(opt0 < def0) ) ; // initialized is never less than uninitialized - BOOST_CHECK ( opt0 > def0 ) ; - BOOST_CHECK ( !(opt0 <= def0) ) ; - BOOST_CHECK ( opt0 >= opt0 ) ; - - // If both are initialized, values are compared - BOOST_CHECK ( opt0 != opt1 ) ; - BOOST_CHECK ( opt1 == opt2 ) ; - BOOST_CHECK ( opt0 < opt1 ) ; - BOOST_CHECK ( opt1 > opt0 ) ; - BOOST_CHECK ( opt1 <= opt2 ) ; - BOOST_CHECK ( opt1 >= opt0 ) ; -} void test_with_builtin_types() { TRACE( std::endl << BOOST_CURRENT_FUNCTION ); test_basics( ARG(double) ); - test_relops( ARG(double) ) ; } void test_with_class_type() @@ -291,7 +232,6 @@ void test_with_class_type() TRACE( std::endl << BOOST_CURRENT_FUNCTION ); test_basics( ARG(X) ); - test_relops( ARG(X) ) ; BOOST_CHECK ( X::count == 0 ) ; } From a2268d78b4ecff754e9d2d97de4f4362dd410d06 Mon Sep 17 00:00:00 2001 From: Andrzej Krzemienski Date: Wed, 10 Dec 2014 23:10:07 +0100 Subject: [PATCH 10/23] more optional ref tesst this breaks on msvc, but that only reveals the problems that were there anyway. --- test/optional_test_ref_portable_minimum.cpp | 195 ++++++++++++++++++++ 1 file changed, 195 insertions(+) diff --git a/test/optional_test_ref_portable_minimum.cpp b/test/optional_test_ref_portable_minimum.cpp index 6f4ed9a..a4da751 100644 --- a/test/optional_test_ref_portable_minimum.cpp +++ b/test/optional_test_ref_portable_minimum.cpp @@ -67,6 +67,12 @@ struct concrete_type_of typedef Impl type; }; +template <> +struct concrete_type_of +{ + typedef const Impl type; +}; + template struct has_arrow { @@ -83,6 +89,10 @@ int& val(int& i) { return i; } int& val(Abstract& a) { return a.val(); } int& val(ScopeGuard& g) { return g.val(); } +const int& val(const int& i) { return i; } +const int& val(const Abstract& a) { return a.val(); } +const int& val(const ScopeGuard& g) { return g.val(); } + bool operator==(const Abstract& l, const Abstract& r) { return l.val() == r.val(); } bool operator==(const ScopeGuard& l, const ScopeGuard& r) { return l.val() == r.val(); } @@ -90,6 +100,46 @@ bool operator<(const Abstract& l, const Abstract& r) { return l.val() < r.val(); bool operator<(const ScopeGuard& l, const ScopeGuard& r) { return l.val() < r.val(); } // end testable classes +template +typename boost::enable_if< has_arrow >::type +test_arrow_const() +{ + const typename concrete_type_of::type v(2); + optional o(v); + BOOST_TEST(o); + BOOST_TEST_EQ(o->val(), 2); + BOOST_TEST(boost::addressof(o->val()) == boost::addressof(v.val())); +} + +template +typename boost::disable_if< has_arrow >::type +test_arrow_const() +{ +} + +template +typename boost::enable_if< has_arrow >::type +test_arrow_noconst_const() +{ + typename concrete_type_of::type v(2); + optional o(v); + BOOST_TEST(o); + BOOST_TEST_EQ(o->val(), 2); + BOOST_TEST(boost::addressof(o->val()) == boost::addressof(v.val())); + + v.val() = 1; + BOOST_TEST(o); + BOOST_TEST_EQ(o->val(), 1); + BOOST_TEST_EQ(v.val(), 1); + BOOST_TEST(boost::addressof(o->val()) == boost::addressof(v.val())); +} + +template +typename boost::disable_if< has_arrow >::type +test_arrow_noconst_const() +{ +} + template typename boost::enable_if< has_arrow >::type test_arrow() @@ -98,11 +148,20 @@ test_arrow() optional o(v); BOOST_TEST(o); BOOST_TEST_EQ(o->val(), 2); + BOOST_TEST(boost::addressof(o->val()) == boost::addressof(v.val())); + + v.val() = 1; + BOOST_TEST(o); + BOOST_TEST_EQ(o->val(), 1); + BOOST_TEST_EQ(v.val(), 1); + BOOST_TEST(boost::addressof(o->val()) == boost::addressof(v.val())); o->val() = 3; BOOST_TEST(o); BOOST_TEST_EQ(o->val(), 3); BOOST_TEST_EQ(v.val(), 3); + BOOST_TEST(boost::addressof(o->val()) == boost::addressof(v.val())); + } template @@ -127,6 +186,38 @@ void test_not_containing_value_for() BOOST_TEST(o3 == none); } +template +void test_direct_init_for_const() +{ + const typename concrete_type_of::type v(2); + optional o(v); + + BOOST_TEST(o); + BOOST_TEST(o != none); + BOOST_TEST(boost::addressof(*o) == boost::addressof(v)); + BOOST_TEST_EQ(val(*o), val(v)); + BOOST_TEST_EQ(val(*o), 2); +} + +template +void test_direct_init_for_noconst_const() +{ + typename concrete_type_of::type v(2); + optional o(v); + + BOOST_TEST(o); + BOOST_TEST(o != none); + BOOST_TEST(boost::addressof(*o) == boost::addressof(v)); + BOOST_TEST_EQ(val(*o), val(v)); + BOOST_TEST_EQ(val(*o), 2); + + val(v) = 9; + BOOST_TEST(boost::addressof(*o) == boost::addressof(v)); + BOOST_TEST_EQ(val(*o), val(v)); + BOOST_TEST_EQ(val(*o), 9); + BOOST_TEST_EQ(val(v), 9); +} + template void test_direct_init_for() { @@ -173,6 +264,40 @@ void test_clearing_the_value() BOOST_TEST_EQ(val(v), 2); } +template +void test_copy_assignment_for_const() +{ + const typename concrete_type_of::type v(2); + optional o; + o = optional(v); + + BOOST_TEST(o); + BOOST_TEST(o != none); + BOOST_TEST(boost::addressof(*o) == boost::addressof(v)); + BOOST_TEST(val(*o) == val(v)); + BOOST_TEST(val(*o) == 2); +} + +template +void test_copy_assignment_for_noconst_const() +{ + typename concrete_type_of::type v(2); + optional o; + o = optional(v); + + BOOST_TEST(o); + BOOST_TEST(o != none); + BOOST_TEST(boost::addressof(*o) == boost::addressof(v)); + BOOST_TEST(val(*o) == val(v)); + BOOST_TEST(val(*o) == 2); + + val(v) = 9; + BOOST_TEST(boost::addressof(*o) == boost::addressof(v)); + BOOST_TEST_EQ(val(*o), val(v)); + BOOST_TEST_EQ(val(*o), 9); + BOOST_TEST_EQ(val(v), 9); +} + template void test_copy_assignment_for() { @@ -199,6 +324,54 @@ void test_copy_assignment_for() BOOST_TEST_EQ(val(v), 7); } +template +void test_rebinding_assignment_semantics_const() +{ + const typename concrete_type_of::type v(2), w(7); + optional o(v); + + BOOST_TEST(o); + BOOST_TEST(boost::addressof(*o) == boost::addressof(v)); + BOOST_TEST_EQ(val(*o), val(v)); + BOOST_TEST_EQ(val(*o), 2); + + o = optional(w); + BOOST_TEST_EQ(val(v), 2); + + BOOST_TEST(o); + BOOST_TEST(boost::addressof(*o) != boost::addressof(v)); + BOOST_TEST_NE(val(*o), val(v)); + BOOST_TEST_NE(val(*o), 2); + + BOOST_TEST(boost::addressof(*o) == boost::addressof(w)); + BOOST_TEST_EQ(val(*o), val(w)); + BOOST_TEST_EQ(val(*o), 7); +} + +template +void test_rebinding_assignment_semantics_noconst_const() +{ + typename concrete_type_of::type v(2), w(7); + optional o(v); + + BOOST_TEST(o); + BOOST_TEST(boost::addressof(*o) == boost::addressof(v)); + BOOST_TEST_EQ(val(*o), val(v)); + BOOST_TEST_EQ(val(*o), 2); + + o = optional(w); + BOOST_TEST_EQ(val(v), 2); + + BOOST_TEST(o); + BOOST_TEST(boost::addressof(*o) != boost::addressof(v)); + BOOST_TEST_NE(val(*o), val(v)); + BOOST_TEST_NE(val(*o), 2); + + BOOST_TEST(boost::addressof(*o) == boost::addressof(w)); + BOOST_TEST_EQ(val(*o), val(w)); + BOOST_TEST_EQ(val(*o), 7); +} + template void test_rebinding_assignment_semantics() { @@ -432,11 +605,33 @@ void test_optional_ref() test_swap(); } +template +void test_optional_const_ref() +{ + test_not_containing_value_for(); + test_direct_init_for_const(); + test_direct_init_for_noconst_const(); + test_copy_assignment_for_const(); + test_copy_assignment_for_noconst_const(); + test_rebinding_assignment_semantics_const(); + test_rebinding_assignment_semantics_noconst_const(); + test_clearing_the_value(); + test_arrow_const(); + test_arrow_noconst_const(); + test_equality(); + test_order(); + //test_swap(); +} + int main() { test_optional_ref(); test_optional_ref(); //test_optional_ref(); + test_optional_const_ref(); + test_optional_const_ref(); + //test_optional_const_ref(); + return boost::report_errors(); } From f649878d7efa69a4021617901e44a6cc72f55cfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20Krzemie=C5=84ski?= Date: Mon, 5 Jan 2015 15:49:31 +0100 Subject: [PATCH 11/23] Update libraries.json --- meta/libraries.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/meta/libraries.json b/meta/libraries.json index f40ada7..4bdac31 100644 --- a/meta/libraries.json +++ b/meta/libraries.json @@ -1,12 +1,13 @@ { "key": "optional", + "boost-version": "1.30.0", "name": "Optional", "authors": [ "Fernando Cacciola" ], - "description": "Discriminated-union wrapper for optional values.", + "description": "A value-semantic, type-safe wrapper for representing 'optional' (or 'nullable') objects of a given type. An optional object may or may not contain a value of the underlying type.", "category": [ - "Miscellaneous" + "Data structures" ], "maintainers": [ "Fernando Cacciola ", From cf665bc3f7e7b317f83337af69b62c91c04a719b Mon Sep 17 00:00:00 2001 From: Andrzej Krzemienski Date: Wed, 7 Jan 2015 16:35:23 +0100 Subject: [PATCH 12/23] More fine grained optional ref assign tests --- test/Jamfile.v2 | 3 + test/optional_ref_assign_test_defs.hpp | 166 +++++++++++++ test/optional_test_ref_assign_const_int.cpp | 34 +++ test/optional_test_ref_assign_mutable_int.cpp | 31 +++ ...ional_test_ref_assign_portable_minimum.cpp | 44 ++++ test/optional_test_ref_portable_minimum.cpp | 223 +----------------- test/testable_classes.hpp | 91 +++++++ 7 files changed, 370 insertions(+), 222 deletions(-) create mode 100644 test/optional_ref_assign_test_defs.hpp create mode 100644 test/optional_test_ref_assign_const_int.cpp create mode 100644 test/optional_test_ref_assign_mutable_int.cpp create mode 100644 test/optional_test_ref_assign_portable_minimum.cpp create mode 100644 test/testable_classes.hpp diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 46ed39c..dc29fea 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -20,6 +20,9 @@ import testing ; [ run optional_test_conversions_from_U.cpp ] [ run optional_test_tie.cpp ] [ run optional_test_ref.cpp ] + [ run optional_test_ref_assign_portable_minimum.cpp ] + [ run optional_test_ref_assign_mutable_int.cpp ] + [ run optional_test_ref_assign_const_int.cpp ] [ run optional_test_ref_portable_minimum.cpp ] [ run optional_test_inplace.cpp ] [ run optional_test_io.cpp ] diff --git a/test/optional_ref_assign_test_defs.hpp b/test/optional_ref_assign_test_defs.hpp new file mode 100644 index 0000000..1dc9643 --- /dev/null +++ b/test/optional_ref_assign_test_defs.hpp @@ -0,0 +1,166 @@ +// Copyright (C) 2014 Andrzej Krzemienski. +// +// Use, modification, and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/lib/optional for documentation. +// +// You are welcome to contact the author at: akrzemi1@gmail.com + +#ifndef BOOST_OPTIONAL_TEST_OPTIONAL_REF_ASSIGN_TEST_DEFS_AK_07JAN2015_HPP +#define BOOST_OPTIONAL_TEST_OPTIONAL_REF_ASSIGN_TEST_DEFS_AK_07JAN2015_HPP + +#include "boost/optional/optional.hpp" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#include "boost/core/addressof.hpp" +#include "testable_classes.hpp" + +using boost::optional; +using boost::none; + +template +void test_copy_assignment_for_const() +{ + const typename concrete_type_of::type v(2); + optional o; + o = optional(v); + + BOOST_TEST(o); + BOOST_TEST(o != none); + BOOST_TEST(boost::addressof(*o) == boost::addressof(v)); + BOOST_TEST(val(*o) == val(v)); + BOOST_TEST(val(*o) == 2); +} + +template +void test_copy_assignment_for_noconst_const() +{ + typename concrete_type_of::type v(2); + optional o; + o = optional(v); + + BOOST_TEST(o); + BOOST_TEST(o != none); + BOOST_TEST(boost::addressof(*o) == boost::addressof(v)); + BOOST_TEST(val(*o) == val(v)); + BOOST_TEST(val(*o) == 2); + + val(v) = 9; + BOOST_TEST(boost::addressof(*o) == boost::addressof(v)); + BOOST_TEST_EQ(val(*o), val(v)); + BOOST_TEST_EQ(val(*o), 9); + BOOST_TEST_EQ(val(v), 9); +} + +template +void test_copy_assignment_for() +{ + typename concrete_type_of::type v(2); + optional o; + o = optional(v); + + BOOST_TEST(o); + BOOST_TEST(o != none); + BOOST_TEST(boost::addressof(*o) == boost::addressof(v)); + BOOST_TEST(val(*o) == val(v)); + BOOST_TEST(val(*o) == 2); + + val(v) = 9; + BOOST_TEST(boost::addressof(*o) == boost::addressof(v)); + BOOST_TEST_EQ(val(*o), val(v)); + BOOST_TEST_EQ(val(*o), 9); + BOOST_TEST_EQ(val(v), 9); + + val(*o) = 7; + BOOST_TEST(boost::addressof(*o) == boost::addressof(v)); + BOOST_TEST_EQ(val(*o), val(v)); + BOOST_TEST_EQ(val(*o), 7); + BOOST_TEST_EQ(val(v), 7); +} + +template +void test_rebinding_assignment_semantics_const() +{ + const typename concrete_type_of::type v(2), w(7); + optional o(v); + + BOOST_TEST(o); + BOOST_TEST(boost::addressof(*o) == boost::addressof(v)); + BOOST_TEST_EQ(val(*o), val(v)); + BOOST_TEST_EQ(val(*o), 2); + + o = optional(w); + BOOST_TEST_EQ(val(v), 2); + + BOOST_TEST(o); + BOOST_TEST(boost::addressof(*o) != boost::addressof(v)); + BOOST_TEST_NE(val(*o), val(v)); + BOOST_TEST_NE(val(*o), 2); + + BOOST_TEST(boost::addressof(*o) == boost::addressof(w)); + BOOST_TEST_EQ(val(*o), val(w)); + BOOST_TEST_EQ(val(*o), 7); +} + +template +void test_rebinding_assignment_semantics_noconst_const() +{ + typename concrete_type_of::type v(2), w(7); + optional o(v); + + BOOST_TEST(o); + BOOST_TEST(boost::addressof(*o) == boost::addressof(v)); + BOOST_TEST_EQ(val(*o), val(v)); + BOOST_TEST_EQ(val(*o), 2); + + o = optional(w); + BOOST_TEST_EQ(val(v), 2); + + BOOST_TEST(o); + BOOST_TEST(boost::addressof(*o) != boost::addressof(v)); + BOOST_TEST_NE(val(*o), val(v)); + BOOST_TEST_NE(val(*o), 2); + + BOOST_TEST(boost::addressof(*o) == boost::addressof(w)); + BOOST_TEST_EQ(val(*o), val(w)); + BOOST_TEST_EQ(val(*o), 7); +} + +template +void test_rebinding_assignment_semantics() +{ + typename concrete_type_of::type v(2), w(7); + optional o(v); + + BOOST_TEST(o); + BOOST_TEST(boost::addressof(*o) == boost::addressof(v)); + BOOST_TEST_EQ(val(*o), val(v)); + BOOST_TEST_EQ(val(*o), 2); + + o = optional(w); + BOOST_TEST_EQ(val(v), 2); + + BOOST_TEST(o); + BOOST_TEST(boost::addressof(*o) != boost::addressof(v)); + BOOST_TEST_NE(val(*o), val(v)); + BOOST_TEST_NE(val(*o), 2); + + BOOST_TEST(boost::addressof(*o) == boost::addressof(w)); + BOOST_TEST_EQ(val(*o), val(w)); + BOOST_TEST_EQ(val(*o), 7); + + val(*o) = 8; + BOOST_TEST(boost::addressof(*o) == boost::addressof(w)); + BOOST_TEST_EQ(val(*o), val(w)); + BOOST_TEST_EQ(val(*o), 8); + BOOST_TEST_EQ(val(w), 8); + BOOST_TEST_EQ(val(v), 2); +} + +#endif //BOOST_OPTIONAL_TEST_OPTIONAL_REF_ASSIGN_TEST_DEFS_AK_07JAN2015_HPP + diff --git a/test/optional_test_ref_assign_const_int.cpp b/test/optional_test_ref_assign_const_int.cpp new file mode 100644 index 0000000..a14ef6d --- /dev/null +++ b/test/optional_test_ref_assign_const_int.cpp @@ -0,0 +1,34 @@ +// Copyright (C) 2014 Andrzej Krzemienski. +// +// Use, modification, and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/lib/optional for documentation. +// +// You are welcome to contact the author at: akrzemi1@gmail.com + + +#include "boost/optional/optional.hpp" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#include "boost/core/lightweight_test.hpp" +#include "testable_classes.hpp" +#include "optional_ref_assign_test_defs.hpp" + +using boost::optional; +using boost::none; + + +int main() +{ + test_copy_assignment_for_const(); + test_copy_assignment_for_noconst_const(); + test_rebinding_assignment_semantics_const(); + test_rebinding_assignment_semantics_noconst_const(); + + return boost::report_errors(); +} diff --git a/test/optional_test_ref_assign_mutable_int.cpp b/test/optional_test_ref_assign_mutable_int.cpp new file mode 100644 index 0000000..1c674da --- /dev/null +++ b/test/optional_test_ref_assign_mutable_int.cpp @@ -0,0 +1,31 @@ +// Copyright (C) 2014 Andrzej Krzemienski. +// +// Use, modification, and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/lib/optional for documentation. +// +// You are welcome to contact the author at: akrzemi1@gmail.com + + +#include "boost/optional/optional.hpp" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#include "boost/core/lightweight_test.hpp" +#include "testable_classes.hpp" +#include "optional_ref_assign_test_defs.hpp" + +using boost::optional; +using boost::none; + +int main() +{ + test_copy_assignment_for(); + test_rebinding_assignment_semantics(); + + return boost::report_errors(); +} diff --git a/test/optional_test_ref_assign_portable_minimum.cpp b/test/optional_test_ref_assign_portable_minimum.cpp new file mode 100644 index 0000000..2a548ab --- /dev/null +++ b/test/optional_test_ref_assign_portable_minimum.cpp @@ -0,0 +1,44 @@ +// Copyright (C) 2014 Andrzej Krzemienski. +// +// Use, modification, and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/lib/optional for documentation. +// +// You are welcome to contact the author at: akrzemi1@gmail.com + + +#include "boost/optional/optional.hpp" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#include "boost/core/lightweight_test.hpp" +#include "testable_classes.hpp" +#include "optional_ref_assign_test_defs.hpp" + +using boost::optional; +using boost::none; + + +template +void test_optional_ref_assignment() +{ + test_copy_assignment_for(); + test_rebinding_assignment_semantics(); + + test_copy_assignment_for_const(); + test_copy_assignment_for_noconst_const(); + test_rebinding_assignment_semantics_const(); + test_rebinding_assignment_semantics_noconst_const(); +} + +int main() +{ + test_optional_ref_assignment(); + //test_optional_ref_assignment(); + + return boost::report_errors(); +} diff --git a/test/optional_test_ref_portable_minimum.cpp b/test/optional_test_ref_portable_minimum.cpp index a4da751..ddcffc9 100644 --- a/test/optional_test_ref_portable_minimum.cpp +++ b/test/optional_test_ref_portable_minimum.cpp @@ -18,87 +18,11 @@ #include "boost/core/addressof.hpp" #include "boost/core/enable_if.hpp" #include "boost/core/lightweight_test.hpp" +#include "testable_classes.hpp" using boost::optional; using boost::none; -// testable classes -struct ScopeGuard // no copy/move ctor/assign -{ - int val_; - explicit ScopeGuard(int v) : val_(v) {} - int& val() { return val_; } - const int& val() const { return val_; } - -private: - ScopeGuard(ScopeGuard const&); - void operator=(ScopeGuard const&); -}; - -struct Abstract -{ - virtual int& val() = 0; - virtual const int& val() const = 0; - virtual ~Abstract() {} - Abstract(){} - -private: - Abstract(Abstract const&); - void operator=(Abstract const&); -}; - -struct Impl : Abstract -{ - int val_; - Impl(int v) : val_(v) {} - int& val() { return val_; } - const int& val() const { return val_; } -}; - -template -struct concrete_type_of -{ - typedef T type; -}; - -template <> -struct concrete_type_of -{ - typedef Impl type; -}; - -template <> -struct concrete_type_of -{ - typedef const Impl type; -}; - -template -struct has_arrow -{ - static const bool value = true; -}; - -template <> -struct has_arrow -{ - static const bool value = false; -}; - -int& val(int& i) { return i; } -int& val(Abstract& a) { return a.val(); } -int& val(ScopeGuard& g) { return g.val(); } - -const int& val(const int& i) { return i; } -const int& val(const Abstract& a) { return a.val(); } -const int& val(const ScopeGuard& g) { return g.val(); } - -bool operator==(const Abstract& l, const Abstract& r) { return l.val() == r.val(); } -bool operator==(const ScopeGuard& l, const ScopeGuard& r) { return l.val() == r.val(); } - -bool operator<(const Abstract& l, const Abstract& r) { return l.val() < r.val(); } -bool operator<(const ScopeGuard& l, const ScopeGuard& r) { return l.val() < r.val(); } -// end testable classes template typename boost::enable_if< has_arrow >::type @@ -264,145 +188,6 @@ void test_clearing_the_value() BOOST_TEST_EQ(val(v), 2); } -template -void test_copy_assignment_for_const() -{ - const typename concrete_type_of::type v(2); - optional o; - o = optional(v); - - BOOST_TEST(o); - BOOST_TEST(o != none); - BOOST_TEST(boost::addressof(*o) == boost::addressof(v)); - BOOST_TEST(val(*o) == val(v)); - BOOST_TEST(val(*o) == 2); -} - -template -void test_copy_assignment_for_noconst_const() -{ - typename concrete_type_of::type v(2); - optional o; - o = optional(v); - - BOOST_TEST(o); - BOOST_TEST(o != none); - BOOST_TEST(boost::addressof(*o) == boost::addressof(v)); - BOOST_TEST(val(*o) == val(v)); - BOOST_TEST(val(*o) == 2); - - val(v) = 9; - BOOST_TEST(boost::addressof(*o) == boost::addressof(v)); - BOOST_TEST_EQ(val(*o), val(v)); - BOOST_TEST_EQ(val(*o), 9); - BOOST_TEST_EQ(val(v), 9); -} - -template -void test_copy_assignment_for() -{ - typename concrete_type_of::type v(2); - optional o; - o = optional(v); - - BOOST_TEST(o); - BOOST_TEST(o != none); - BOOST_TEST(boost::addressof(*o) == boost::addressof(v)); - BOOST_TEST(val(*o) == val(v)); - BOOST_TEST(val(*o) == 2); - - val(v) = 9; - BOOST_TEST(boost::addressof(*o) == boost::addressof(v)); - BOOST_TEST_EQ(val(*o), val(v)); - BOOST_TEST_EQ(val(*o), 9); - BOOST_TEST_EQ(val(v), 9); - - val(*o) = 7; - BOOST_TEST(boost::addressof(*o) == boost::addressof(v)); - BOOST_TEST_EQ(val(*o), val(v)); - BOOST_TEST_EQ(val(*o), 7); - BOOST_TEST_EQ(val(v), 7); -} - -template -void test_rebinding_assignment_semantics_const() -{ - const typename concrete_type_of::type v(2), w(7); - optional o(v); - - BOOST_TEST(o); - BOOST_TEST(boost::addressof(*o) == boost::addressof(v)); - BOOST_TEST_EQ(val(*o), val(v)); - BOOST_TEST_EQ(val(*o), 2); - - o = optional(w); - BOOST_TEST_EQ(val(v), 2); - - BOOST_TEST(o); - BOOST_TEST(boost::addressof(*o) != boost::addressof(v)); - BOOST_TEST_NE(val(*o), val(v)); - BOOST_TEST_NE(val(*o), 2); - - BOOST_TEST(boost::addressof(*o) == boost::addressof(w)); - BOOST_TEST_EQ(val(*o), val(w)); - BOOST_TEST_EQ(val(*o), 7); -} - -template -void test_rebinding_assignment_semantics_noconst_const() -{ - typename concrete_type_of::type v(2), w(7); - optional o(v); - - BOOST_TEST(o); - BOOST_TEST(boost::addressof(*o) == boost::addressof(v)); - BOOST_TEST_EQ(val(*o), val(v)); - BOOST_TEST_EQ(val(*o), 2); - - o = optional(w); - BOOST_TEST_EQ(val(v), 2); - - BOOST_TEST(o); - BOOST_TEST(boost::addressof(*o) != boost::addressof(v)); - BOOST_TEST_NE(val(*o), val(v)); - BOOST_TEST_NE(val(*o), 2); - - BOOST_TEST(boost::addressof(*o) == boost::addressof(w)); - BOOST_TEST_EQ(val(*o), val(w)); - BOOST_TEST_EQ(val(*o), 7); -} - -template -void test_rebinding_assignment_semantics() -{ - typename concrete_type_of::type v(2), w(7); - optional o(v); - - BOOST_TEST(o); - BOOST_TEST(boost::addressof(*o) == boost::addressof(v)); - BOOST_TEST_EQ(val(*o), val(v)); - BOOST_TEST_EQ(val(*o), 2); - - o = optional(w); - BOOST_TEST_EQ(val(v), 2); - - BOOST_TEST(o); - BOOST_TEST(boost::addressof(*o) != boost::addressof(v)); - BOOST_TEST_NE(val(*o), val(v)); - BOOST_TEST_NE(val(*o), 2); - - BOOST_TEST(boost::addressof(*o) == boost::addressof(w)); - BOOST_TEST_EQ(val(*o), val(w)); - BOOST_TEST_EQ(val(*o), 7); - - val(*o) = 8; - BOOST_TEST(boost::addressof(*o) == boost::addressof(w)); - BOOST_TEST_EQ(val(*o), val(w)); - BOOST_TEST_EQ(val(*o), 8); - BOOST_TEST_EQ(val(w), 8); - BOOST_TEST_EQ(val(v), 2); -} - template void test_equality() { @@ -596,8 +381,6 @@ void test_optional_ref() { test_not_containing_value_for(); test_direct_init_for(); - test_copy_assignment_for(); - test_rebinding_assignment_semantics(); test_clearing_the_value(); test_arrow(); test_equality(); @@ -611,10 +394,6 @@ void test_optional_const_ref() test_not_containing_value_for(); test_direct_init_for_const(); test_direct_init_for_noconst_const(); - test_copy_assignment_for_const(); - test_copy_assignment_for_noconst_const(); - test_rebinding_assignment_semantics_const(); - test_rebinding_assignment_semantics_noconst_const(); test_clearing_the_value(); test_arrow_const(); test_arrow_noconst_const(); diff --git a/test/testable_classes.hpp b/test/testable_classes.hpp new file mode 100644 index 0000000..e18359f --- /dev/null +++ b/test/testable_classes.hpp @@ -0,0 +1,91 @@ +// Copyright (C) 2014 Andrzej Krzemienski. +// +// Use, modification, and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/optional for documentation. +// +// You are welcome to contact the author at: +// akrzemi1@gmail.com + +#ifndef BOOST_OPTIONAL_TEST_TESTABKE_CLASSES_AK_07JAN2015_HPP +#define BOOST_OPTIONAL_TEST_TESTABKE_CLASSES_AK_07JAN2015_HPP + +struct ScopeGuard // no copy/move ctor/assign +{ + int val_; + explicit ScopeGuard(int v) : val_(v) {} + int& val() { return val_; } + const int& val() const { return val_; } + +private: + ScopeGuard(ScopeGuard const&); + void operator=(ScopeGuard const&); +}; + +struct Abstract +{ + virtual int& val() = 0; + virtual const int& val() const = 0; + virtual ~Abstract() {} + Abstract(){} + +private: + Abstract(Abstract const&); + void operator=(Abstract const&); +}; + +struct Impl : Abstract +{ + int val_; + Impl(int v) : val_(v) {} + int& val() { return val_; } + const int& val() const { return val_; } +}; + +template +struct concrete_type_of +{ + typedef T type; +}; + +template <> +struct concrete_type_of +{ + typedef Impl type; +}; + +template <> +struct concrete_type_of +{ + typedef const Impl type; +}; + +template +struct has_arrow +{ + static const bool value = true; +}; + +template <> +struct has_arrow +{ + static const bool value = false; +}; + +int& val(int& i) { return i; } +int& val(Abstract& a) { return a.val(); } +int& val(ScopeGuard& g) { return g.val(); } + +const int& val(const int& i) { return i; } +const int& val(const Abstract& a) { return a.val(); } +const int& val(const ScopeGuard& g) { return g.val(); } + +bool operator==(const Abstract& l, const Abstract& r) { return l.val() == r.val(); } +bool operator==(const ScopeGuard& l, const ScopeGuard& r) { return l.val() == r.val(); } + +bool operator<(const Abstract& l, const Abstract& r) { return l.val() < r.val(); } +bool operator<(const ScopeGuard& l, const ScopeGuard& r) { return l.val() < r.val(); } + +#endif //BOOST_OPTIONAL_TEST_TESTABKE_CLASSES_AK_07JAN2015_HPP From 9e3a4a9b7b2193d38a87b64c31613ddf2d5b08f0 Mon Sep 17 00:00:00 2001 From: Andrzej Krzemienski Date: Thu, 8 Jan 2015 11:33:58 +0100 Subject: [PATCH 13/23] finished dividing optional ref tests --- test/Jamfile.v2 | 2 +- test/optional_test_ref.cpp | 272 -------------------- test/optional_test_ref_converting_ctor.cpp | 107 ++++++++ test/optional_test_ref_portable_minimum.cpp | 32 +++ 4 files changed, 140 insertions(+), 273 deletions(-) delete mode 100644 test/optional_test_ref.cpp create mode 100644 test/optional_test_ref_converting_ctor.cpp diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index dc29fea..952c75d 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -19,10 +19,10 @@ import testing ; [ run optional_test.cpp ] [ run optional_test_conversions_from_U.cpp ] [ run optional_test_tie.cpp ] - [ run optional_test_ref.cpp ] [ run optional_test_ref_assign_portable_minimum.cpp ] [ run optional_test_ref_assign_mutable_int.cpp ] [ run optional_test_ref_assign_const_int.cpp ] + [ run optional_test_ref_converting_ctor.cpp ] [ run optional_test_ref_portable_minimum.cpp ] [ run optional_test_inplace.cpp ] [ run optional_test_io.cpp ] diff --git a/test/optional_test_ref.cpp b/test/optional_test_ref.cpp deleted file mode 100644 index 6525ed3..0000000 --- a/test/optional_test_ref.cpp +++ /dev/null @@ -1,272 +0,0 @@ -// Copyright (C) 2003, Fernando Luis Cacciola Carballal. -// -// Use, modification, and distribution is subject to the Boost Software -// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -// -// See http://www.boost.org/lib/optional for documentation. -// -// You are welcome to contact the author at: -// fernando_cacciola@hotmail.com -// -#include -#include -#include - -#define BOOST_ENABLE_ASSERT_HANDLER - -#include "boost/optional.hpp" - -#ifdef __BORLANDC__ -#pragma hdrstop -#endif - -#include "boost/none.hpp" - -#include "boost/test/minimal.hpp" - -#include "optional_test_common.cpp" - -template -inline void check_ref_uninitialized_const ( optional const& opt ) -{ -#ifndef BOOST_OPTIONAL_NO_NULL_COMPARE - BOOST_CHECK( opt == 0 ) ; -#endif - BOOST_CHECK( !opt ) ; -} -template -inline void check_ref_uninitialized ( optional& opt ) -{ -#ifndef BOOST_OPTIONAL_NO_NULL_COMPARE - BOOST_CHECK( opt == 0 ) ; -#endif - BOOST_CHECK( !opt ) ; - - check_ref_uninitialized_const(opt); -} - -template -inline void check_ref_initialized_const ( optional const& opt ) -{ - BOOST_CHECK( opt ) ; - -#ifndef BOOST_OPTIONAL_NO_NULL_COMPARE - BOOST_CHECK( opt != 0 ) ; -#endif - - BOOST_CHECK ( !!opt ) ; -} - -template -inline void check_ref_initialized ( optional& opt ) -{ - BOOST_CHECK( opt ) ; - -#ifndef BOOST_OPTIONAL_NO_NULL_COMPARE - BOOST_CHECK( opt != 0 ) ; -#endif - - BOOST_CHECK ( !!opt ) ; - - check_ref_initialized_const(opt); -} - -template -inline void check_ref_value_const ( optional const& opt, T const& v, T const& z ) -{ - BOOST_CHECK( *opt == v ) ; - BOOST_CHECK( *opt != z ) ; - BOOST_CHECK( opt.get() == v ) ; - BOOST_CHECK( opt.get() != z ) ; -} - -template -inline void check_ref_value ( optional& opt, T const& v, T const& z ) -{ - BOOST_CHECK( *opt == v ) ; - BOOST_CHECK( *opt != z ) ; - BOOST_CHECK( opt.get() == v ) ; - BOOST_CHECK( opt.get() != z ) ; - - check_ref_value_const(opt,v,z); -} - -// -// Basic test. -// Check ordinary functionality: -// Initialization, assignment, comparison and value-accessing. -// -template -void test_basics( T const* ) -{ - TRACE( std::endl << BOOST_CURRENT_FUNCTION ); - - T z(0); - - T original_a(1); - - T a(1); - - T b(2); - - T c(10); - - T& aref = a ; - T& bref = b ; - - // Default construction. - // 'def' state is Uninitialized. - // T::T() is not called - optional def ; - check_ref_uninitialized(def); - - // Direct initialization. - // 'oa' state is Initialized and binds to 'a' - // T::T( T const& x ) is NOT used becasue the optional holds a reference. - set_pending_copy( ARG(T) ) ; - optional oa ( aref ) ; - check_is_pending_copy( ARG(T) ); - check_ref_initialized(oa); - check_ref_value(oa,a,z); - *oa = b ; // changes the value of 'a' through the reference - BOOST_CHECK( a == b ) ; - - - // Copy initialization. - // T::T ( T const& x ) is NOT used becasue the optional holds a reference. - set_pending_copy( ARG(T) ) ; - optional const oa2 ( oa ) ; - check_is_pending_copy( ARG(T) ) ; - check_ref_initialized_const(oa2); - check_ref_value_const(oa2,a,z); - *oa2 = original_a ; // restores the value of 'a' through the reference - BOOST_CHECK( a == original_a ) ; - - optional ob ; - - // Value-Assignment upon Uninitialized optional. - // T::T ( T const& x ) is NOT used becasue the optional holds a reference. - set_pending_copy( ARG(T) ) ; - ob = a ; // Binds ob to a temporary non-const refererence to 'a' - check_is_pending_copy( ARG(T) ) ; - check_ref_initialized(ob); - check_ref_value(ob,a,z); - a = c; - check_ref_value(ob,a,z); - - // Value-Assignment upon Initialized optional. - // T::operator= ( T const& x ) is used. - set_pending_assign( ARG(T) ) ; - ob = b ; // Rebinds 'ob' to 'b' (without changing 'a') - check_is_pending_assign( ARG(T) ) ; - check_ref_initialized(ob); - check_ref_value(ob,b,z); - BOOST_CHECK(a == c); // From a=c in previous test - b = c; - check_ref_value(ob,b,z); - - - // Assignment initialization. - // T::T ( T const& x ) is NOT used becasue the optional holds a reference. - set_pending_copy( ARG(T) ) ; - optional const oa3 = b ; - check_is_pending_copy( ARG(T) ) ; - check_ref_initialized_const(oa3); - check_ref_value_const(oa3,b,z); - - - // Assignment - // T::operator=( T const& x ) is used. - set_pending_assign( ARG(T) ) ; - oa = ob ; // Rebinds 'a' to 'b' - check_is_pending_assign( ARG(T) ) ; - check_ref_initialized(oa); - a = original_a ; - check_ref_value(oa,b,z); - - // Uninitializing Assignment upon Initialized Optional - // T::~T() is NOT used becasue the optional holds a reference. - set_pending_dtor( ARG(T) ) ; - set_pending_copy( ARG(T) ) ; - oa = def ; - check_is_pending_dtor( ARG(T) ) ; - check_is_pending_copy( ARG(T) ) ; - check_ref_uninitialized(oa); - - // Uninitializing Assignment upon Uninitialized Optional - // (Dtor is not called this time) - set_pending_dtor( ARG(T) ) ; - set_pending_copy( ARG(T) ) ; - oa = def ; - check_is_pending_dtor( ARG(T) ) ; - check_is_pending_copy( ARG(T) ) ; - check_ref_uninitialized(oa); - - - // Deinitialization of Initialized Optional - // T::~T() is NOT used becasue the optional holds a reference. - set_pending_dtor( ARG(T) ) ; - ob.reset(); - check_is_pending_dtor( ARG(T) ) ; - check_ref_uninitialized(ob); - - // Deinitialization of Uninitialized Optional - // T::~T() is not called this time - set_pending_dtor( ARG(T) ) ; - ob.reset(); - check_is_pending_dtor( ARG(T) ) ; - check_ref_uninitialized(ob); -} - - -void test_with_builtin_types() -{ - TRACE( std::endl << BOOST_CURRENT_FUNCTION ); - - test_basics( ARG(double) ); -} - -void test_with_class_type() -{ - TRACE( std::endl << BOOST_CURRENT_FUNCTION ); - - test_basics( ARG(X) ); - - BOOST_CHECK ( X::count == 0 ) ; -} - -void test_binding() -{ - int i = 0 ; - optional ori1 = i ; - BOOST_CHECK( &(*ori1) == &i ) ; - - optional ori2(i) ; - BOOST_CHECK( &(*ori2) == &i ) ; - - int const ci = 0 ; - optional orci1 = ci ; - BOOST_CHECK( &(*orci1) == &ci ) ; - - optional orci2(ci) ; - BOOST_CHECK( &(*orci2) == &ci ) ; -} - -int test_main( int, char* [] ) -{ - try - { - test_with_class_type(); - test_with_builtin_types(); - test_binding(); - } - catch ( ... ) - { - BOOST_ERROR("Unexpected Exception caught!"); - } - - return 0; -} - - diff --git a/test/optional_test_ref_converting_ctor.cpp b/test/optional_test_ref_converting_ctor.cpp new file mode 100644 index 0000000..d7df3dc --- /dev/null +++ b/test/optional_test_ref_converting_ctor.cpp @@ -0,0 +1,107 @@ +// Copyright (C) 2014 Andrzej Krzemienski. +// +// Use, modification, and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/lib/optional for documentation. +// +// You are welcome to contact the author at: akrzemi1@gmail.com + + +#include "boost/optional/optional.hpp" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#include "boost/core/addressof.hpp" +#include "boost/core/enable_if.hpp" +#include "boost/core/lightweight_test.hpp" +#include "testable_classes.hpp" + +using boost::optional; +using boost::none; + +template +void test_converting_ctor() +{ + typename concrete_type_of::type v1(1), v2(2); + + { + optional o1 = v1, o1_ = v1, o2 = v2; + + BOOST_TEST(o1); + BOOST_TEST(boost::addressof(*o1) == boost::addressof(v1)); + BOOST_TEST(o1_); + BOOST_TEST(boost::addressof(*o1_) == boost::addressof(v1)); + BOOST_TEST(boost::addressof(*o1_) == boost::addressof(*o1)); + + BOOST_TEST(o2); + BOOST_TEST(boost::addressof(*o2) == boost::addressof(v2)); + BOOST_TEST(boost::addressof(*o2) != boost::addressof(*o1)); + } + { + const optional o1 = v1, o1_ = v1, o2 = v2; + + BOOST_TEST(o1); + BOOST_TEST(boost::addressof(*o1) == boost::addressof(v1)); + BOOST_TEST(o1_); + BOOST_TEST(boost::addressof(*o1_) == boost::addressof(v1)); + BOOST_TEST(boost::addressof(*o1_) == boost::addressof(*o1)); + + BOOST_TEST(o2); + BOOST_TEST(boost::addressof(*o2) == boost::addressof(v2)); + BOOST_TEST(boost::addressof(*o2) != boost::addressof(*o1)); + } +} + +template +void test_converting_ctor_for_noconst_const() +{ + typename concrete_type_of::type v1(1), v2(2); + + { + optional o1 = v1, o1_ = v1, o2 = v2; + + BOOST_TEST(o1); + BOOST_TEST(boost::addressof(*o1) == boost::addressof(v1)); + BOOST_TEST(o1_); + BOOST_TEST(boost::addressof(*o1_) == boost::addressof(v1)); + BOOST_TEST(boost::addressof(*o1_) == boost::addressof(*o1)); + + BOOST_TEST(o2); + BOOST_TEST(boost::addressof(*o2) == boost::addressof(v2)); + BOOST_TEST(boost::addressof(*o2) != boost::addressof(*o1)); + } + { + const optional o1 = v1, o1_ = v1, o2 = v2; + + BOOST_TEST(o1); + BOOST_TEST(boost::addressof(*o1) == boost::addressof(v1)); + BOOST_TEST(o1_); + BOOST_TEST(boost::addressof(*o1_) == boost::addressof(v1)); + BOOST_TEST(boost::addressof(*o1_) == boost::addressof(*o1)); + + BOOST_TEST(o2); + BOOST_TEST(boost::addressof(*o2) == boost::addressof(v2)); + BOOST_TEST(boost::addressof(*o2) != boost::addressof(*o1)); + } +} + +template +void test_all_const_cases() +{ + test_converting_ctor(); + test_converting_ctor(); + test_converting_ctor_for_noconst_const(); +} + +int main() +{ + test_all_const_cases(); + test_all_const_cases(); + //test_all_const_cases(); + + return boost::report_errors(); +} diff --git a/test/optional_test_ref_portable_minimum.cpp b/test/optional_test_ref_portable_minimum.cpp index ddcffc9..e8439c9 100644 --- a/test/optional_test_ref_portable_minimum.cpp +++ b/test/optional_test_ref_portable_minimum.cpp @@ -23,6 +23,38 @@ using boost::optional; using boost::none; +struct CountingClass +{ + static int count; + static int assign_count; + CountingClass() { ++count; } + CountingClass(const CountingClass&) { ++count; } + CountingClass& operator=(const CountingClass&) { ++assign_count; return *this; } + ~CountingClass() { ++count; } +}; + +int CountingClass::count = 0; +int CountingClass::assign_count = 0; + +void test_no_object_creation() +{ + BOOST_TEST_EQ(0, CountingClass::count); + BOOST_TEST_EQ(0, CountingClass::assign_count); + { + CountingClass v1, v2; + optional oA(v1); + optional oB; + optional oC = oA; + oB = oA; + *oB = v2; + oC = none; + oC = optional(v2); + oB = none; + oA = oB; + } + BOOST_TEST_EQ(4, CountingClass::count); + BOOST_TEST_EQ(1, CountingClass::assign_count); +} template typename boost::enable_if< has_arrow >::type From 35eaec5a52b47f305f3cadcf0546e76992fc344e Mon Sep 17 00:00:00 2001 From: Andrzej Krzemienski Date: Mon, 12 Jan 2015 17:37:15 +0100 Subject: [PATCH 14/23] Doc: added release notes section --- doc/00_optional.qbk | 3 +- doc/91_relnotes.qbk | 41 ++++ ...owledgments.qbk => 92_acknowledgments.qbk} | 2 +- doc/html/boost_optional/acknowledgements.html | 6 +- .../optional_reference_binding.html | 6 +- doc/html/boost_optional/relnotes.html | 119 ++++++++++ doc/html/index.html | 3 +- test/optional_test_move.cpp | 220 ++++++++---------- 8 files changed, 270 insertions(+), 130 deletions(-) create mode 100644 doc/91_relnotes.qbk rename doc/{91_acknowledgments.qbk => 92_acknowledgments.qbk} (98%) create mode 100644 doc/html/boost_optional/relnotes.html diff --git a/doc/00_optional.qbk b/doc/00_optional.qbk index 95c982f..2f940b7 100644 --- a/doc/00_optional.qbk +++ b/doc/00_optional.qbk @@ -91,6 +91,7 @@ This is how you solve it with `boost::optional`: [include 20_reference.qbk] [endsect] [include 90_dependencies.qbk] -[include 91_acknowledgments.qbk] +[include 91_relnotes.qbk] +[include 92_acknowledgments.qbk] diff --git a/doc/91_relnotes.qbk b/doc/91_relnotes.qbk new file mode 100644 index 0000000..94a9c61 --- /dev/null +++ b/doc/91_relnotes.qbk @@ -0,0 +1,41 @@ +[/ + Boost.Optional + + Copyright (c) 2015 Andrzej Krzemienski + + Distributed under the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) +] + + +[section:relnotes Release Notes] + +[heading Boost Release 1.58] + +* `boost::none_t` is no longer convertible from literal `0`. This avoids a bug where `optional> oi = 0;` would initialize an optional object with no contained value. + + +[heading Boost Release 1.57] + +* [@https://github.com/boostorg/optional/pull/9 Git pull #9]: ['"Supply `` to fix C++03 compile error on `logic_error("...")`"]. + + +[heading Boost Release 1.56] + +* Added support for rvalue references. Now `optional` works with moveable but non-copyable `T`'s, +* Improved `swap` (now uses move operations), +* Added function `emplace()`. This is the last of the requests from [@https://svn.boost.org/trac/boost/ticket/1841 Trac #1841], +* `optional` is moveable, including conditional `noexcept` specifications, which make it `move_if_noexcept`-friendly, +* Using explicit operator bool() on platforms that support it ([@https://svn.boost.org/trac/boost/ticket/4227 Trac #4227]) (breaking change), +* Forward declaration of `operator<<(ostream&, optional const&)` to prevent inadvertent incorrect serialization of optional objects, +* Removed deprecated function `reset()` from examples ([@https://svn.boost.org/trac/boost/ticket/9005 Trac #9005]), +* Equality comparison with `boost::none` does not require that `T` be EqualityComparable, +* Optional rvalue references are explicitly disallowed, +* Binding temporaries to optional references is explicitly disallowed (breaking change), +* More ways to access the contained value, functions `value()`, `value_or()`, `value_or_eval()`, +* Updated and reorganized documentation, added tutorial and quick guide sections. + + + +[endsect][/ relnotes] diff --git a/doc/91_acknowledgments.qbk b/doc/92_acknowledgments.qbk similarity index 98% rename from doc/91_acknowledgments.qbk rename to doc/92_acknowledgments.qbk index cb1b3bb..f337ce2 100644 --- a/doc/91_acknowledgments.qbk +++ b/doc/92_acknowledgments.qbk @@ -9,7 +9,7 @@ ] -[section Acknowledgements] +[section:acknowledgements Acknowledgements] [heading Pre-formal review] diff --git a/doc/html/boost_optional/acknowledgements.html b/doc/html/boost_optional/acknowledgements.html index 659795d..9c8019a 100644 --- a/doc/html/boost_optional/acknowledgements.html +++ b/doc/html/boost_optional/acknowledgements.html @@ -6,7 +6,7 @@ - + @@ -19,7 +19,7 @@

-PrevUpHome +PrevUpHome

@@ -124,7 +124,7 @@
-PrevUpHome +PrevUpHome
diff --git a/doc/html/boost_optional/dependencies_and_portability/optional_reference_binding.html b/doc/html/boost_optional/dependencies_and_portability/optional_reference_binding.html index b27d9c1..fe0e2b6 100644 --- a/doc/html/boost_optional/dependencies_and_portability/optional_reference_binding.html +++ b/doc/html/boost_optional/dependencies_and_portability/optional_reference_binding.html @@ -7,7 +7,7 @@ - + @@ -20,7 +20,7 @@

-PrevUpHomeNext +PrevUpHomeNext

@@ -94,7 +94,7 @@
-PrevUpHomeNext +PrevUpHomeNext
diff --git a/doc/html/boost_optional/relnotes.html b/doc/html/boost_optional/relnotes.html new file mode 100644 index 0000000..c0dc717 --- /dev/null +++ b/doc/html/boost_optional/relnotes.html @@ -0,0 +1,119 @@ + + + +Release Notes + + + + + + + + + + + + + + + +
Boost C++ LibrariesHomeLibrariesPeopleFAQMore
+
+
+PrevUpHomeNext +
+
+ +

+ + Boost + Release 1.58 +

+
  • + boost::none_t is no longer convertible from + literal 0. This avoids a bug + where optional<rational<int>> oi = 0; would + initialize an optional object with no contained value. +
+

+ + Boost + Release 1.57 +

+
  • + Git pull #9: + "Supply <string> + to fix C++03 compile error on logic_error("...")". +
+

+ + Boost + Release 1.56 +

+
    +
  • + Added support for rvalue references. Now optional<T> works with moveable but non-copyable + T's, +
  • +
  • + Improved swap (now uses + move operations), +
  • +
  • + Added function emplace(). This is the last of the requests from + Trac #1841, +
  • +
  • + optional is moveable, including + conditional noexcept specifications, + which make it move_if_noexcept-friendly, +
  • +
  • + Using explicit operator bool() on platforms that support it (Trac + #4227) (breaking change), +
  • +
  • + Forward declaration of operator<<(ostream&, optional + const&) + to prevent inadvertent incorrect serialization of optional objects, +
  • +
  • + Removed deprecated function reset() from examples (Trac + #9005), +
  • +
  • + Equality comparison with boost::none + does not require that T + be EqualityComparable, +
  • +
  • + Optional rvalue references are explicitly disallowed, +
  • +
  • + Binding temporaries to optional references is explicitly disallowed (breaking + change), +
  • +
  • + More ways to access the contained value, functions value(), value_or(), value_or_eval(), +
  • +
  • + Updated and reorganized documentation, added tutorial and quick guide sections. +
  • +
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/index.html b/doc/html/index.html index 58b2183..d3e9ad7 100644 --- a/doc/html/index.html +++ b/doc/html/index.html @@ -86,6 +86,7 @@
Optional Reference Binding
+
Release Notes
Acknowledgements

@@ -136,7 +137,7 @@
- +

Last revised: December 06, 2014 at 20:01:35 GMT

Last revised: January 12, 2015 at 16:12:58 GMT


diff --git a/test/optional_test_move.cpp b/test/optional_test_move.cpp index 779e0c7..51aa970 100644 --- a/test/optional_test_move.cpp +++ b/test/optional_test_move.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014 Andrzej Krzemienski. +// Copyright (C) 2014 - 2015 Andrzej Krzemienski. // // Use, modification, and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at @@ -8,19 +8,7 @@ // // You are welcome to contact the author at: // akrzemi1@gmail.com -// -// Revisions: -// -#include -#include -#include -#define BOOST_ENABLE_ASSERT_HANDLER - -#include "boost/bind/apply.hpp" // Included just to test proper interaction with boost::apply<> as reported by Daniel Wallin -#include "boost/mpl/bool.hpp" -#include "boost/mpl/bool_fwd.hpp" // For mpl::true_ and mpl::false_ -#include "boost/static_assert.hpp" #include "boost/optional/optional.hpp" @@ -28,11 +16,10 @@ #pragma hdrstop #endif -#include "boost/none.hpp" +#include "boost/core/lightweight_test.hpp" -#include "boost/test/minimal.hpp" - -#include "optional_test_common.cpp" +using boost::optional; +using boost::none; //#ifndef BOOST_OPTIONAL_NO_CONVERTING_ASSIGNMENT //#ifndef BOOST_OPTIONAL_NO_CONVERTING_COPY_CTOR @@ -86,37 +73,37 @@ bool operator!=( Oracle const& a, Oracle const& b ) { return a.val.i != b.val.i; void test_move_ctor_from_U() { optional o1 ((OracleVal())); - BOOST_CHECK(o1); - BOOST_CHECK(o1->s == sValueMoveConstructed || o1->s == sMoveConstructed); + BOOST_TEST(o1); + BOOST_TEST(o1->s == sValueMoveConstructed || o1->s == sMoveConstructed); OracleVal v1; optional o2 (v1); - BOOST_CHECK(o2); - BOOST_CHECK(o2->s == sValueCopyConstructed || o2->s == sCopyConstructed || o2->s == sMoveConstructed ); - BOOST_CHECK(v1.s == sIntConstructed); + BOOST_TEST(o2); + BOOST_TEST(o2->s == sValueCopyConstructed || o2->s == sCopyConstructed || o2->s == sMoveConstructed ); + BOOST_TEST(v1.s == sIntConstructed); optional o3 (boost::move(v1)); - BOOST_CHECK(o3); - BOOST_CHECK(o3->s == sValueMoveConstructed || o3->s == sMoveConstructed); - BOOST_CHECK(v1.s == sMovedFrom); + BOOST_TEST(o3); + BOOST_TEST(o3->s == sValueMoveConstructed || o3->s == sMoveConstructed); + BOOST_TEST(v1.s == sMovedFrom); } void test_move_ctor_form_T() { optional o1 ((Oracle())); - BOOST_CHECK(o1); - BOOST_CHECK(o1->s == sMoveConstructed); + BOOST_TEST(o1); + BOOST_TEST(o1->s == sMoveConstructed); Oracle v1; optional o2 (v1); - BOOST_CHECK(o2); - BOOST_CHECK(o2->s == sCopyConstructed); - BOOST_CHECK(v1.s == sDefaultConstructed); + BOOST_TEST(o2); + BOOST_TEST(o2->s == sCopyConstructed); + BOOST_TEST(v1.s == sDefaultConstructed); optional o3 (boost::move(v1)); - BOOST_CHECK(o3); - BOOST_CHECK(o3->s == sMoveConstructed); - BOOST_CHECK(v1.s == sMovedFrom); + BOOST_TEST(o3); + BOOST_TEST(o3->s == sMoveConstructed); + BOOST_TEST(v1.s == sMovedFrom); } void test_move_ctor_from_optional_T() @@ -124,22 +111,22 @@ void test_move_ctor_from_optional_T() optional o1; optional o2(boost::move(o1)); - BOOST_CHECK(!o1); - BOOST_CHECK(!o2); + BOOST_TEST(!o1); + BOOST_TEST(!o2); optional o3((Oracle())); optional o4(boost::move(o3)); - BOOST_CHECK(o3); - BOOST_CHECK(o4); - BOOST_CHECK(o3->s == sMovedFrom); - BOOST_CHECK(o4->s == sMoveConstructed); + BOOST_TEST(o3); + BOOST_TEST(o4); + BOOST_TEST(o3->s == sMovedFrom); + BOOST_TEST(o4->s == sMoveConstructed); optional o5((optional())); - BOOST_CHECK(!o5); + BOOST_TEST(!o5); optional o6((optional(Oracle()))); - BOOST_CHECK(o6); - BOOST_CHECK(o6->s == sMoveConstructed); + BOOST_TEST(o6); + BOOST_TEST(o6->s == sMoveConstructed); optional o7(o6); // does copy ctor from non-const lvalue compile? } @@ -149,59 +136,59 @@ void test_move_assign_from_U() optional o1 = boost::none; // test if additional ctors didn't break it o1 = boost::none; // test if additional assignments didn't break it o1 = OracleVal(); - BOOST_CHECK(o1); + BOOST_TEST(o1); - BOOST_CHECK(o1->s == sValueMoveConstructed); + BOOST_TEST(o1->s == sValueMoveConstructed); o1 = OracleVal(); - BOOST_CHECK(o1); - BOOST_CHECK(o1->s == sMoveAssigned); + BOOST_TEST(o1); + BOOST_TEST(o1->s == sMoveAssigned); OracleVal v1; optional o2; o2 = v1; - BOOST_CHECK(o2); - BOOST_CHECK(o2->s == sValueCopyConstructed); - BOOST_CHECK(v1.s == sIntConstructed); + BOOST_TEST(o2); + BOOST_TEST(o2->s == sValueCopyConstructed); + BOOST_TEST(v1.s == sIntConstructed); o2 = v1; - BOOST_CHECK(o2); - BOOST_CHECK(o2->s == sCopyAssigned || o2->s == sMoveAssigned); - BOOST_CHECK(v1.s == sIntConstructed); + BOOST_TEST(o2); + BOOST_TEST(o2->s == sCopyAssigned || o2->s == sMoveAssigned); + BOOST_TEST(v1.s == sIntConstructed); optional o3; o3 = boost::move(v1); - BOOST_CHECK(o3); - BOOST_CHECK(o3->s == sValueMoveConstructed); - BOOST_CHECK(v1.s == sMovedFrom); + BOOST_TEST(o3); + BOOST_TEST(o3->s == sValueMoveConstructed); + BOOST_TEST(v1.s == sMovedFrom); } void test_move_assign_from_T() { optional o1; o1 = Oracle(); - BOOST_CHECK(o1); - BOOST_CHECK(o1->s == sMoveConstructed); + BOOST_TEST(o1); + BOOST_TEST(o1->s == sMoveConstructed); o1 = Oracle(); - BOOST_CHECK(o1); - BOOST_CHECK(o1->s == sMoveAssigned); + BOOST_TEST(o1); + BOOST_TEST(o1->s == sMoveAssigned); Oracle v1; optional o2; o2 = v1; - BOOST_CHECK(o2); - BOOST_CHECK(o2->s == sCopyConstructed); - BOOST_CHECK(v1.s == sDefaultConstructed); + BOOST_TEST(o2); + BOOST_TEST(o2->s == sCopyConstructed); + BOOST_TEST(v1.s == sDefaultConstructed); o2 = v1; - BOOST_CHECK(o2); - BOOST_CHECK(o2->s == sCopyAssigned); - BOOST_CHECK(v1.s == sDefaultConstructed); + BOOST_TEST(o2); + BOOST_TEST(o2->s == sCopyAssigned); + BOOST_TEST(v1.s == sDefaultConstructed); optional o3; o3 = boost::move(v1); - BOOST_CHECK(o3); - BOOST_CHECK(o3->s == sMoveConstructed); - BOOST_CHECK(v1.s == sMovedFrom); + BOOST_TEST(o3); + BOOST_TEST(o3->s == sMoveConstructed); + BOOST_TEST(v1.s == sMovedFrom); } void test_move_assign_from_optional_T() @@ -209,23 +196,23 @@ void test_move_assign_from_optional_T() optional o1; optional o2; o1 = optional(); - BOOST_CHECK(!o1); + BOOST_TEST(!o1); optional o3((Oracle())); o1 = o3; - BOOST_CHECK(o3); - BOOST_CHECK(o3->s == sMoveConstructed); - BOOST_CHECK(o1); - BOOST_CHECK(o1->s == sCopyConstructed); + BOOST_TEST(o3); + BOOST_TEST(o3->s == sMoveConstructed); + BOOST_TEST(o1); + BOOST_TEST(o1->s == sCopyConstructed); o2 = boost::move(o3); - BOOST_CHECK(o3); - BOOST_CHECK(o3->s == sMovedFrom); - BOOST_CHECK(o2); - BOOST_CHECK(o2->s == sMoveConstructed); + BOOST_TEST(o3); + BOOST_TEST(o3->s == sMovedFrom); + BOOST_TEST(o2); + BOOST_TEST(o2->s == sMoveConstructed); o2 = optional((Oracle())); - BOOST_CHECK(o2); - BOOST_CHECK(o2->s == sMoveAssigned); + BOOST_TEST(o2); + BOOST_TEST(o2->s == sMoveAssigned); } class MoveOnly @@ -247,21 +234,21 @@ void test_with_move_only() { optional o1; optional o2((MoveOnly(1))); - BOOST_CHECK(o2); - BOOST_CHECK(o2->val == 1); + BOOST_TEST(o2); + BOOST_TEST(o2->val == 1); optional o3 (boost::move(o1)); - BOOST_CHECK(!o3); + BOOST_TEST(!o3); optional o4 (boost::move(o2)); - BOOST_CHECK(o4); - BOOST_CHECK(o4->val == 1); - BOOST_CHECK(o2); - BOOST_CHECK(o2->val == 0); + BOOST_TEST(o4); + BOOST_TEST(o4->val == 1); + BOOST_TEST(o2); + BOOST_TEST(o2->val == 0); o3 = boost::move(o4); - BOOST_CHECK(o3); - BOOST_CHECK(o3->val == 1); - BOOST_CHECK(o4); - BOOST_CHECK(o4->val == 0); + BOOST_TEST(o3); + BOOST_TEST(o3->val == 1); + BOOST_TEST(o4); + BOOST_TEST(o4->val == 0); } class MoveOnlyB @@ -287,15 +274,15 @@ void test_move_assign_from_optional_U() optional b1; b1 = boost::move(a); - BOOST_CHECK(b1); - BOOST_CHECK(b1->val == 2); - BOOST_CHECK(a); - BOOST_CHECK(a->val == 0); + BOOST_TEST(b1); + BOOST_TEST(b1->val == 2); + BOOST_TEST(a); + BOOST_TEST(a->val == 0); b1 = MoveOnly(4); - BOOST_CHECK(b1); - BOOST_CHECK(b1->val == 4); + BOOST_TEST(b1); + BOOST_TEST(b1->val == 4); } void test_move_ctor_from_optional_U() @@ -303,15 +290,15 @@ void test_move_ctor_from_optional_U() optional a((MoveOnly(2))); optional b1(boost::move(a)); - BOOST_CHECK(b1); - BOOST_CHECK(b1->val == 2); - BOOST_CHECK(a); - BOOST_CHECK(a->val == 0); + BOOST_TEST(b1); + BOOST_TEST(b1->val == 2); + BOOST_TEST(a); + BOOST_TEST(a->val == 0); optional b2(( optional(( MoveOnly(4) )) )); - BOOST_CHECK(b2); - BOOST_CHECK(b2->val == 4); + BOOST_TEST(b2); + BOOST_TEST(b2->val == 4); } void test_swap() @@ -320,8 +307,8 @@ void test_swap() optional b((MoveOnly(3))); swap(a, b); - BOOST_CHECK(a->val == 3); - BOOST_CHECK(b->val == 2); + BOOST_TEST(a->val == 3); + BOOST_TEST(b->val == 2); } void test_optional_ref_to_movables() @@ -329,26 +316,24 @@ void test_optional_ref_to_movables() MoveOnly m(3); optional orm = m; orm->val = 2; - BOOST_CHECK(m.val == 2); + BOOST_TEST(m.val == 2); optional orm2 = orm; orm2->val = 1; - BOOST_CHECK(m.val == 1); - BOOST_CHECK(orm->val == 1); + BOOST_TEST(m.val == 1); + BOOST_TEST(orm->val == 1); optional orm3 = boost::move(orm); orm3->val = 4; - BOOST_CHECK(m.val == 4); - BOOST_CHECK(orm->val == 4); - BOOST_CHECK(orm2->val == 4); + BOOST_TEST(m.val == 4); + BOOST_TEST(orm->val == 4); + BOOST_TEST(orm2->val == 4); } #endif -int test_main( int, char* [] ) +int main() { - try - { #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES test_move_ctor_from_U(); test_move_ctor_form_T(); @@ -362,13 +347,6 @@ int test_main( int, char* [] ) test_optional_ref_to_movables(); test_swap(); #endif - } - catch ( ... ) - { - BOOST_ERROR("Unexpected Exception caught!"); - } - return 0; + return boost::report_errors(); } - - From a8a6be013fe12a67ffc5b97ff449ac6160f27194 Mon Sep 17 00:00:00 2001 From: Andrzej Krzemienski Date: Tue, 13 Jan 2015 23:17:23 +0100 Subject: [PATCH 15/23] More tests migrated to core/minimal_test --- test/optional_test_emplace.cpp | 90 +++++++++++++--------------------- test/optional_test_io.cpp | 75 ++++++++-------------------- 2 files changed, 55 insertions(+), 110 deletions(-) diff --git a/test/optional_test_emplace.cpp b/test/optional_test_emplace.cpp index b55c1eb..117f26c 100644 --- a/test/optional_test_emplace.cpp +++ b/test/optional_test_emplace.cpp @@ -8,19 +8,6 @@ // // You are welcome to contact the author at: // akrzemi1@gmail.com -// -// Revisions: -// -#include -#include -#include - -#define BOOST_ENABLE_ASSERT_HANDLER - -#include "boost/bind/apply.hpp" // Included just to test proper interaction with boost::apply<> as reported by Daniel Wallin -#include "boost/mpl/bool.hpp" -#include "boost/mpl/bool_fwd.hpp" // For mpl::true_ and mpl::false_ -#include "boost/static_assert.hpp" #include "boost/optional/optional.hpp" @@ -28,15 +15,15 @@ #pragma hdrstop #endif +#include "boost/core/lightweight_test.hpp" #include "boost/none.hpp" -#include "boost/test/minimal.hpp" - -#include "optional_test_common.cpp" - //#ifndef BOOST_OPTIONAL_NO_CONVERTING_ASSIGNMENT //#ifndef BOOST_OPTIONAL_NO_CONVERTING_COPY_CTOR +using boost::optional; +using boost::none; + #if (!defined BOOST_NO_CXX11_RVALUE_REFERENCES) && (!defined BOOST_NO_CXX11_VARIADIC_TEMPLATES) class Guard @@ -68,36 +55,36 @@ void test_emplace() optional o; o.emplace(); - BOOST_CHECK(o); - BOOST_CHECK(0 == o->which_ctor); + BOOST_TEST(o); + BOOST_TEST(0 == o->which_ctor); o.emplace(i, 2.0); - BOOST_CHECK(o); - BOOST_CHECK(1 == o->which_ctor); + BOOST_TEST(o); + BOOST_TEST(1 == o->which_ctor); o.emplace(1, d); - BOOST_CHECK(o); - BOOST_CHECK(2 == o->which_ctor); + BOOST_TEST(o); + BOOST_TEST(2 == o->which_ctor); o.emplace(1, 2.0); - BOOST_CHECK(o); - BOOST_CHECK(3 == o->which_ctor); + BOOST_TEST(o); + BOOST_TEST(3 == o->which_ctor); o.emplace(i, d); - BOOST_CHECK(o); - BOOST_CHECK(4 == o->which_ctor); + BOOST_TEST(o); + BOOST_TEST(4 == o->which_ctor); o.emplace(cs); - BOOST_CHECK(o); - BOOST_CHECK(5 == o->which_ctor); + BOOST_TEST(o); + BOOST_TEST(5 == o->which_ctor); o.emplace(ms); - BOOST_CHECK(o); - BOOST_CHECK(6 == o->which_ctor); + BOOST_TEST(o); + BOOST_TEST(6 == o->which_ctor); o.emplace(std::string()); - BOOST_CHECK(o); - BOOST_CHECK(7 == o->which_ctor); + BOOST_TEST(o); + BOOST_TEST(7 == o->which_ctor); } @@ -119,10 +106,10 @@ void test_no_moves_on_emplacement() try { optional o; o.emplace(1); - BOOST_CHECK(o); + BOOST_TEST(o); } catch (...) { - BOOST_CHECK(false); + BOOST_TEST(false); } } #endif @@ -143,47 +130,40 @@ void test_clear_on_throw() optional ot; try { ot.emplace(false); - BOOST_CHECK(ot); + BOOST_TEST(ot); } catch(...) { - BOOST_CHECK(false); + BOOST_TEST(false); } try { ot.emplace(true); - BOOST_CHECK(false); + BOOST_TEST(false); } catch(...) { - BOOST_CHECK(!ot); + BOOST_TEST(!ot); } } void test_no_assignment_on_emplacement() { optional os; - BOOST_CHECK(!os); + BOOST_TEST(!os); os.emplace("wow"); - BOOST_CHECK(os); - BOOST_CHECK(*os == "wow"); + BOOST_TEST(os); + BOOST_TEST_EQ(*os, "wow"); } -int test_main( int, char* [] ) +int main() { - try - { #if (!defined BOOST_NO_CXX11_RVALUE_REFERENCES) && (!defined BOOST_NO_CXX11_VARIADIC_TEMPLATES) - test_emplace(); + test_emplace(); #endif #if (!defined BOOST_NO_CXX11_RVALUE_REFERENCES) - test_no_moves_on_emplacement(); + test_no_moves_on_emplacement(); #endif - test_clear_on_throw(); - test_no_assignment_on_emplacement(); - } - catch ( ... ) - { - BOOST_ERROR("Unexpected Exception caught!"); - } + test_clear_on_throw(); + test_no_assignment_on_emplacement(); - return 0; + return boost::report_errors(); } diff --git a/test/optional_test_io.cpp b/test/optional_test_io.cpp index a4877d5..196363e 100644 --- a/test/optional_test_io.cpp +++ b/test/optional_test_io.cpp @@ -1,4 +1,5 @@ // Copyright (C) 2003, Fernando Luis Cacciola Carballal. +// Copyright (C) 2014 Andrzej Krzemienski. // // Use, modification, and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at @@ -8,52 +9,24 @@ // // You are welcome to contact the author at: // fernando_cacciola@hotmail.com -// -#include -#include -#include - -#define BOOST_ENABLE_ASSERT_HANDLER +#include #include "boost/optional/optional.hpp" #include "boost/optional/optional_io.hpp" -#include "boost/none.hpp" -#include "boost/test/minimal.hpp" - -#ifdef ENABLE_TRACE -#define TRACE(msg) std::cout << msg << std::endl ; -#else -#define TRACE(msg) +#ifdef __BORLANDC__ +#pragma hdrstop #endif -namespace boost { +#include "boost/core/lightweight_test.hpp" -void assertion_failed (char const * expr, char const * func, char const * file, long ) -{ - using std::string ; - string msg = string("Boost assertion failure for \"") - + string(expr) - + string("\" at file \"") - + string(file) - + string("\" function \"") - + string(func) - + string("\"") ; - - TRACE(msg); - - throw std::logic_error(msg); -} - -} - -using namespace std ; -using namespace boost ; +using boost::optional; +using boost::make_optional; template void test2( Opt o, Opt buff ) { - stringstream s ; + std::stringstream s ; const int markv = 123 ; int mark = 0 ; @@ -61,8 +34,8 @@ void test2( Opt o, Opt buff ) s << o << " " << markv ; s >> buff >> mark ; - BOOST_CHECK( buff == o ) ; - BOOST_CHECK( mark == markv ) ; + BOOST_TEST( buff == o ) ; + BOOST_TEST( mark == markv ) ; } @@ -79,20 +52,20 @@ void test( T v, T w ) template void subtest_tag_none_reversibility_with_optional(optional ov) { - stringstream s; + std::stringstream s; s << boost::none; s >> ov; - BOOST_CHECK(!ov); + BOOST_TEST(!ov); } template void subtest_tag_none_equivalence_with_optional() { - stringstream s, r; + std::stringstream s, r; optional ov; s << boost::none; r << ov; - BOOST_CHECK(s.str() == r.str()); + BOOST_TEST_EQ(s.str(), r.str()); } template @@ -104,20 +77,12 @@ void test_tag_none(T v) } -int test_main( int, char* [] ) +int main() { - try - { - test(1,2); - test(string("hello"),string("buffer")); - test_tag_none(10); - test_tag_none(string("text")); - } - catch ( ... ) - { - BOOST_ERROR("Unexpected Exception caught!"); - } + test(1,2); + test(std::string("hello"), std::string("buffer")); + test_tag_none(10); + test_tag_none(std::string("text")); - return 0; + return boost::report_errors(); } - From 67c7e21b4bef4d884dca1214984e77160f3d0850 Mon Sep 17 00:00:00 2001 From: Andrzej Krzemienski Date: Thu, 15 Jan 2015 22:46:34 +0100 Subject: [PATCH 16/23] Migration to lightweight_test continues --- test/Jamfile.v2 | 2 +- test/optional_test_inplace.cpp | 84 ---------------- test/optional_test_inplace_factory.cpp | 104 ++++++++++++++++++++ test/optional_test_minimum_requirements.cpp | 67 ++++--------- test/optional_test_tie.cpp | 83 ++++++++-------- 5 files changed, 167 insertions(+), 173 deletions(-) delete mode 100644 test/optional_test_inplace.cpp create mode 100644 test/optional_test_inplace_factory.cpp diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 952c75d..63045c5 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -24,7 +24,7 @@ import testing ; [ run optional_test_ref_assign_const_int.cpp ] [ run optional_test_ref_converting_ctor.cpp ] [ run optional_test_ref_portable_minimum.cpp ] - [ run optional_test_inplace.cpp ] + [ run optional_test_inplace_factory.cpp ] [ run optional_test_io.cpp ] [ run optional_test_move.cpp ] [ run optional_test_noexcept_move.cpp ] diff --git a/test/optional_test_inplace.cpp b/test/optional_test_inplace.cpp deleted file mode 100644 index b0e8285..0000000 --- a/test/optional_test_inplace.cpp +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright (C) 2003, Fernando Luis Cacciola Carballal. -// -// Use, modification, and distribution is subject to the Boost Software -// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -// -// See http://www.boost.org/lib/optional for documentation. -// -// You are welcome to contact the author at: -// fernando_cacciola@hotmail.com -// -#include -#include -#include - -#define BOOST_ENABLE_ASSERT_HANDLER - -#include "boost/optional/optional.hpp" - -#ifndef BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT -#include "boost/utility/in_place_factory.hpp" -#include "boost/utility/typed_in_place_factory.hpp" -#endif - -#ifdef __BORLANDC__ -#pragma hdrstop -#endif - -#include "boost/test/minimal.hpp" - -#include "optional_test_common.cpp" - -#ifndef BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT -struct A -{ - A ( double a0, std::string a1 ) : m_a0(a0), m_a1(a1) {} - - friend bool operator == ( A const& x, A const& y ) - { return x.m_a0 == y.m_a0 && x.m_a1 == y.m_a1 ; } - - double m_a0 ; - std::string m_a1 ; -} ; - -int test_main( int, char* [] ) -{ - double a00 = 3.14, a10 = 6.02e-23; - std::string a01("pi"), a11("mol"); - - A a0(a00,a01); - A a1(a10,a11); - - boost::optional opt1(a0); - - boost::optional opt2 ( boost::in_place(a00,a01) ) ; - - boost::optional opt3 ( boost::in_place(a00,a01) ) ; - - BOOST_CHECK( opt1 == opt2 ) ; - BOOST_CHECK( opt2 == opt2 ) ; - BOOST_CHECK( *opt2 == a0 ) ; - -#ifndef BOOST_OPTIONAL_WEAK_OVERLOAD_RESOLUTION - - opt2 = boost::in_place(a10,a11); - BOOST_CHECK( *opt2 == a1 ) ; - - opt3 = boost::in_place(a10,a11); - BOOST_CHECK( *opt3 == a1 ) ; - -#endif - - return 0; -} -#else -int test_main( int, char* [] ) -{ - // If in-place factories are not supported there is nothing to test - return 0 ; -} -#endif - - - diff --git a/test/optional_test_inplace_factory.cpp b/test/optional_test_inplace_factory.cpp new file mode 100644 index 0000000..1e852f0 --- /dev/null +++ b/test/optional_test_inplace_factory.cpp @@ -0,0 +1,104 @@ +// Copyright (C) 2003, Fernando Luis Cacciola Carballal. +// Copyright (C) 2015 Andrzej Krzemienski. +// +// Use, modification, and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/lib/optional for documentation. +// +// You are welcome to contact the author at: +// fernando_cacciola@hotmail.com + +#include +#include "boost/optional/optional.hpp" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#ifndef BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT +#include "boost/utility/in_place_factory.hpp" +#include "boost/utility/typed_in_place_factory.hpp" +#endif + +#include "boost/core/lightweight_test.hpp" +#include "boost/none.hpp" + +struct Guard +{ + double num; + std::string str; + Guard() : num() {} + Guard(double num_, std::string str_) : num(num_), str(str_) {} + + friend bool operator==(const Guard& lhs, const Guard& rhs) { return lhs.num == rhs.num && lhs.str == rhs.str; } + friend bool operator!=(const Guard& lhs, const Guard& rhs) { return !(lhs == rhs); } + +private: + Guard(const Guard&); + Guard& operator=(const Guard&); +}; + +void test_ctor() +{ +#ifndef BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT + Guard g0, g1(1.0, "one"), g2(2.0, "two"); + + boost::optional og0 ( boost::in_place() ); + boost::optional og1 ( boost::in_place(1.0, "one") ); + boost::optional og1_( boost::in_place(1.0, "one") ); + boost::optional og2 ( boost::in_place(2.0, "two") ); + + BOOST_TEST(og0); + BOOST_TEST(og1); + BOOST_TEST(og1_); + BOOST_TEST(og2); + + BOOST_TEST(*og0 == g0); + BOOST_TEST(*og1 == g1); + BOOST_TEST(*og1_ == g1); + BOOST_TEST(*og2 == g2); + + BOOST_TEST(og1_ == og1); + BOOST_TEST(og1_ != og2); + BOOST_TEST(og1_ != og0); +#endif +} + +void test_assign() +{ +#ifndef BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT +#ifndef BOOST_OPTIONAL_WEAK_OVERLOAD_RESOLUTION + Guard g0, g1(1.0, "one"), g2(2.0, "two"); + + boost::optional og0, og1, og1_, og2; + + og0 = boost::in_place(); + og1 = boost::in_place(1.0, "one"); + og1_ = boost::in_place(1.0, "one"); + og2 = boost::in_place(2.0, "two"); + + BOOST_TEST(og0); + BOOST_TEST(og1); + BOOST_TEST(og1_); + BOOST_TEST(og2); + + BOOST_TEST(*og0 == g0); + BOOST_TEST(*og1 == g1); + BOOST_TEST(*og1_ == g1); + BOOST_TEST(*og2 == g2); + + BOOST_TEST(og1_ == og1); + BOOST_TEST(og1_ != og2); + BOOST_TEST(og1_ != og0); +#endif +#endif +} + +int main() +{ + test_ctor(); + test_assign(); + return boost::report_errors(); +} \ No newline at end of file diff --git a/test/optional_test_minimum_requirements.cpp b/test/optional_test_minimum_requirements.cpp index 5649d69..77ef1fc 100644 --- a/test/optional_test_minimum_requirements.cpp +++ b/test/optional_test_minimum_requirements.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014 Andrzej Krzemienski. +// Copyright (C) 2014-2015 Andrzej Krzemienski. // // Use, modification, and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at @@ -8,19 +8,6 @@ // // You are welcome to contact the author at: // akrzemi1@gmail.com -// -// Revisions: -// -#include -#include -#include - -#define BOOST_ENABLE_ASSERT_HANDLER - -#include "boost/bind/apply.hpp" // Included just to test proper interaction with boost::apply<> as reported by Daniel Wallin -#include "boost/mpl/bool.hpp" -#include "boost/mpl/bool_fwd.hpp" // For mpl::true_ and mpl::false_ -#include "boost/static_assert.hpp" #include "boost/optional/optional.hpp" @@ -28,12 +15,9 @@ #pragma hdrstop #endif +#include "boost/core/lightweight_test.hpp" #include "boost/none.hpp" -#include "boost/test/minimal.hpp" - -#include "optional_test_common.cpp" - class NonConstructible { private: @@ -46,16 +30,10 @@ private: void test_non_constructible() { - optional o; - BOOST_CHECK(!o); - BOOST_CHECK(o == boost::none); - try { - o.value(); - BOOST_CHECK(false); - } - catch(...) { - BOOST_CHECK(true); - } + boost::optional o; + BOOST_TEST(!o); + BOOST_TEST(o == boost::none); + BOOST_TEST_THROWS(o.value(), boost::bad_optional_access); } class Guard @@ -72,33 +50,26 @@ private: void test_guard() { - optional o; + boost::optional o; o.emplace(1); - BOOST_CHECK(o); + BOOST_TEST(o); + BOOST_TEST(o != boost::none); } void test_non_assignable() { - optional o; + boost::optional o; o.emplace("cat"); - BOOST_CHECK(o); - BOOST_CHECK(*o == "cat"); + BOOST_TEST(o); + BOOST_TEST(o != boost::none); + BOOST_TEST_EQ(*o, std::string("cat")); } -int test_main( int, char* [] ) +int main() { - try - { - test_non_constructible(); - test_guard(); - test_non_assignable(); - } - catch ( ... ) - { - BOOST_ERROR("Unexpected Exception caught!"); - } - - return 0; -} - + test_non_constructible(); + test_guard(); + test_non_assignable(); + return boost::report_errors(); +} \ No newline at end of file diff --git a/test/optional_test_tie.cpp b/test/optional_test_tie.cpp index c4fc4ed..f77e74b 100644 --- a/test/optional_test_tie.cpp +++ b/test/optional_test_tie.cpp @@ -1,4 +1,5 @@ // Copyright (C) 2003, Fernando Luis Cacciola Carballal. +// Copyright (C) 2015 Andrzej Krzemienski. // // Use, modification, and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at @@ -8,57 +9,59 @@ // // You are welcome to contact the author at: // fernando_cacciola@hotmail.com -// -#include -#include -#include -#define BOOST_ENABLE_ASSERT_HANDLER - -#include "boost/optional.hpp" -#include "boost/tuple/tuple.hpp" +#include "boost/optional/optional.hpp" #ifdef __BORLANDC__ #pragma hdrstop #endif -#include "boost/test/minimal.hpp" +#include "boost/core/lightweight_test.hpp" +#include "boost/none.hpp" +#include "boost/tuple/tuple.hpp" -#include "optional_test_common.cpp" - -// Test boost::tie() interoperabiliy. -int test_main( int, char* [] ) +struct counting_oracle { - typedef X T ; - - try - { - TRACE( std::endl << BOOST_CURRENT_FUNCTION ); + int val; + counting_oracle() : val() { ++default_ctor_count; } + counting_oracle(int v) : val(v) { ++val_ctor_count; } + counting_oracle(const counting_oracle& rhs) : val(rhs.val) { ++copy_ctor_count; } + counting_oracle& operator=(const counting_oracle& rhs) { val = rhs.val; ++copy_assign_count; return *this; } + ~counting_oracle() { ++dtor_count; } - T z(0); - T a(1); - T b(2); + static int dtor_count; + static int default_ctor_count; + static int val_ctor_count; + static int copy_ctor_count; + static int copy_assign_count; + static int equals_count; - optional oa, ob ; - - // T::T( T const& x ) is used - set_pending_dtor( ARG(T) ) ; - set_pending_copy( ARG(T) ) ; - boost::tie(oa,ob) = std::make_pair(a,b) ; - check_is_not_pending_dtor( ARG(T) ) ; - check_is_not_pending_copy( ARG(T) ) ; - check_initialized(oa); - check_initialized(ob); - check_value(oa,a,z); - check_value(ob,b,z); - - } - catch ( ... ) - { - BOOST_ERROR("Unexpected Exception caught!"); - } + friend bool operator==(const counting_oracle& lhs, const counting_oracle& rhs) { ++equals_count; return lhs.val == rhs.val; } +}; - return 0; +int counting_oracle::dtor_count = 0; +int counting_oracle::default_ctor_count = 0; +int counting_oracle::val_ctor_count = 0; +int counting_oracle::copy_ctor_count = 0; +int counting_oracle::copy_assign_count = 0; +int counting_oracle::equals_count = 0; + +// Test boost::tie() interoperability. +int main() +{ + const std::pair pair(1, 2); + boost::optional o1, o2; + boost::tie(o1, o2) = pair; + + BOOST_TEST(o1); + BOOST_TEST(o2); + BOOST_TEST(*o1 == counting_oracle(1)); + BOOST_TEST(*o2 == counting_oracle(2)); + BOOST_TEST_EQ(2, counting_oracle::copy_ctor_count); + BOOST_TEST_EQ(0, counting_oracle::copy_assign_count); + BOOST_TEST_EQ(0, counting_oracle::default_ctor_count); + + return boost::report_errors(); } From eed1b6ea33bd7e463d31869bac05e68c7efb5867 Mon Sep 17 00:00:00 2001 From: Andrzej Krzemienski Date: Fri, 16 Jan 2015 14:18:44 +0100 Subject: [PATCH 17/23] fixing bug in tests: not accounting for copy elision --- test/optional_test_inplace_fail.cpp | 73 +++++++++++++--------------- test/optional_test_inplace_fail2.cpp | 73 ++++++++++++---------------- test/optional_test_tie.cpp | 15 +++++- 3 files changed, 79 insertions(+), 82 deletions(-) diff --git a/test/optional_test_inplace_fail.cpp b/test/optional_test_inplace_fail.cpp index c6ba1d6..bb7c26f 100644 --- a/test/optional_test_inplace_fail.cpp +++ b/test/optional_test_inplace_fail.cpp @@ -1,4 +1,5 @@ // Copyright (C) 2003, Fernando Luis Cacciola Carballal. +// Copyright (C) 2015 Andrzej Krzemienski. // // Use, modification, and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at @@ -8,53 +9,45 @@ // // You are welcome to contact the author at: // fernando_cacciola@hotmail.com -// -#include -#include + #include - -#define BOOST_ENABLE_ASSERT_HANDLER - #include "boost/optional/optional.hpp" -#ifndef BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT -#include "boost/utility/in_place_factory.hpp" -#endif - #ifdef __BORLANDC__ #pragma hdrstop #endif -#include "boost/test/minimal.hpp" - -#include "optional_test_common.cpp" - #ifndef BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT -struct A -{ - A ( double a0, std::string a1 ) : m_a0(a0), m_a1(a1) {} - - friend bool operator == ( A const& x, A const& y ) - { return x.m_a0 == y.m_a0 && x.m_a1 == y.m_a1 ; } - - double m_a0 ; - std::string m_a1 ; -} ; - -int test_main( int, char* [] ) -{ - int invalid_extra_parameter ; - boost::optional opt2 ( boost::in_place(3.14,"pi",invalid_extra_parameter) ) ; - - return 0; -} -#else -int test_main( int, char* [] ) -{ - int invalid_extra_parameter ; - boost::optional opt2 ( A(3.14,"pi",invalid_extra_parameter) ) ; - - return 0; -} +#include "boost/utility/in_place_factory.hpp" +#include "boost/utility/typed_in_place_factory.hpp" #endif +#include "boost/core/lightweight_test.hpp" +#include "boost/none.hpp" + +struct Guard +{ + double num; + std::string str; + Guard() : num() {} + Guard(double num_, std::string str_) : num(num_), str(str_) {} + + friend bool operator==(const Guard& lhs, const Guard& rhs) { return lhs.num == rhs.num && lhs.str == rhs.str; } + friend bool operator!=(const Guard& lhs, const Guard& rhs) { return !(lhs == rhs); } + +private: + Guard(const Guard&); + Guard& operator=(const Guard&); +}; + + +int main() +{ +#ifndef BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT + int excessive_param = 2; + boost::optional og1 ( boost::in_place(1.0, "one", excessive_param) ); +#else + NOTHING_TO_TEST_SO_JUST_FAIL +#endif + return 0; +} \ No newline at end of file diff --git a/test/optional_test_inplace_fail2.cpp b/test/optional_test_inplace_fail2.cpp index f82d857..e6a0004 100644 --- a/test/optional_test_inplace_fail2.cpp +++ b/test/optional_test_inplace_fail2.cpp @@ -1,4 +1,5 @@ // Copyright (C) 2003, Fernando Luis Cacciola Carballal. +// Copyright (C) 2015 Andrzej Krzemienski. // // Use, modification, and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at @@ -8,55 +9,45 @@ // // You are welcome to contact the author at: // fernando_cacciola@hotmail.com -// -#include -#include + #include - -#define BOOST_ENABLE_ASSERT_HANDLER - #include "boost/optional/optional.hpp" -#ifndef BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT -#include "boost/utility/typed_in_place_factory.hpp" -#endif - #ifdef __BORLANDC__ #pragma hdrstop #endif -#include "boost/test/minimal.hpp" - -#include "optional_test_common.cpp" - #ifndef BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT -struct A -{ - A ( double a0, std::string a1 ) : m_a0(a0), m_a1(a1) {} - - friend bool operator == ( A const& x, A const& y ) - { return x.m_a0 == y.m_a0 && x.m_a1 == y.m_a1 ; } - - double m_a0 ; - std::string m_a1 ; -} ; - -int test_main( int, char* [] ) -{ - // This must fail to compile. - // The first template argument to in_place<> is the target-type, - // not the first constructor parameter type. - boost::optional opt2 ( boost::in_place(3.14,"pi") ) ; - - return 0; -} -#else -int test_main( int, char* [] ) -{ - boost::optional opt2 ( int(3.14) ) ; - - return 0; -} +#include "boost/utility/in_place_factory.hpp" +#include "boost/utility/typed_in_place_factory.hpp" #endif +#include "boost/core/lightweight_test.hpp" +#include "boost/none.hpp" +struct Guard +{ + double num; + std::string str; + Guard() : num() {} + Guard(double num_, std::string str_) : num(num_), str(str_) {} + + friend bool operator==(const Guard& lhs, const Guard& rhs) { return lhs.num == rhs.num && lhs.str == rhs.str; } + friend bool operator!=(const Guard& lhs, const Guard& rhs) { return !(lhs == rhs); } + +private: + Guard(const Guard&); + Guard& operator=(const Guard&); +}; + + +int main() +{ +#ifndef BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT + typedef int BAD_TARGET_TYPE; + boost::optional og1 ( boost::in_place(1.0, "one") ); +#else + NOTHING_TO_TEST_SO_JUST_FAIL +#endif + return 0; +} \ No newline at end of file diff --git a/test/optional_test_tie.cpp b/test/optional_test_tie.cpp index f77e74b..0b49bfa 100644 --- a/test/optional_test_tie.cpp +++ b/test/optional_test_tie.cpp @@ -46,9 +46,22 @@ int counting_oracle::copy_ctor_count = 0; int counting_oracle::copy_assign_count = 0; int counting_oracle::equals_count = 0; +int count_copy_ctors_on_copy() // checks if we have copy elision +{ + counting_oracle::copy_ctor_count = 0; + + counting_oracle c(1); + counting_oracle c2(c); + int ans = counting_oracle::copy_ctor_count; + counting_oracle::copy_ctor_count = 0; + counting_oracle::val_ctor_count = 0; + return ans; +} + // Test boost::tie() interoperability. int main() { + int copy_factor = count_copy_ctors_on_copy(); const std::pair pair(1, 2); boost::optional o1, o2; boost::tie(o1, o2) = pair; @@ -57,7 +70,7 @@ int main() BOOST_TEST(o2); BOOST_TEST(*o1 == counting_oracle(1)); BOOST_TEST(*o2 == counting_oracle(2)); - BOOST_TEST_EQ(2, counting_oracle::copy_ctor_count); + BOOST_TEST_EQ(2 * copy_factor, counting_oracle::copy_ctor_count); BOOST_TEST_EQ(0, counting_oracle::copy_assign_count); BOOST_TEST_EQ(0, counting_oracle::default_ctor_count); From 2437f9cb4c2d9ac1c4c0077f40418a90bde62b2c Mon Sep 17 00:00:00 2001 From: Andrzej Krzemienski Date: Fri, 16 Jan 2015 19:16:12 +0100 Subject: [PATCH 18/23] testing swap() in a separate file --- test/Jamfile.v2 | 1 + test/optional_test.cpp | 332 ------------------------------- test/optional_test_swap.cpp | 376 ++++++++++++++++++++++++++++++++++++ 3 files changed, 377 insertions(+), 332 deletions(-) create mode 100644 test/optional_test_swap.cpp diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 63045c5..4876b41 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -17,6 +17,7 @@ import testing ; { test-suite optional : [ run optional_test.cpp ] + [ run optional_test_swap.cpp ] [ run optional_test_conversions_from_U.cpp ] [ run optional_test_tie.cpp ] [ run optional_test_ref_assign_portable_minimum.cpp ] diff --git a/test/optional_test.cpp b/test/optional_test.cpp index 1247965..3591867 100644 --- a/test/optional_test.cpp +++ b/test/optional_test.cpp @@ -907,337 +907,6 @@ void test_no_implicit_conversions() } - -namespace optional_swap_test -{ - class default_ctor_exception : public std::exception {} ; - class copy_ctor_exception : public std::exception {} ; - class assignment_exception : public std::exception {} ; - - // - // Base class for swap test classes. Its assignment should not be called, when swapping - // optional objects. (The default std::swap would do so.) - // - class base_class_with_forbidden_assignment - { - public: - base_class_with_forbidden_assignment & operator=(const base_class_with_forbidden_assignment &) - { - BOOST_CHECK(!"The assignment should not be used while swapping!"); - throw assignment_exception(); - } - - virtual ~base_class_with_forbidden_assignment() {} - }; - - // - // Class without default constructor - // - class class_without_default_ctor : public base_class_with_forbidden_assignment - { - public: - char data; - explicit class_without_default_ctor(char arg) : data(arg) {} - }; - - // - // Class whose default constructor should not be used by optional::swap! - // - class class_whose_default_ctor_should_not_be_used : public base_class_with_forbidden_assignment - { - public: - char data; - explicit class_whose_default_ctor_should_not_be_used(char arg) : data(arg) {} - - class_whose_default_ctor_should_not_be_used() - { - BOOST_CHECK(!"This default constructor should not be used while swapping!"); - throw default_ctor_exception(); - } - }; - - // - // Class whose default constructor should be used by optional::swap. - // Its copy constructor should be avoided! - // - class class_whose_default_ctor_should_be_used : public base_class_with_forbidden_assignment - { - public: - char data; - explicit class_whose_default_ctor_should_be_used(char arg) : data(arg) { } - - class_whose_default_ctor_should_be_used() : data('\0') { } - - class_whose_default_ctor_should_be_used(const class_whose_default_ctor_should_be_used &) - { - BOOST_CHECK(!"This copy constructor should not be used while swapping!"); - throw copy_ctor_exception(); - } - }; - - // - // Class template whose default constructor should be used by optional::swap. - // Its copy constructor should be avoided! - // - template - class template_whose_default_ctor_should_be_used : public base_class_with_forbidden_assignment - { - public: - T data; - explicit template_whose_default_ctor_should_be_used(T arg) : data(arg) { } - - template_whose_default_ctor_should_be_used() : data('\0') { } - - template_whose_default_ctor_should_be_used(const template_whose_default_ctor_should_be_used &) - { - BOOST_CHECK(!"This copy constructor should not be used while swapping!"); - throw copy_ctor_exception(); - } - }; - - // - // Class whose explicit constructor should be used by optional::swap. - // Its other constructors should be avoided! - // - class class_whose_explicit_ctor_should_be_used : public base_class_with_forbidden_assignment - { - public: - char data; - explicit class_whose_explicit_ctor_should_be_used(char arg) : data(arg) { } - - class_whose_explicit_ctor_should_be_used() - { - BOOST_CHECK(!"This default constructor should not be used while swapping!"); - throw default_ctor_exception(); - } - - class_whose_explicit_ctor_should_be_used(const class_whose_explicit_ctor_should_be_used &) - { - BOOST_CHECK(!"This copy constructor should not be used while swapping!"); - throw copy_ctor_exception(); - } - }; - - void swap(class_whose_default_ctor_should_not_be_used & lhs, class_whose_default_ctor_should_not_be_used & rhs) - { - std::swap(lhs.data, rhs.data); - } - - void swap(class_whose_default_ctor_should_be_used & lhs, class_whose_default_ctor_should_be_used & rhs) - { - std::swap(lhs.data, rhs.data); - } - - void swap(class_without_default_ctor & lhs, class_without_default_ctor & rhs) - { - std::swap(lhs.data, rhs.data); - } - - void swap(class_whose_explicit_ctor_should_be_used & lhs, class_whose_explicit_ctor_should_be_used & rhs) - { - std::swap(lhs.data, rhs.data); - } - - template - void swap(template_whose_default_ctor_should_be_used & lhs, template_whose_default_ctor_should_be_used & rhs) - { - std::swap(lhs.data, rhs.data); - } - - // - // optional::swap should be customized when neither the copy constructor - // nor the default constructor of T are supposed to be used when swapping, e.g., - // for the following type T = class_whose_explicit_ctor_should_be_used. - // - void swap(boost::optional & x, boost::optional & y) - { - bool hasX(x); - bool hasY(y); - - if ( !hasX && !hasY ) - return; - - if( !hasX ) - x = boost::in_place('\0'); - else if ( !hasY ) - y = boost::in_place('\0'); - - optional_swap_test::swap(*x,*y); - - if( !hasX ) - y = boost::none ; - else if( !hasY ) - x = boost::none ; - } - - -} // End of namespace optional_swap_test. - - -namespace boost { - -// -// Compile time tweaking on whether or not swap should use the default constructor: -// - -template <> struct optional_swap_should_use_default_constructor< - optional_swap_test::class_whose_default_ctor_should_be_used> : mpl::true_ {} ; - -template <> struct optional_swap_should_use_default_constructor< - optional_swap_test::class_whose_default_ctor_should_not_be_used> : mpl::false_ {} ; - -template struct optional_swap_should_use_default_constructor< - optional_swap_test::template_whose_default_ctor_should_be_used > : mpl::true_ {} ; - - -// -// Specialization of boost::swap: -// -template <> -void swap(optional & x, optional & y) -{ - optional_swap_test::swap(x, y); -} - -} // namespace boost - - -namespace std { - -// -// Specializations of std::swap: -// - -template <> -void swap(optional_swap_test::class_whose_default_ctor_should_be_used & x, optional_swap_test::class_whose_default_ctor_should_be_used & y) -{ - optional_swap_test::swap(x, y); -} - -template <> -void swap(optional_swap_test::class_whose_default_ctor_should_not_be_used & x, optional_swap_test::class_whose_default_ctor_should_not_be_used & y) -{ - optional_swap_test::swap(x, y); -} - -template <> -void swap(optional_swap_test::class_without_default_ctor & x, optional_swap_test::class_without_default_ctor & y) -{ - optional_swap_test::swap(x, y); -} - -template <> -void swap(optional_swap_test::class_whose_explicit_ctor_should_be_used & x, optional_swap_test::class_whose_explicit_ctor_should_be_used & y) -{ - optional_swap_test::swap(x, y); -} - -} // namespace std - - -// -// Tests whether the swap function works properly for optional. -// Assumes that T has one data member, of type char. -// Returns true iff the test is passed. -// -template -bool test_swap_function( T const* ) -{ - const boost::unit_test::counter_t counter_before_test = boost::minimal_test::errors_counter(); - try - { - optional obj1; - optional obj2('a'); - - // Self-swap should not have any effect. - swap(obj1, obj1); - swap(obj2, obj2); - BOOST_CHECK(!obj1); - BOOST_CHECK(!!obj2 && obj2->data == 'a'); - - // Call non-member swap. - swap(obj1, obj2); - - // Test if obj1 and obj2 are really swapped. - BOOST_CHECK(!!obj1 && obj1->data == 'a'); - BOOST_CHECK(!obj2); - - // Call non-member swap one more time. - swap(obj1, obj2); - - // Test if obj1 and obj2 are swapped back. - BOOST_CHECK(!obj1); - BOOST_CHECK(!!obj2 && obj2->data == 'a'); - } - catch(const std::exception &) - { - // The swap function should not throw, for our test cases. - return false ; - } - return boost::minimal_test::errors_counter() == counter_before_test ; -} - -// -// Tests whether the optional::swap member function works properly. -// Assumes that T has one data member, of type char. -// Returns true iff the test is passed. -// -template -bool test_swap_member_function( T const* ) -{ - const boost::unit_test::counter_t counter_before_test = boost::minimal_test::errors_counter(); - try - { - optional obj1; - optional obj2('a'); - - // Self-swap should not have any effect. - obj1.swap(obj1); - obj2.swap(obj2); - BOOST_CHECK(!obj1); - BOOST_CHECK(!!obj2 && obj2->data == 'a'); - - // Call member swap. - obj1.swap(obj2); - - // Test if obj1 and obj2 are really swapped. - BOOST_CHECK(!!obj1 && obj1->data == 'a'); - BOOST_CHECK(!obj2); - - // Call member swap one more time. - obj1.swap(obj2); - - // Test if obj1 and obj2 are swapped back. - BOOST_CHECK(!obj1); - BOOST_CHECK(!!obj2 && obj2->data == 'a'); - } - catch(const std::exception &) - { - // The optional::swap member function should not throw, for our test cases. - return false ; - } - return boost::minimal_test::errors_counter() == counter_before_test ; -} - - -// -// Tests compile time tweaking of swap, by means of -// optional_swap_should_use_default_constructor. -// -void test_swap_tweaking() -{ - BOOST_CHECK( test_swap_function( ARG(optional_swap_test::class_without_default_ctor) ) ); - BOOST_CHECK( test_swap_function( ARG(optional_swap_test::class_whose_default_ctor_should_be_used) ) ); - BOOST_CHECK( test_swap_function( ARG(optional_swap_test::class_whose_default_ctor_should_not_be_used) ) ); - BOOST_CHECK( test_swap_function( ARG(optional_swap_test::class_whose_explicit_ctor_should_be_used) ) ); - BOOST_CHECK( test_swap_function( ARG(optional_swap_test::template_whose_default_ctor_should_be_used) ) ); - BOOST_CHECK( test_swap_member_function( ARG(optional_swap_test::class_without_default_ctor) ) ); - BOOST_CHECK( test_swap_member_function( ARG(optional_swap_test::class_whose_default_ctor_should_be_used) ) ); - BOOST_CHECK( test_swap_member_function( ARG(optional_swap_test::class_whose_default_ctor_should_not_be_used) ) ); - BOOST_CHECK( test_swap_member_function( ARG(optional_swap_test::class_whose_explicit_ctor_should_be_used) ) ); - BOOST_CHECK( test_swap_member_function( ARG(optional_swap_test::template_whose_default_ctor_should_be_used) ) ); -} - // Test for support for classes with overridden operator& class CustomAddressOfClass { @@ -1272,7 +941,6 @@ int test_main( int, char* [] ) test_with_class_type(); test_with_builtin_types(); test_no_implicit_conversions(); - test_swap_tweaking(); test_custom_addressof_operator(); } catch ( ... ) diff --git a/test/optional_test_swap.cpp b/test/optional_test_swap.cpp new file mode 100644 index 0000000..53eebc2 --- /dev/null +++ b/test/optional_test_swap.cpp @@ -0,0 +1,376 @@ +// Copyright (C) 2003, 2008 Fernando Luis Cacciola Carballal. +// +// Use, modification, and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/lib/optional for documentation. +// +// You are welcome to contact the author at: +// fernando_cacciola@hotmail.com +// +// Revisions: +// 12 May 2008 (added more swap tests) +// +#include +#include +#include + +#define BOOST_ENABLE_ASSERT_HANDLER + +#include "boost/bind/apply.hpp" // Included just to test proper interaction with boost::apply<> as reported by Daniel Wallin +#include "boost/mpl/bool.hpp" +#include "boost/mpl/bool_fwd.hpp" // For mpl::true_ and mpl::false_ + +#include "boost/optional/optional.hpp" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#include "boost/none.hpp" + +#include "boost/test/minimal.hpp" + +#include "optional_test_common.cpp" + + + +namespace optional_swap_test +{ + class default_ctor_exception : public std::exception {} ; + class copy_ctor_exception : public std::exception {} ; + class assignment_exception : public std::exception {} ; + + // + // Base class for swap test classes. Its assignment should not be called, when swapping + // optional objects. (The default std::swap would do so.) + // + class base_class_with_forbidden_assignment + { + public: + base_class_with_forbidden_assignment & operator=(const base_class_with_forbidden_assignment &) + { + BOOST_CHECK(!"The assignment should not be used while swapping!"); + throw assignment_exception(); + } + + virtual ~base_class_with_forbidden_assignment() {} + }; + + // + // Class without default constructor + // + class class_without_default_ctor : public base_class_with_forbidden_assignment + { + public: + char data; + explicit class_without_default_ctor(char arg) : data(arg) {} + }; + + // + // Class whose default constructor should not be used by optional::swap! + // + class class_whose_default_ctor_should_not_be_used : public base_class_with_forbidden_assignment + { + public: + char data; + explicit class_whose_default_ctor_should_not_be_used(char arg) : data(arg) {} + + class_whose_default_ctor_should_not_be_used() + { + BOOST_CHECK(!"This default constructor should not be used while swapping!"); + throw default_ctor_exception(); + } + }; + + // + // Class whose default constructor should be used by optional::swap. + // Its copy constructor should be avoided! + // + class class_whose_default_ctor_should_be_used : public base_class_with_forbidden_assignment + { + public: + char data; + explicit class_whose_default_ctor_should_be_used(char arg) : data(arg) { } + + class_whose_default_ctor_should_be_used() : data('\0') { } + + class_whose_default_ctor_should_be_used(const class_whose_default_ctor_should_be_used &) + { + BOOST_CHECK(!"This copy constructor should not be used while swapping!"); + throw copy_ctor_exception(); + } + }; + + // + // Class template whose default constructor should be used by optional::swap. + // Its copy constructor should be avoided! + // + template + class template_whose_default_ctor_should_be_used : public base_class_with_forbidden_assignment + { + public: + T data; + explicit template_whose_default_ctor_should_be_used(T arg) : data(arg) { } + + template_whose_default_ctor_should_be_used() : data('\0') { } + + template_whose_default_ctor_should_be_used(const template_whose_default_ctor_should_be_used &) + { + BOOST_CHECK(!"This copy constructor should not be used while swapping!"); + throw copy_ctor_exception(); + } + }; + + // + // Class whose explicit constructor should be used by optional::swap. + // Its other constructors should be avoided! + // + class class_whose_explicit_ctor_should_be_used : public base_class_with_forbidden_assignment + { + public: + char data; + explicit class_whose_explicit_ctor_should_be_used(char arg) : data(arg) { } + + class_whose_explicit_ctor_should_be_used() + { + BOOST_CHECK(!"This default constructor should not be used while swapping!"); + throw default_ctor_exception(); + } + + class_whose_explicit_ctor_should_be_used(const class_whose_explicit_ctor_should_be_used &) + { + BOOST_CHECK(!"This copy constructor should not be used while swapping!"); + throw copy_ctor_exception(); + } + }; + + void swap(class_whose_default_ctor_should_not_be_used & lhs, class_whose_default_ctor_should_not_be_used & rhs) + { + std::swap(lhs.data, rhs.data); + } + + void swap(class_whose_default_ctor_should_be_used & lhs, class_whose_default_ctor_should_be_used & rhs) + { + std::swap(lhs.data, rhs.data); + } + + void swap(class_without_default_ctor & lhs, class_without_default_ctor & rhs) + { + std::swap(lhs.data, rhs.data); + } + + void swap(class_whose_explicit_ctor_should_be_used & lhs, class_whose_explicit_ctor_should_be_used & rhs) + { + std::swap(lhs.data, rhs.data); + } + + template + void swap(template_whose_default_ctor_should_be_used & lhs, template_whose_default_ctor_should_be_used & rhs) + { + std::swap(lhs.data, rhs.data); + } + + // + // optional::swap should be customized when neither the copy constructor + // nor the default constructor of T are supposed to be used when swapping, e.g., + // for the following type T = class_whose_explicit_ctor_should_be_used. + // + void swap(boost::optional & x, boost::optional & y) + { + bool hasX(x); + bool hasY(y); + + if ( !hasX && !hasY ) + return; + + if( !hasX ) + x = boost::in_place('\0'); + else if ( !hasY ) + y = boost::in_place('\0'); + + optional_swap_test::swap(*x,*y); + + if( !hasX ) + y = boost::none ; + else if( !hasY ) + x = boost::none ; + } + + +} // End of namespace optional_swap_test. + + +namespace boost { + +// +// Compile time tweaking on whether or not swap should use the default constructor: +// + +template <> struct optional_swap_should_use_default_constructor< + optional_swap_test::class_whose_default_ctor_should_be_used> : mpl::true_ {} ; + +template <> struct optional_swap_should_use_default_constructor< + optional_swap_test::class_whose_default_ctor_should_not_be_used> : mpl::false_ {} ; + +template struct optional_swap_should_use_default_constructor< + optional_swap_test::template_whose_default_ctor_should_be_used > : mpl::true_ {} ; + + +// +// Specialization of boost::swap: +// +template <> +void swap(optional & x, optional & y) +{ + optional_swap_test::swap(x, y); +} + +} // namespace boost + + +namespace std { + +// +// Specializations of std::swap: +// + +template <> +void swap(optional_swap_test::class_whose_default_ctor_should_be_used & x, optional_swap_test::class_whose_default_ctor_should_be_used & y) +{ + optional_swap_test::swap(x, y); +} + +template <> +void swap(optional_swap_test::class_whose_default_ctor_should_not_be_used & x, optional_swap_test::class_whose_default_ctor_should_not_be_used & y) +{ + optional_swap_test::swap(x, y); +} + +template <> +void swap(optional_swap_test::class_without_default_ctor & x, optional_swap_test::class_without_default_ctor & y) +{ + optional_swap_test::swap(x, y); +} + +template <> +void swap(optional_swap_test::class_whose_explicit_ctor_should_be_used & x, optional_swap_test::class_whose_explicit_ctor_should_be_used & y) +{ + optional_swap_test::swap(x, y); +} + +} // namespace std + + +// +// Tests whether the swap function works properly for optional. +// Assumes that T has one data member, of type char. +// Returns true iff the test is passed. +// +template +void test_swap_function( T const* ) +{ + try + { + optional obj1; + optional obj2('a'); + + // Self-swap should not have any effect. + swap(obj1, obj1); + swap(obj2, obj2); + BOOST_CHECK(!obj1); + BOOST_CHECK(!!obj2 && obj2->data == 'a'); + + // Call non-member swap. + swap(obj1, obj2); + + // Test if obj1 and obj2 are really swapped. + BOOST_CHECK(!!obj1 && obj1->data == 'a'); + BOOST_CHECK(!obj2); + + // Call non-member swap one more time. + swap(obj1, obj2); + + // Test if obj1 and obj2 are swapped back. + BOOST_CHECK(!obj1); + BOOST_CHECK(!!obj2 && obj2->data == 'a'); + } + catch(const std::exception &) + { + // The swap function should not throw, for our test cases. + BOOST_CHECK(!"throw in swap"); + } +} + +// +// Tests whether the optional::swap member function works properly. +// Assumes that T has one data member, of type char. +// Returns true iff the test is passed. +// +template +void test_swap_member_function( T const* ) +{ + try + { + optional obj1; + optional obj2('a'); + + // Self-swap should not have any effect. + obj1.swap(obj1); + obj2.swap(obj2); + BOOST_CHECK(!obj1); + BOOST_CHECK(!!obj2 && obj2->data == 'a'); + + // Call member swap. + obj1.swap(obj2); + + // Test if obj1 and obj2 are really swapped. + BOOST_CHECK(!!obj1 && obj1->data == 'a'); + BOOST_CHECK(!obj2); + + // Call member swap one more time. + obj1.swap(obj2); + + // Test if obj1 and obj2 are swapped back. + BOOST_CHECK(!obj1); + BOOST_CHECK(!!obj2 && obj2->data == 'a'); + } + catch(const std::exception &) + { + BOOST_CHECK(!"throw in swap"); + } +} + + +// +// Tests compile time tweaking of swap, by means of +// optional_swap_should_use_default_constructor. +// +void test_swap_tweaking() +{ + ( test_swap_function( ARG(optional_swap_test::class_without_default_ctor) ) ); + ( test_swap_function( ARG(optional_swap_test::class_whose_default_ctor_should_be_used) ) ); + ( test_swap_function( ARG(optional_swap_test::class_whose_default_ctor_should_not_be_used) ) ); + ( test_swap_function( ARG(optional_swap_test::class_whose_explicit_ctor_should_be_used) ) ); + ( test_swap_function( ARG(optional_swap_test::template_whose_default_ctor_should_be_used) ) ); + ( test_swap_member_function( ARG(optional_swap_test::class_without_default_ctor) ) ); + ( test_swap_member_function( ARG(optional_swap_test::class_whose_default_ctor_should_be_used) ) ); + ( test_swap_member_function( ARG(optional_swap_test::class_whose_default_ctor_should_not_be_used) ) ); + ( test_swap_member_function( ARG(optional_swap_test::class_whose_explicit_ctor_should_be_used) ) ); + ( test_swap_member_function( ARG(optional_swap_test::template_whose_default_ctor_should_be_used) ) ); +} + +int test_main( int, char* [] ) +{ + try + { + test_swap_tweaking(); + } + catch ( ... ) + { + BOOST_ERROR("Unexpected Exception caught!"); + } + + return 0; +} From c12beb89918e550425044abc14ad69c5c8cd4752 Mon Sep 17 00:00:00 2001 From: Andrzej Krzemienski Date: Fri, 16 Jan 2015 22:19:00 +0100 Subject: [PATCH 19/23] test cleanup --- test/optional_test_swap.cpp | 74 ++++++++----------- test/optional_test_the_compiler.cpp | 108 ---------------------------- 2 files changed, 29 insertions(+), 153 deletions(-) delete mode 100644 test/optional_test_the_compiler.cpp diff --git a/test/optional_test_swap.cpp b/test/optional_test_swap.cpp index 53eebc2..b6802b1 100644 --- a/test/optional_test_swap.cpp +++ b/test/optional_test_swap.cpp @@ -1,4 +1,5 @@ // Copyright (C) 2003, 2008 Fernando Luis Cacciola Carballal. +// Copyright (C) 2015 Andrzej Krzemienski. // // Use, modification, and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at @@ -12,15 +13,6 @@ // Revisions: // 12 May 2008 (added more swap tests) // -#include -#include -#include - -#define BOOST_ENABLE_ASSERT_HANDLER - -#include "boost/bind/apply.hpp" // Included just to test proper interaction with boost::apply<> as reported by Daniel Wallin -#include "boost/mpl/bool.hpp" -#include "boost/mpl/bool_fwd.hpp" // For mpl::true_ and mpl::false_ #include "boost/optional/optional.hpp" @@ -28,13 +20,13 @@ #pragma hdrstop #endif -#include "boost/none.hpp" - -#include "boost/test/minimal.hpp" - -#include "optional_test_common.cpp" +#include "boost/core/lightweight_test.hpp" +using boost::optional; +using boost::none; + +#define ARG(T) (static_cast< T const* >(0)) namespace optional_swap_test { @@ -51,7 +43,7 @@ namespace optional_swap_test public: base_class_with_forbidden_assignment & operator=(const base_class_with_forbidden_assignment &) { - BOOST_CHECK(!"The assignment should not be used while swapping!"); + BOOST_TEST(!"The assignment should not be used while swapping!"); throw assignment_exception(); } @@ -79,7 +71,7 @@ namespace optional_swap_test class_whose_default_ctor_should_not_be_used() { - BOOST_CHECK(!"This default constructor should not be used while swapping!"); + BOOST_TEST(!"This default constructor should not be used while swapping!"); throw default_ctor_exception(); } }; @@ -98,7 +90,7 @@ namespace optional_swap_test class_whose_default_ctor_should_be_used(const class_whose_default_ctor_should_be_used &) { - BOOST_CHECK(!"This copy constructor should not be used while swapping!"); + BOOST_TEST(!"This copy constructor should not be used while swapping!"); throw copy_ctor_exception(); } }; @@ -118,7 +110,7 @@ namespace optional_swap_test template_whose_default_ctor_should_be_used(const template_whose_default_ctor_should_be_used &) { - BOOST_CHECK(!"This copy constructor should not be used while swapping!"); + BOOST_TEST(!"This copy constructor should not be used while swapping!"); throw copy_ctor_exception(); } }; @@ -135,13 +127,13 @@ namespace optional_swap_test class_whose_explicit_ctor_should_be_used() { - BOOST_CHECK(!"This default constructor should not be used while swapping!"); + BOOST_TEST(!"This default constructor should not be used while swapping!"); throw default_ctor_exception(); } class_whose_explicit_ctor_should_be_used(const class_whose_explicit_ctor_should_be_used &) { - BOOST_CHECK(!"This copy constructor should not be used while swapping!"); + BOOST_TEST(!"This copy constructor should not be used while swapping!"); throw copy_ctor_exception(); } }; @@ -279,27 +271,27 @@ void test_swap_function( T const* ) // Self-swap should not have any effect. swap(obj1, obj1); swap(obj2, obj2); - BOOST_CHECK(!obj1); - BOOST_CHECK(!!obj2 && obj2->data == 'a'); + BOOST_TEST(!obj1); + BOOST_TEST(!!obj2 && obj2->data == 'a'); // Call non-member swap. swap(obj1, obj2); // Test if obj1 and obj2 are really swapped. - BOOST_CHECK(!!obj1 && obj1->data == 'a'); - BOOST_CHECK(!obj2); + BOOST_TEST(!!obj1 && obj1->data == 'a'); + BOOST_TEST(!obj2); // Call non-member swap one more time. swap(obj1, obj2); // Test if obj1 and obj2 are swapped back. - BOOST_CHECK(!obj1); - BOOST_CHECK(!!obj2 && obj2->data == 'a'); + BOOST_TEST(!obj1); + BOOST_TEST(!!obj2 && obj2->data == 'a'); } catch(const std::exception &) { // The swap function should not throw, for our test cases. - BOOST_CHECK(!"throw in swap"); + BOOST_TEST(!"throw in swap"); } } @@ -319,26 +311,26 @@ void test_swap_member_function( T const* ) // Self-swap should not have any effect. obj1.swap(obj1); obj2.swap(obj2); - BOOST_CHECK(!obj1); - BOOST_CHECK(!!obj2 && obj2->data == 'a'); + BOOST_TEST(!obj1); + BOOST_TEST(!!obj2 && obj2->data == 'a'); // Call member swap. obj1.swap(obj2); // Test if obj1 and obj2 are really swapped. - BOOST_CHECK(!!obj1 && obj1->data == 'a'); - BOOST_CHECK(!obj2); + BOOST_TEST(!!obj1 && obj1->data == 'a'); + BOOST_TEST(!obj2); // Call member swap one more time. obj1.swap(obj2); // Test if obj1 and obj2 are swapped back. - BOOST_CHECK(!obj1); - BOOST_CHECK(!!obj2 && obj2->data == 'a'); + BOOST_TEST(!obj1); + BOOST_TEST(!!obj2 && obj2->data == 'a'); } catch(const std::exception &) { - BOOST_CHECK(!"throw in swap"); + BOOST_TEST(!"throw in swap"); } } @@ -361,16 +353,8 @@ void test_swap_tweaking() ( test_swap_member_function( ARG(optional_swap_test::template_whose_default_ctor_should_be_used) ) ); } -int test_main( int, char* [] ) +int main() { - try - { - test_swap_tweaking(); - } - catch ( ... ) - { - BOOST_ERROR("Unexpected Exception caught!"); - } - - return 0; + test_swap_tweaking(); + return boost::report_errors(); } diff --git a/test/optional_test_the_compiler.cpp b/test/optional_test_the_compiler.cpp deleted file mode 100644 index dea10cb..0000000 --- a/test/optional_test_the_compiler.cpp +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright (C) 2014 Andrzej Krzemienski. -// -// Use, modification, and distribution is subject to the Boost Software -// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -// -// See http://www.boost.org/lib/optional for documentation. -// -// You are welcome to contact the author at: -// akrzemi1@gmail.com -// -// Revisions: -// -#include -#include -//#include - -#define BOOST_ENABLE_ASSERT_HANDLER - -//#include "boost/bind/apply.hpp" // Included just to test proper interaction with boost::apply<> as reported by Daniel Wallin -#include "boost/mpl/bool.hpp" -#include "boost/mpl/bool_fwd.hpp" // For mpl::true_ and mpl::false_ -#include "boost/static_assert.hpp" - -#include "boost/optional/optional.hpp" - -#ifdef __BORLANDC__ -#pragma hdrstop -#endif - -#include "boost/test/minimal.hpp" -#include "optional_test_common.cpp" - - -const int global_i = 0; - -class TestingReferenceBinding -{ -public: - TestingReferenceBinding(const int& ii) - { - BOOST_CHECK(&ii == &global_i); - } - - void operator=(const int& ii) - { - BOOST_CHECK(&ii == &global_i); - } - #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES - void operator=(int&&) - { - BOOST_CHECK(false); - } - #endif -}; - -class TestingReferenceBinding2 // same definition as above, I need a different type -{ -public: - TestingReferenceBinding2(const int& ii) - { - BOOST_CHECK(&ii == &global_i); - } - - void operator=(const int& ii) - { - BOOST_CHECK(&ii == &global_i); - } - #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES - void operator=(int&&) - { - BOOST_CHECK(false); - } - #endif -}; - - -void test_broken_compiler() -{ -// we are not testing boost::optional here, but the c++ compiler -// if this test fails, optional references will obviously fail too - - const int& iref = global_i; - BOOST_CHECK(&iref == &global_i); - - TestingReferenceBinding ttt = global_i; - ttt = global_i; - - TestingReferenceBinding2 ttt2 = iref; - ttt2 = iref; -} - - -int test_main( int, char* [] ) -{ - try - { - test_broken_compiler(); - } - catch ( ... ) - { - BOOST_ERROR("Unexpected Exception caught!"); - } - - return 0; -} - - From cc1710307047a4dd6223f5342177d932435a7f97 Mon Sep 17 00:00:00 2001 From: Andrzej Krzemienski Date: Sat, 17 Jan 2015 09:21:36 +0100 Subject: [PATCH 20/23] tie tests still buggy --- test/optional_test_tie.cpp | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/test/optional_test_tie.cpp b/test/optional_test_tie.cpp index 0b49bfa..b5c5818 100644 --- a/test/optional_test_tie.cpp +++ b/test/optional_test_tie.cpp @@ -37,6 +37,11 @@ struct counting_oracle static int equals_count; friend bool operator==(const counting_oracle& lhs, const counting_oracle& rhs) { ++equals_count; return lhs.val == rhs.val; } + + static void clear_count() + { + dtor_count = default_ctor_count = val_ctor_count = copy_ctor_count = copy_assign_count = equals_count = 0; + } }; int counting_oracle::dtor_count = 0; @@ -46,23 +51,12 @@ int counting_oracle::copy_ctor_count = 0; int counting_oracle::copy_assign_count = 0; int counting_oracle::equals_count = 0; -int count_copy_ctors_on_copy() // checks if we have copy elision -{ - counting_oracle::copy_ctor_count = 0; - - counting_oracle c(1); - counting_oracle c2(c); - int ans = counting_oracle::copy_ctor_count; - counting_oracle::copy_ctor_count = 0; - counting_oracle::val_ctor_count = 0; - return ans; -} - // Test boost::tie() interoperability. int main() -{ - int copy_factor = count_copy_ctors_on_copy(); +{ const std::pair pair(1, 2); + counting_oracle::clear_count(); + boost::optional o1, o2; boost::tie(o1, o2) = pair; @@ -70,7 +64,7 @@ int main() BOOST_TEST(o2); BOOST_TEST(*o1 == counting_oracle(1)); BOOST_TEST(*o2 == counting_oracle(2)); - BOOST_TEST_EQ(2 * copy_factor, counting_oracle::copy_ctor_count); + BOOST_TEST_EQ(2, counting_oracle::copy_ctor_count); BOOST_TEST_EQ(0, counting_oracle::copy_assign_count); BOOST_TEST_EQ(0, counting_oracle::default_ctor_count); From 726b227aa95848d8de9d8f0e0b2d0554d1101e41 Mon Sep 17 00:00:00 2001 From: Andrzej Krzemienski Date: Wed, 21 Jan 2015 00:10:51 +0100 Subject: [PATCH 21/23] operator<< improvements --- doc/00_optional.qbk | 15 ++-- doc/14_io.qbk | 37 ++++++++ ...erences.qbk => 15_optional_references.qbk} | 0 ...actories.qbk => 16_in_place_factories.qbk} | 0 ...optional_bool.qbk => 17_optional_bool.qbk} | 0 ...ion_safety.qbk => 18_exception_safety.qbk} | 0 ...uirements.qbk => 19_type_requirements.qbk} | 0 ..._performance.qbk => 1A_on_performance.qbk} | 0 doc/91_relnotes.qbk | 2 + doc/html/boost_optional/acknowledgements.html | 2 +- .../dependencies_and_portability.html | 2 +- .../optional_reference_binding.html | 2 +- doc/html/boost_optional/quick_start.html | 2 +- ...sing_unnecessary_default_construction.html | 2 +- .../optional_automatic_variables.html | 2 +- .../quick_start/optional_data_members.html | 2 +- .../quick_start/storage_in_containers.html | 2 +- .../reference/detailed_semantics.html | 2 +- doc/html/boost_optional/relnotes.html | 17 +++- .../tutorial/a_note_about_optional_bool_.html | 2 +- .../tutorial/design_overview.html | 2 +- .../design_overview/the_interface.html | 2 +- .../design_overview/the_semantics.html | 2 +- .../tutorial/exception_safety_guarantees.html | 2 +- .../tutorial/in_place_factories.html | 2 +- .../boost_optional/tutorial/io_operators.html | 87 +++++++++++++++++++ .../tutorial/optional_references.html | 8 +- .../tutorial/performance_considerations.html | 2 +- ...for_assignment_of_optional_references.html | 2 +- .../tutorial/relational_operators.html | 8 +- .../tutorial/type_requirements.html | 2 +- .../tutorial/when_to_use_optional.html | 2 +- doc/html/index.html | 5 +- doc/html/optional/reference.html | 2 +- doc/html/optional/tutorial.html | 3 +- include/boost/optional/optional.hpp | 9 +- include/boost/optional/optional_io.hpp | 3 +- test/Jamfile.v2 | 1 + test/optional_test_fail_io_without_io.cpp | 24 +++++ 39 files changed, 213 insertions(+), 46 deletions(-) create mode 100644 doc/14_io.qbk rename doc/{14_optional_references.qbk => 15_optional_references.qbk} (100%) rename doc/{15_in_place_factories.qbk => 16_in_place_factories.qbk} (100%) rename doc/{16_optional_bool.qbk => 17_optional_bool.qbk} (100%) rename doc/{17_exception_safety.qbk => 18_exception_safety.qbk} (100%) rename doc/{18_type_requirements.qbk => 19_type_requirements.qbk} (100%) rename doc/{19_on_performance.qbk => 1A_on_performance.qbk} (100%) create mode 100644 doc/html/boost_optional/tutorial/io_operators.html create mode 100644 test/optional_test_fail_io_without_io.cpp diff --git a/doc/00_optional.qbk b/doc/00_optional.qbk index 2f940b7..28532de 100644 --- a/doc/00_optional.qbk +++ b/doc/00_optional.qbk @@ -2,7 +2,7 @@ [quickbook 1.4] [authors [Cacciola Carballal, Fernando Luis]] [copyright 2003-2007 Fernando Luis Cacciola Carballal] - [copyright 2014 Andrzej Krzemieński] + [copyright 2014-2015 Andrzej Krzemieński] [category miscellaneous] [id optional] [dirname optional] @@ -80,12 +80,13 @@ This is how you solve it with `boost::optional`: [include 11_development.qbk] [include 12_when_to_use.qbk] [include 13_relational_operators.qbk] -[include 14_optional_references.qbk] -[include 15_in_place_factories.qbk] -[include 16_optional_bool.qbk] -[include 17_exception_safety.qbk] -[include 18_type_requirements.qbk] -[include 19_on_performance.qbk] +[include 14_io.qbk] +[include 15_optional_references.qbk] +[include 16_in_place_factories.qbk] +[include 17_optional_bool.qbk] +[include 18_exception_safety.qbk] +[include 19_type_requirements.qbk] +[include 1A_on_performance.qbk] [endsect] [section Reference] [include 20_reference.qbk] diff --git a/doc/14_io.qbk b/doc/14_io.qbk new file mode 100644 index 0000000..0fb4e89 --- /dev/null +++ b/doc/14_io.qbk @@ -0,0 +1,37 @@ + +[section IO operators] + +It is possible to use `optional` with IO streams, provided that `T` can be used with streams. IOStream operators are defined in a separate header. + +`` +#include +#include + +int main() +{ + boost::optional o1 = 1, oN = boost::none; + std::cout << o1; + std::cin >> oN; +} +`` + +The current implementation does not guarantee any particular output. What it guarantees is that if streaming out and then back in `T` gives the same value, then streaming out and then back in `optional` will also give back the same result: + +`` +#include +#include +#include + +int main() +{ + boost::optional o1 = 1, oN = boost::none; + boost::optional x1, x2; + std::stringstream s; + s << o1 << oN; + s >> x1 >> x2; + assert (o1 == x1); + assert (oN == x2); +} +`` + +[endsect] diff --git a/doc/14_optional_references.qbk b/doc/15_optional_references.qbk similarity index 100% rename from doc/14_optional_references.qbk rename to doc/15_optional_references.qbk diff --git a/doc/15_in_place_factories.qbk b/doc/16_in_place_factories.qbk similarity index 100% rename from doc/15_in_place_factories.qbk rename to doc/16_in_place_factories.qbk diff --git a/doc/16_optional_bool.qbk b/doc/17_optional_bool.qbk similarity index 100% rename from doc/16_optional_bool.qbk rename to doc/17_optional_bool.qbk diff --git a/doc/17_exception_safety.qbk b/doc/18_exception_safety.qbk similarity index 100% rename from doc/17_exception_safety.qbk rename to doc/18_exception_safety.qbk diff --git a/doc/18_type_requirements.qbk b/doc/19_type_requirements.qbk similarity index 100% rename from doc/18_type_requirements.qbk rename to doc/19_type_requirements.qbk diff --git a/doc/19_on_performance.qbk b/doc/1A_on_performance.qbk similarity index 100% rename from doc/19_on_performance.qbk rename to doc/1A_on_performance.qbk diff --git a/doc/91_relnotes.qbk b/doc/91_relnotes.qbk index 94a9c61..666571c 100644 --- a/doc/91_relnotes.qbk +++ b/doc/91_relnotes.qbk @@ -14,6 +14,8 @@ [heading Boost Release 1.58] * `boost::none_t` is no longer convertible from literal `0`. This avoids a bug where `optional> oi = 0;` would initialize an optional object with no contained value. +* Improved the trick that prevents streaming out `optional` without header `optional_io.hpp` by using safe-bool idiom. This addresses [@https://svn.boost.org/trac/boost/ticket/10825 Trac #10825] +* IOStream operators are now mentioned in documentation. [heading Boost Release 1.57] diff --git a/doc/html/boost_optional/acknowledgements.html b/doc/html/boost_optional/acknowledgements.html index 9c8019a..d025d50 100644 --- a/doc/html/boost_optional/acknowledgements.html +++ b/doc/html/boost_optional/acknowledgements.html @@ -116,7 +116,7 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-

-PrevUpHomeNext +PrevUpHomeNext

@@ -101,7 +101,7 @@

-

-PrevUpHomeNext +PrevUpHomeNext
diff --git a/doc/html/boost_optional/tutorial/performance_considerations.html b/doc/html/boost_optional/tutorial/performance_considerations.html index d054e01..2e2d4ca 100644 --- a/doc/html/boost_optional/tutorial/performance_considerations.html +++ b/doc/html/boost_optional/tutorial/performance_considerations.html @@ -209,7 +209,7 @@
-
-