// 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 // 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 "boost/optional/optional.hpp" #include "boost/utility/in_place_factory.hpp" #ifdef __BORLANDC__ #pragma hdrstop #endif #include "boost/core/lightweight_test.hpp" #if __cplusplus < 201103L #include #else #include #endif using boost::optional; using boost::none; #define ARG(T) (static_cast< T const* >(0)) 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_TEST(!"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_TEST(!"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_TEST(!"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_TEST(!"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_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_TEST(!"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> : true_type {} ; template <> struct optional_swap_should_use_default_constructor< optional_swap_test::class_whose_default_ctor_should_not_be_used> : false_type {} ; template struct optional_swap_should_use_default_constructor< optional_swap_test::template_whose_default_ctor_should_be_used > : true_type {} ; // // 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_TEST(!obj1); BOOST_TEST(!!obj2 && obj2->data == 'a'); // Call non-member swap. swap(obj1, obj2); // Test if obj1 and obj2 are really swapped. 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_TEST(!obj1); BOOST_TEST(!!obj2 && obj2->data == 'a'); } catch(const std::exception &) { // The swap function should not throw, for our test cases. BOOST_TEST(!"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_TEST(!obj1); BOOST_TEST(!!obj2 && obj2->data == 'a'); // Call member swap. obj1.swap(obj2); // Test if obj1 and obj2 are really swapped. 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_TEST(!obj1); BOOST_TEST(!!obj2 && obj2->data == 'a'); } catch(const std::exception &) { BOOST_TEST(!"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 main() { test_swap_tweaking(); return boost::report_errors(); }