Merged changes from trunk. Fixes #3395. Also updates swap behavior: if default constructor has no-throw guarantee, swap will use it to provide no-throw guarantee itself. operator>> behavior changed slightly so that the stream is not accessed when unrecognized character sequence is detected. The stream is marked with failbit in such a case.

[SVN r67183]
This commit is contained in:
Andrey Semashev
2010-12-12 11:34:12 +00:00
parent 3d859e5fbe
commit ef2d285d47
4 changed files with 557 additions and 95 deletions

View File

@ -1,4 +1,4 @@
// Copyright (C) 2003, Fernando Luis Cacciola Carballal. // Copyright (C) 2003, 2008 Fernando Luis Cacciola Carballal.
// //
// Use, modification, and distribution is subject to the Boost Software // Use, modification, and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
@ -9,16 +9,20 @@
// You are welcome to contact the author at: // You are welcome to contact the author at:
// fernando_cacciola@hotmail.com // fernando_cacciola@hotmail.com
// //
// Revisions:
// 27 Apr 2008 (improved swap) Fernando Cacciola, Niels Dekker, Thorsten Ottosen
//
#ifndef BOOST_OPTIONAL_OPTIONAL_FLC_19NOV2002_HPP #ifndef BOOST_OPTIONAL_OPTIONAL_FLC_19NOV2002_HPP
#define BOOST_OPTIONAL_OPTIONAL_FLC_19NOV2002_HPP #define BOOST_OPTIONAL_OPTIONAL_FLC_19NOV2002_HPP
#include<new> #include <new>
#include<algorithm> #include <algorithm>
#include "boost/config.hpp" #include "boost/config.hpp"
#include "boost/assert.hpp" #include "boost/assert.hpp"
#include "boost/type.hpp" #include "boost/type.hpp"
#include "boost/type_traits/alignment_of.hpp" #include "boost/type_traits/alignment_of.hpp"
#include "boost/type_traits/has_nothrow_constructor.hpp"
#include "boost/type_traits/type_with_alignment.hpp" #include "boost/type_traits/type_with_alignment.hpp"
#include "boost/type_traits/remove_reference.hpp" #include "boost/type_traits/remove_reference.hpp"
#include "boost/type_traits/is_reference.hpp" #include "boost/type_traits/is_reference.hpp"
@ -27,7 +31,9 @@
#include "boost/mpl/not.hpp" #include "boost/mpl/not.hpp"
#include "boost/detail/reference_content.hpp" #include "boost/detail/reference_content.hpp"
#include "boost/none.hpp" #include "boost/none.hpp"
#include "boost/utility/addressof.hpp"
#include "boost/utility/compare_pointees.hpp" #include "boost/utility/compare_pointees.hpp"
#include "boost/utility/in_place_factory.hpp"
#include "boost/optional/optional_fwd.hpp" #include "boost/optional/optional_fwd.hpp"
@ -76,6 +82,15 @@
#define BOOST_OPTIONAL_WEAK_OVERLOAD_RESOLUTION #define BOOST_OPTIONAL_WEAK_OVERLOAD_RESOLUTION
#endif #endif
#if defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) > 302 \
&& !defined(__INTEL_COMPILER)
// GCC since 3.3 has may_alias attribute that helps to alleviate optimizer issues with
// regard to violation of the strict aliasing rules. The optional< T > storage type is marked
// with this attribute in order to let the compiler know that it will alias objects of type T
// and silence compilation warnings.
#define BOOST_OPTIONAL_DETAIL_USE_ATTRIBUTE_MAY_ALIAS
#endif
// Daniel Wallin discovered that bind/apply.hpp badly interacts with the apply<> // Daniel Wallin discovered that bind/apply.hpp badly interacts with the apply<>
// member template of a factory as used in the optional<> implementation. // member template of a factory as used in the optional<> implementation.
// He proposed this simple fix which is to move the call to apply<> outside // He proposed this simple fix which is to move the call to apply<> outside
@ -105,7 +120,12 @@ template <class T>
class aligned_storage class aligned_storage
{ {
// Borland ICEs if unnamed unions are used for this! // Borland ICEs if unnamed unions are used for this!
union dummy_u union
// This works around GCC warnings about breaking strict aliasing rules when casting storage address to T*
#if defined(BOOST_OPTIONAL_DETAIL_USE_ATTRIBUTE_MAY_ALIAS)
__attribute__((may_alias))
#endif
dummy_u
{ {
char data[ sizeof(T) ]; char data[ sizeof(T) ];
BOOST_DEDUCED_TYPENAME type_with_alignment< BOOST_DEDUCED_TYPENAME type_with_alignment<
@ -114,8 +134,13 @@ class aligned_storage
public: public:
void const* address() const { return &dummy_.data[0]; } #if defined(BOOST_OPTIONAL_DETAIL_USE_ATTRIBUTE_MAY_ALIAS)
void * address() { return &dummy_.data[0]; } void const* address() const { return &dummy_; }
void * address() { return &dummy_; }
#else
void const* address() const { return dummy_.data; }
void * address() { return dummy_.data; }
#endif
} ; } ;
template<class T> template<class T>
@ -149,7 +174,7 @@ class optional_base : public optional_tag
typedef typedef
#if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) #if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
BOOST_DEDUCED_TYPENAME BOOST_DEDUCED_TYPENAME
#endif #endif
::boost::detail::make_reference_content<T>::type internal_type ; ::boost::detail::make_reference_content<T>::type internal_type ;
typedef aligned_storage<internal_type> storage_type ; typedef aligned_storage<internal_type> storage_type ;
@ -200,7 +225,7 @@ class optional_base : public optional_tag
{ {
construct(val); construct(val);
} }
// Creates an optional<T> initialized with 'val' IFF cond is true, otherwise creates an uninitialzed optional<T>. // Creates an optional<T> initialized with 'val' IFF cond is true, otherwise creates an uninitialzed optional<T>.
// Can throw if T::T(T const&) does // Can throw if T::T(T const&) does
optional_base ( bool cond, argument_type val ) optional_base ( bool cond, argument_type val )
@ -421,8 +446,22 @@ class optional_base : public optional_tag
private : private :
// internal_type can be either T or reference_content<T> // internal_type can be either T or reference_content<T>
#if defined(BOOST_OPTIONAL_DETAIL_USE_ATTRIBUTE_MAY_ALIAS)
// This workaround is supposed to silence GCC warnings about broken strict aliasing rules
internal_type const* get_object() const
{
union { void const* ap_pvoid; internal_type const* as_ptype; } caster = { m_storage.address() };
return caster.as_ptype;
}
internal_type * get_object()
{
union { void* ap_pvoid; internal_type* as_ptype; } caster = { m_storage.address() };
return caster.as_ptype;
}
#else
internal_type const* get_object() const { return static_cast<internal_type const*>(m_storage.address()); } internal_type const* get_object() const { return static_cast<internal_type const*>(m_storage.address()); }
internal_type * get_object() { return static_cast<internal_type *> (m_storage.address()); } internal_type * get_object() { return static_cast<internal_type *> (m_storage.address()); }
#endif
// reference_content<T> lacks an implicit conversion to T&, so the following is needed to obtain a proper reference. // reference_content<T> lacks an implicit conversion to T&, so the following is needed to obtain a proper reference.
reference_const_type dereference( internal_type const* p, is_not_reference_tag ) const { return *p ; } reference_const_type dereference( internal_type const* p, is_not_reference_tag ) const { return *p ; }
@ -513,12 +552,12 @@ class optional : public optional_detail::optional_base<T>
// Depending on the above some T ctor is called. // Depending on the above some T ctor is called.
// Can throw is the resolved T ctor throws. // Can throw is the resolved T ctor throws.
template<class Expr> template<class Expr>
explicit optional ( Expr const& expr ) : base(expr,&expr) {} explicit optional ( Expr const& expr ) : base(expr,boost::addressof(expr)) {}
#endif #endif
// Creates a deep copy of another optional<T> // Creates a deep copy of another optional<T>
// Can throw if T::T(T const&) does // Can throw if T::T(T const&) does
optional ( optional const& rhs ) : base(rhs) {} optional ( optional const& rhs ) : base( static_cast<base const&>(rhs) ) {}
// No-throw (assuming T::~T() doesn't) // No-throw (assuming T::~T() doesn't)
~optional() {} ~optional() {}
@ -527,9 +566,9 @@ class optional : public optional_detail::optional_base<T>
// Assigns from an expression. See corresponding constructor. // Assigns from an expression. See corresponding constructor.
// Basic Guarantee: If the resolved T ctor throws, this is left UNINITIALIZED // Basic Guarantee: If the resolved T ctor throws, this is left UNINITIALIZED
template<class Expr> template<class Expr>
optional& operator= ( Expr expr ) optional& operator= ( Expr const& expr )
{ {
this->assign_expr(expr,&expr); this->assign_expr(expr,boost::addressof(expr));
return *this ; return *this ;
} }
#endif #endif
@ -552,7 +591,7 @@ class optional : public optional_detail::optional_base<T>
// (NOTE: On BCB, this operator is not actually called and left is left UNMODIFIED in case of a throw) // (NOTE: On BCB, this operator is not actually called and left is left UNMODIFIED in case of a throw)
optional& operator= ( optional const& rhs ) optional& operator= ( optional const& rhs )
{ {
this->assign( rhs ) ; this->assign( static_cast<base const&>(rhs) ) ;
return *this ; return *this ;
} }
@ -573,6 +612,14 @@ class optional : public optional_detail::optional_base<T>
return *this ; return *this ;
} }
void swap( optional & arg )
{
// allow for Koenig lookup
using boost::swap ;
swap(*this, arg);
}
// Returns a reference to the value if this is initialized, otherwise, // Returns a reference to the value if this is initialized, otherwise,
// the behaviour is UNDEFINED // the behaviour is UNDEFINED
// No-throw // No-throw
@ -582,7 +629,7 @@ class optional : public optional_detail::optional_base<T>
// Returns a copy of the value if this is initialized, 'v' otherwise // Returns a copy of the value if this is initialized, 'v' otherwise
reference_const_type get_value_or ( reference_const_type v ) const { return this->is_initialized() ? get() : v ; } reference_const_type get_value_or ( reference_const_type v ) const { return this->is_initialized() ? get() : v ; }
reference_type get_value_or ( reference_type v ) { return this->is_initialized() ? get() : v ; } reference_type get_value_or ( reference_type v ) { return this->is_initialized() ? get() : v ; }
// Returns a pointer to the value if this is initialized, otherwise, // Returns a pointer to the value if this is initialized, otherwise,
// the behaviour is UNDEFINED // the behaviour is UNDEFINED
// No-throw // No-throw
@ -599,22 +646,22 @@ class optional : public optional_detail::optional_base<T>
// No-throw // No-throw
operator unspecified_bool_type() const { return this->safe_bool() ; } operator unspecified_bool_type() const { return this->safe_bool() ; }
// This is provided for those compilers which don't like the conversion to bool // This is provided for those compilers which don't like the conversion to bool
// on some contexts. // on some contexts.
bool operator!() const { return !this->is_initialized() ; } bool operator!() const { return !this->is_initialized() ; }
} ; } ;
// Returns optional<T>(v) // Returns optional<T>(v)
template<class T> template<class T>
inline inline
optional<T> make_optional ( T const& v ) optional<T> make_optional ( T const& v )
{ {
return optional<T>(v); return optional<T>(v);
} }
// Returns optional<T>(cond,v) // Returns optional<T>(cond,v)
template<class T> template<class T>
inline inline
optional<T> make_optional ( bool cond, T const& v ) optional<T> make_optional ( bool cond, T const& v )
{ {
return optional<T>(cond,v); return optional<T>(cond,v);
@ -880,44 +927,77 @@ namespace optional_detail {
#define BOOST_OPTIONAL_STD_SWAP_INTRODUCED_AT_NS_SCOPE #define BOOST_OPTIONAL_STD_SWAP_INTRODUCED_AT_NS_SCOPE
#endif #endif
// optional's swap: template<bool use_default_constructor> struct swap_selector;
// If both are initialized, calls swap(T&, T&). If this swap throws, both will remain initialized but their values are now unspecified.
// If only one is initialized, calls U.reset(*I), THEN I.reset(). template<>
// If U.reset(*I) throws, both are left UNCHANGED (U is kept uinitialized and I is never reset) struct swap_selector<true>
// If both are uninitialized, do nothing (no-throw)
template<class T>
inline
void optional_swap ( optional<T>& x, optional<T>& y )
{
if ( !x && !!y )
{ {
x.reset(*y); template<class T>
y.reset(); static void optional_swap ( optional<T>& x, optional<T>& y )
} {
else if ( !!x && !y ) bool hasX = x;
{ bool hasY = y;
y.reset(*x);
x.reset(); if ( !hasX && !hasY )
} return;
else if ( !!x && !!y )
{ if( !hasX )
// GCC > 3.2 and all other compilers have the using declaration at function scope (FLC) x = boost::in_place();
else if ( !hasY )
y = boost::in_place();
// GCC > 3.2 and all other compilers have the using declaration at function scope (FLC)
#ifndef BOOST_OPTIONAL_STD_SWAP_INTRODUCED_AT_NS_SCOPE #ifndef BOOST_OPTIONAL_STD_SWAP_INTRODUCED_AT_NS_SCOPE
// allow for Koenig lookup // allow for Koenig lookup
using std::swap ; using std::swap ;
#endif #endif
swap(*x,*y); swap(*x,*y);
}
} if( !hasX )
y = boost::none ;
else if( !hasY )
x = boost::none ;
}
};
template<>
struct swap_selector<false>
{
template<class T>
static void optional_swap ( optional<T>& x, optional<T>& y )
{
if ( !x && !!y )
{
x = *y;
y = boost::none ;
}
else if ( !!x && !y )
{
y = *x ;
x = boost::none ;
}
else if ( !!x && !!y )
{
// GCC > 3.2 and all other compilers have the using declaration at function scope (FLC)
#ifndef BOOST_OPTIONAL_STD_SWAP_INTRODUCED_AT_NS_SCOPE
// allow for Koenig lookup
using std::swap ;
#endif
swap(*x,*y);
}
}
};
} // namespace optional_detail } // namespace optional_detail
template<class T>
struct optional_swap_should_use_default_constructor : has_nothrow_default_constructor<T> {} ;
template<class T> inline void swap ( optional<T>& x, optional<T>& y ) template<class T> inline void swap ( optional<T>& x, optional<T>& y )
{ {
optional_detail::optional_swap(x,y); optional_detail::swap_selector<optional_swap_should_use_default_constructor<T>::value>::optional_swap(x, y);
} }
} // namespace boost } // namespace boost
#endif #endif

View File

@ -13,19 +13,20 @@
#define BOOST_OPTIONAL_OPTIONAL_IO_FLC_19NOV2002_HPP #define BOOST_OPTIONAL_OPTIONAL_IO_FLC_19NOV2002_HPP
#if defined __GNUC__ #if defined __GNUC__
# if (__GNUC__ == 2 && __GNUC_MINOR__ <= 97) # if (__GNUC__ == 2 && __GNUC_MINOR__ <= 97)
# define BOOST_OPTIONAL_NO_TEMPLATED_STREAMS # define BOOST_OPTIONAL_NO_TEMPLATED_STREAMS
# endif # endif
#endif // __GNUC__ #endif // __GNUC__
#if defined BOOST_OPTIONAL_NO_TEMPLATED_STREAMS #if defined BOOST_OPTIONAL_NO_TEMPLATED_STREAMS
# include <iostream> # include <iostream>
#else #else
# include <istream> # include <istream>
# include <ostream> # include <ostream>
#endif #endif
#include <boost/none.hpp>
#include <boost/assert.hpp>
#include "boost/optional/optional.hpp" #include "boost/optional/optional.hpp"
#include "boost/utility/value_init.hpp" #include "boost/utility/value_init.hpp"
@ -62,17 +63,30 @@ std::basic_istream<CharType, CharTrait>&
operator>>(std::basic_istream<CharType, CharTrait>& in, optional<T>& v) operator>>(std::basic_istream<CharType, CharTrait>& in, optional<T>& v)
#endif #endif
{ {
if ( in.good() ) if (in.good())
{ {
int d = in.get(); int d = in.get();
if ( d == ' ' ) if (d == ' ')
{ {
T x ; T x;
in >> x; in >> x;
v = x ; v = x;
} }
else else
v = optional<T>() ; {
if (d == '-')
{
d = in.get();
if (d == '-')
{
v = none;
return in;
}
}
in.setstate( std::ios::failbit );
}
} }
return in; return in;

View File

@ -1,4 +1,4 @@
// Copyright (C) 2003, Fernando Luis Cacciola Carballal. // Copyright (C) 2003, 2008 Fernando Luis Cacciola Carballal.
// //
// Use, modification, and distribution is subject to the Boost Software // Use, modification, and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
@ -9,6 +9,9 @@
// You are welcome to contact the author at: // You are welcome to contact the author at:
// fernando_cacciola@hotmail.com // fernando_cacciola@hotmail.com
// //
// Revisions:
// 12 May 2008 (added more swap tests)
//
#include<iostream> #include<iostream>
#include<stdexcept> #include<stdexcept>
#include<string> #include<string>
@ -16,6 +19,8 @@
#define BOOST_ENABLE_ASSERT_HANDLER #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/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" #include "boost/optional/optional.hpp"
@ -153,27 +158,27 @@ void test_basics( T const* )
ob.reset(); ob.reset();
check_is_pending_dtor( ARG(T) ) ; check_is_pending_dtor( ARG(T) ) ;
check_uninitialized(ob); check_uninitialized(ob);
} }
template<class T> template<class T>
void test_conditional_ctor_and_get_valur_or ( T const* ) void test_conditional_ctor_and_get_valur_or ( T const* )
{ {
TRACE( std::endl << BOOST_CURRENT_FUNCTION ); TRACE( std::endl << BOOST_CURRENT_FUNCTION );
T a(321); T a(321);
T z(123); T z(123);
optional<T> const cdef0(false,a); optional<T> const cdef0(false,a);
optional<T> def0(false,a); optional<T> def0(false,a);
optional<T> def1 = boost::make_optional(false,a); // T is not within boost so ADL won't find make_optional unqualified optional<T> def1 = boost::make_optional(false,a); // T is not within boost so ADL won't find make_optional unqualified
check_uninitialized(def0); check_uninitialized(def0);
check_uninitialized(def1); check_uninitialized(def1);
optional<T> const co0(true,a); optional<T> const co0(true,a);
optional<T> o0(true,a); optional<T> o0(true,a);
optional<T> o1 = boost::make_optional(true,a); // T is not within boost so ADL won't find make_optional unqualified optional<T> o1 = boost::make_optional(true,a); // T is not within boost so ADL won't find make_optional unqualified
@ -181,65 +186,65 @@ void test_conditional_ctor_and_get_valur_or ( T const* )
check_initialized(o1); check_initialized(o1);
check_value(o0,a,z); check_value(o0,a,z);
check_value(o1,a,z); check_value(o1,a,z);
T b = def0.get_value_or(z); T b = def0.get_value_or(z);
BOOST_CHECK( b == z ) ; BOOST_CHECK( b == z ) ;
b = get_optional_value_or(def0,z); b = get_optional_value_or(def0,z);
BOOST_CHECK( b == z ) ; BOOST_CHECK( b == z ) ;
b = o0.get_value_or(z); b = o0.get_value_or(z);
BOOST_CHECK( b == a ) ; BOOST_CHECK( b == a ) ;
b = get_optional_value_or(o0,z); b = get_optional_value_or(o0,z);
BOOST_CHECK( b == a ) ; BOOST_CHECK( b == a ) ;
T const& crz = z ; T const& crz = z ;
T& rz = z ; T& rz = z ;
T const& crzz = def0.get_value_or(crz); T const& crzz = def0.get_value_or(crz);
BOOST_CHECK( crzz == crz ) ; BOOST_CHECK( crzz == crz ) ;
T& rzz = def0.get_value_or(rz); T& rzz = def0.get_value_or(rz);
BOOST_CHECK( rzz == rz ) ; BOOST_CHECK( rzz == rz ) ;
T const& crzzz = get_optional_value_or(cdef0,crz); T const& crzzz = get_optional_value_or(cdef0,crz);
BOOST_CHECK( crzzz == crz ) ; BOOST_CHECK( crzzz == crz ) ;
T& rzzz = get_optional_value_or(def0,rz); T& rzzz = get_optional_value_or(def0,rz);
BOOST_CHECK( rzzz == rz ) ; BOOST_CHECK( rzzz == rz ) ;
T const& crb = o0.get_value_or(crz); T const& crb = o0.get_value_or(crz);
BOOST_CHECK( crb == a ) ; BOOST_CHECK( crb == a ) ;
T& rb = o0.get_value_or(rz); T& rb = o0.get_value_or(rz);
BOOST_CHECK( rb == b ) ; BOOST_CHECK( rb == b ) ;
T const& crbb = get_optional_value_or(co0,crz); T const& crbb = get_optional_value_or(co0,crz);
BOOST_CHECK( crbb == b ) ; BOOST_CHECK( crbb == b ) ;
T const& crbbb = get_optional_value_or(o0,crz); T const& crbbb = get_optional_value_or(o0,crz);
BOOST_CHECK( crbbb == b ) ; BOOST_CHECK( crbbb == b ) ;
T& rbb = get_optional_value_or(o0,rz); T& rbb = get_optional_value_or(o0,rz);
BOOST_CHECK( rbb == b ) ; BOOST_CHECK( rbb == b ) ;
T& ra = a ; T& ra = a ;
optional<T&> defref(false,ra); optional<T&> defref(false,ra);
BOOST_CHECK(!defref); BOOST_CHECK(!defref);
optional<T&> ref(true,ra); optional<T&> ref(true,ra);
BOOST_CHECK(!!ref); BOOST_CHECK(!!ref);
a = T(432); a = T(432);
BOOST_CHECK( *ref == a ) ; BOOST_CHECK( *ref == a ) ;
T& r1 = defref.get_value_or(z); T& r1 = defref.get_value_or(z);
BOOST_CHECK( r1 == z ) ; BOOST_CHECK( r1 == z ) ;
T& r2 = ref.get_value_or(z); T& r2 = ref.get_value_or(z);
BOOST_CHECK( r2 == a ) ; BOOST_CHECK( r2 == a ) ;
} }
@ -713,7 +718,7 @@ void test_relops( T const* )
optional<T> opt0(v0); optional<T> opt0(v0);
optional<T> opt1(v1); optional<T> opt1(v1);
optional<T> opt2(v2); optional<T> opt2(v2);
// Check identity // Check identity
BOOST_CHECK ( def0 == def0 ) ; BOOST_CHECK ( def0 == def0 ) ;
BOOST_CHECK ( opt0 == opt0 ) ; BOOST_CHECK ( opt0 == opt0 ) ;
@ -751,7 +756,7 @@ void test_relops( T const* )
BOOST_CHECK ( opt1 > opt0 ) ; BOOST_CHECK ( opt1 > opt0 ) ;
BOOST_CHECK ( opt1 <= opt2 ) ; BOOST_CHECK ( opt1 <= opt2 ) ;
BOOST_CHECK ( opt1 >= opt0 ) ; BOOST_CHECK ( opt1 >= opt0 ) ;
// Compare against a value directly // Compare against a value directly
BOOST_CHECK ( opt0 == v0 ) ; BOOST_CHECK ( opt0 == v0 ) ;
BOOST_CHECK ( opt0 != v1 ) ; BOOST_CHECK ( opt0 != v1 ) ;
@ -794,7 +799,7 @@ void test_none( T const* )
BOOST_CHECK ( def0 == none ) ; BOOST_CHECK ( def0 == none ) ;
BOOST_CHECK ( non_def != none ) ; BOOST_CHECK ( non_def != none ) ;
BOOST_CHECK ( !def1 ) ; BOOST_CHECK ( !def1 ) ;
BOOST_CHECK ( !(non_def < none) ) ; BOOST_CHECK ( !(non_def < none) ) ;
BOOST_CHECK ( non_def > none ) ; BOOST_CHECK ( non_def > none ) ;
BOOST_CHECK ( !(non_def <= none) ) ; BOOST_CHECK ( !(non_def <= none) ) ;
BOOST_CHECK ( non_def >= none ) ; BOOST_CHECK ( non_def >= none ) ;
@ -814,11 +819,11 @@ void test_arrow( T const* )
optional<T> oa(a) ; optional<T> oa(a) ;
optional<T> const coa(a) ; optional<T> const coa(a) ;
BOOST_CHECK ( coa->V() == 1234 ) ; BOOST_CHECK ( coa->V() == 1234 ) ;
oa->V() = 4321 ; oa->V() = 4321 ;
BOOST_CHECK ( a.V() = 1234 ) ; BOOST_CHECK ( a.V() = 1234 ) ;
BOOST_CHECK ( (*oa).V() = 4321 ) ; BOOST_CHECK ( (*oa).V() = 4321 ) ;
} }
@ -927,6 +932,364 @@ void test_conversions2()
BOOST_CHECK(*get(&opt1) == static_cast<double>(f)); BOOST_CHECK(*get(&opt1) == static_cast<double>(f));
} }
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<T> 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 T>
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 <class T>
void swap(template_whose_default_ctor_should_be_used<T> & lhs, template_whose_default_ctor_should_be_used<T> & rhs)
{
std::swap(lhs.data, rhs.data);
}
//
// optional<T>::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<class_whose_explicit_ctor_should_be_used> & x, boost::optional<class_whose_explicit_ctor_should_be_used> & 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 <class T> struct optional_swap_should_use_default_constructor<
optional_swap_test::template_whose_default_ctor_should_be_used<T> > : mpl::true_ {} ;
//
// Specialization of boost::swap:
//
template <>
void swap(optional<optional_swap_test::class_whose_explicit_ctor_should_be_used> & x, optional<optional_swap_test::class_whose_explicit_ctor_should_be_used> & 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<T>.
// Assumes that T has one data member, of type char.
// Returns true iff the test is passed.
//
template <class T>
bool test_swap_function( T const* )
{
const boost::unit_test::counter_t counter_before_test = boost::minimal_test::errors_counter();
try
{
optional<T> obj1;
optional<T> 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<T>::swap member function works properly.
// Assumes that T has one data member, of type char.
// Returns true iff the test is passed.
//
template <class T>
bool test_swap_member_function( T const* )
{
const boost::unit_test::counter_t counter_before_test = boost::minimal_test::errors_counter();
try
{
optional<T> obj1;
optional<T> 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<T>::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<char>) ) );
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<char>) ) );
}
// Test for support for classes with overridden operator&
class CustomAddressOfClass
{
int n;
public:
CustomAddressOfClass() : n(0) {}
CustomAddressOfClass(CustomAddressOfClass const& that) : n(that.n) {}
explicit CustomAddressOfClass(int m) : n(m) {}
int* operator& () { return &n; }
bool operator== (CustomAddressOfClass const& that) const { return n == that.n; }
};
void test_custom_addressof_operator()
{
boost::optional< CustomAddressOfClass > o1(CustomAddressOfClass(10));
BOOST_CHECK(!!o1);
BOOST_CHECK(o1.get() == CustomAddressOfClass(10));
o1 = CustomAddressOfClass(20);
BOOST_CHECK(!!o1);
BOOST_CHECK(o1.get() == CustomAddressOfClass(20));
o1 = boost::none;
BOOST_CHECK(!o1);
}
int test_main( int, char* [] ) int test_main( int, char* [] )
{ {
try try
@ -936,6 +1299,8 @@ int test_main( int, char* [] )
test_no_implicit_conversions(); test_no_implicit_conversions();
test_conversions1(); test_conversions1();
test_conversions2(); test_conversions2();
test_swap_tweaking();
test_custom_addressof_operator();
} }
catch ( ... ) catch ( ... )
{ {

View File

@ -55,10 +55,14 @@ void test2( Opt o, Opt buff )
{ {
stringstream s ; stringstream s ;
s << o ; const int markv = 123 ;
s >> buff ; int mark = 0 ;
s << o << " " << markv ;
s >> buff >> mark ;
BOOST_ASSERT( buff == o ) ; BOOST_ASSERT( buff == o ) ;
BOOST_ASSERT( mark == markv ) ;
} }
@ -77,7 +81,6 @@ int test_main( int, char* [] )
{ {
test(1,2); test(1,2);
test(string("hello"),string("buffer")); test(string("hello"),string("buffer"));
test(string(""),string("buffer"));
} }
catch ( ... ) catch ( ... )
{ {