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
// 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:
// fernando_cacciola@hotmail.com
//
// Revisions:
// 27 Apr 2008 (improved swap) Fernando Cacciola, Niels Dekker, Thorsten Ottosen
//
#ifndef BOOST_OPTIONAL_OPTIONAL_FLC_19NOV2002_HPP
#define BOOST_OPTIONAL_OPTIONAL_FLC_19NOV2002_HPP
#include<new>
#include<algorithm>
#include <new>
#include <algorithm>
#include "boost/config.hpp"
#include "boost/assert.hpp"
#include "boost/type.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/remove_reference.hpp"
#include "boost/type_traits/is_reference.hpp"
@ -27,7 +31,9 @@
#include "boost/mpl/not.hpp"
#include "boost/detail/reference_content.hpp"
#include "boost/none.hpp"
#include "boost/utility/addressof.hpp"
#include "boost/utility/compare_pointees.hpp"
#include "boost/utility/in_place_factory.hpp"
#include "boost/optional/optional_fwd.hpp"
@ -76,6 +82,15 @@
#define BOOST_OPTIONAL_WEAK_OVERLOAD_RESOLUTION
#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<>
// 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
@ -105,7 +120,12 @@ template <class T>
class aligned_storage
{
// 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) ];
BOOST_DEDUCED_TYPENAME type_with_alignment<
@ -114,8 +134,13 @@ class aligned_storage
public:
void const* address() const { return &dummy_.data[0]; }
void * address() { return &dummy_.data[0]; }
#if defined(BOOST_OPTIONAL_DETAIL_USE_ATTRIBUTE_MAY_ALIAS)
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>
@ -149,7 +174,7 @@ class optional_base : public optional_tag
typedef
#if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
BOOST_DEDUCED_TYPENAME
#endif
#endif
::boost::detail::make_reference_content<T>::type internal_type ;
typedef aligned_storage<internal_type> storage_type ;
@ -200,7 +225,7 @@ class optional_base : public optional_tag
{
construct(val);
}
// 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
optional_base ( bool cond, argument_type val )
@ -421,8 +446,22 @@ class optional_base : public optional_tag
private :
// 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 * 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_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.
// Can throw is the resolved T ctor throws.
template<class Expr>
explicit optional ( Expr const& expr ) : base(expr,&expr) {}
explicit optional ( Expr const& expr ) : base(expr,boost::addressof(expr)) {}
#endif
// Creates a deep copy of another optional<T>
// 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)
~optional() {}
@ -527,9 +566,9 @@ class optional : public optional_detail::optional_base<T>
// Assigns from an expression. See corresponding constructor.
// Basic Guarantee: If the resolved T ctor throws, this is left UNINITIALIZED
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 ;
}
#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)
optional& operator= ( optional const& rhs )
{
this->assign( rhs ) ;
this->assign( static_cast<base const&>(rhs) ) ;
return *this ;
}
@ -573,6 +612,14 @@ class optional : public optional_detail::optional_base<T>
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,
// the behaviour is UNDEFINED
// 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
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 ; }
// Returns a pointer to the value if this is initialized, otherwise,
// the behaviour is UNDEFINED
// No-throw
@ -599,22 +646,22 @@ class optional : public optional_detail::optional_base<T>
// No-throw
operator unspecified_bool_type() const { return this->safe_bool() ; }
// This is provided for those compilers which don't like the conversion to bool
// on some contexts.
bool operator!() const { return !this->is_initialized() ; }
// This is provided for those compilers which don't like the conversion to bool
// on some contexts.
bool operator!() const { return !this->is_initialized() ; }
} ;
// Returns optional<T>(v)
template<class T>
inline
template<class T>
inline
optional<T> make_optional ( T const& v )
{
return optional<T>(v);
}
// Returns optional<T>(cond,v)
template<class T>
inline
template<class T>
inline
optional<T> make_optional ( bool cond, T const& v )
{
return optional<T>(cond,v);
@ -880,44 +927,77 @@ namespace optional_detail {
#define BOOST_OPTIONAL_STD_SWAP_INTRODUCED_AT_NS_SCOPE
#endif
// optional's swap:
// 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().
// If U.reset(*I) throws, both are left UNCHANGED (U is kept uinitialized and I is never reset)
// If both are uninitialized, do nothing (no-throw)
template<class T>
inline
void optional_swap ( optional<T>& x, optional<T>& y )
{
if ( !x && !!y )
template<bool use_default_constructor> struct swap_selector;
template<>
struct swap_selector<true>
{
x.reset(*y);
y.reset();
}
else if ( !!x && !y )
{
y.reset(*x);
x.reset();
}
else if ( !!x && !!y )
{
// GCC > 3.2 and all other compilers have the using declaration at function scope (FLC)
template<class T>
static void optional_swap ( optional<T>& x, optional<T>& y )
{
bool hasX = x;
bool hasY = y;
if ( !hasX && !hasY )
return;
if( !hasX )
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
// allow for Koenig lookup
using std::swap ;
// allow for Koenig lookup
using std::swap ;
#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
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 )
{
optional_detail::optional_swap(x,y);
optional_detail::swap_selector<optional_swap_should_use_default_constructor<T>::value>::optional_swap(x, y);
}
} // namespace boost
#endif

View File

@ -13,19 +13,20 @@
#define BOOST_OPTIONAL_OPTIONAL_IO_FLC_19NOV2002_HPP
#if defined __GNUC__
# if (__GNUC__ == 2 && __GNUC_MINOR__ <= 97)
# if (__GNUC__ == 2 && __GNUC_MINOR__ <= 97)
# define BOOST_OPTIONAL_NO_TEMPLATED_STREAMS
# endif
#endif // __GNUC__
#if defined BOOST_OPTIONAL_NO_TEMPLATED_STREAMS
# include <iostream>
#else
#else
# include <istream>
# include <ostream>
#endif
#endif
#include <boost/none.hpp>
#include <boost/assert.hpp>
#include "boost/optional/optional.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)
#endif
{
if ( in.good() )
if (in.good())
{
int d = in.get();
if ( d == ' ' )
if (d == ' ')
{
T x ;
T x;
in >> x;
v = x ;
v = x;
}
else
v = optional<T>() ;
{
if (d == '-')
{
d = in.get();
if (d == '-')
{
v = none;
return in;
}
}
in.setstate( std::ios::failbit );
}
}
return in;