Updates #5800 (partially fix lexical cast compilation with disabled exceptions)

[SVN r77116]
This commit is contained in:
Antony Polukhin
2012-02-25 16:58:46 +00:00
parent b71fb9aada
commit 25d880f5eb
4 changed files with 145 additions and 50 deletions

View File

@@ -3,7 +3,7 @@
[version 1.0]
[copyright 2000-2005 Kevlin Henney]
[copyright 2006-2010 Alexander Nasonov]
[copyright 2011 Antony Polukhin]
[copyright 2011-2012 Antony Polukhin]
[category String and text processing]
[category Miscellaneous]
[license
@@ -170,6 +170,11 @@ limitation of compiler options that you use.
[endsect]
[section Changes]
* [*boost 1.50.0 :]
* `boost::bad_lexical_cast` exception is now globaly visible and can be catched even if code is compiled with -fvisibility=hidden.
* Now it is possible to compile library with disabled exceptions.
* [*boost 1.49.0 :]
* Restored work with typedefed wchar_t (compilation flag /Zc:wchar_t- for Visual Studio).

View File

@@ -104,7 +104,7 @@ _CRTIMP int __cdecl vswprintf(wchar_t * __restrict__ , const wchar_t * __restric
namespace boost
{
// exception used to indicate runtime lexical_cast failure
class bad_lexical_cast :
class BOOST_SYMBOL_VISIBLE bad_lexical_cast :
// workaround MSVC bug with std::bad_cast when _HAS_EXCEPTIONS == 0
#if defined(BOOST_MSVC) && defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS
public std::exception
@@ -1958,52 +1958,52 @@ namespace boost
}
};
class precision_loss_error : public boost::numeric::bad_numeric_cast
template<class Source, class Target >
struct detect_precision_loss
{
public:
virtual const char * what() const throw()
{ return "bad numeric conversion: precision loss error"; }
};
typedef boost::numeric::Trunc<Source> Rounder;
typedef Source source_type ;
template<class S >
struct throw_on_precision_loss
{
typedef boost::numeric::Trunc<S> Rounder;
typedef S source_type ;
typedef typename mpl::if_< is_arithmetic<S>,S,S const&>::type argument_type ;
typedef BOOST_DEDUCED_TYPENAME mpl::if_<
is_arithmetic<Source>, Source, Source const&
>::type argument_type ;
static source_type nearbyint ( argument_type s )
{
source_type orig_div_round = s / Rounder::nearbyint(s);
const source_type orig_div_round = s / Rounder::nearbyint(s);
const source_type eps = std::numeric_limits<source_type>::epsilon();
if ((orig_div_round > 1 ? orig_div_round - 1 : 1 - orig_div_round) > eps)
BOOST_LCAST_THROW_BAD_CAST(Source, Target);
if ( (orig_div_round > 1 ? orig_div_round - 1 : 1 - orig_div_round) > std::numeric_limits<source_type>::epsilon() )
BOOST_THROW_EXCEPTION( precision_loss_error() );
return s ;
}
typedef typename Rounder::round_style round_style;
} ;
template<class Source, class Target >
struct nothrow_overflow_handler
{
void operator() ( boost::numeric::range_check_result r )
{
if (r != boost::numeric::cInRange)
BOOST_LCAST_THROW_BAD_CAST(Source, Target);
}
} ;
template<typename Target, typename Source>
struct lexical_cast_dynamic_num_not_ignoring_minus
{
static inline Target lexical_cast_impl(const Source &arg)
{
try{
typedef boost::numeric::converter<
Target,
Source,
boost::numeric::conversion_traits<Target,Source>,
boost::numeric::def_overflow_handler,
throw_on_precision_loss<Source>
> Converter ;
return Converter::convert(arg);
} catch( ::boost::numeric::bad_numeric_cast const& ) {
BOOST_LCAST_THROW_BAD_CAST(Source, Target);
}
BOOST_UNREACHABLE_RETURN(static_cast<Target>(0));
return boost::numeric::converter<
Target,
Source,
boost::numeric::conversion_traits<Target,Source>,
nothrow_overflow_handler<Source, Target>,
detect_precision_loss<Source, Target>
>::convert(arg);
}
};
@@ -2012,25 +2012,17 @@ namespace boost
{
static inline Target lexical_cast_impl(const Source &arg)
{
try{
typedef boost::numeric::converter<
Target,
Source,
boost::numeric::conversion_traits<Target,Source>,
boost::numeric::def_overflow_handler,
throw_on_precision_loss<Source>
> Converter ;
typedef boost::numeric::converter<
Target,
Source,
boost::numeric::conversion_traits<Target,Source>,
nothrow_overflow_handler<Source, Target>,
detect_precision_loss<Source, Target>
> converter_t;
bool has_minus = ( arg < 0);
if ( has_minus ) {
return static_cast<Target>(-Converter::convert(-arg));
} else {
return Converter::convert(arg);
}
} catch( ::boost::numeric::bad_numeric_cast const& ) {
BOOST_LCAST_THROW_BAD_CAST(Source, Target);
}
BOOST_UNREACHABLE_RETURN(static_cast<Target>(0));
return (
arg < 0 ? -converter_t::convert(-arg) : converter_t::convert(arg)
);
}
};

View File

@@ -39,5 +39,8 @@ test-suite conversion
[ compile lexical_cast_typedefed_wchar_test.cpp : <toolset>msvc:<nowchar>on ]
[ run lexical_cast_typedefed_wchar_test_runtime.cpp ../../test/build//boost_unit_test_framework/<link>static : : : <toolset>msvc:<nowchar>on ]
[ run lexical_cast_no_locale_test.cpp ../../test/build//boost_unit_test_framework/<link>static : : : <define>BOOST_NO_STD_LOCALE ]
[ run lexical_cast_no_exceptions_test.cpp ../../test/build//boost_unit_test_framework/<link>static : : : <define>BOOST_NO_EXCEPTIONS ]
;
#Add missing flags, when numeric_cast compilation with exceptions disabled will be fixed:
# [ run lexical_cast_no_exceptions_test.cpp ../../test/build//boost_unit_test_framework/<link>static : : : <define>BOOST_NO_EXCEPTIONS <toolset>gcc:<cflags>-fno-exceptions ]

View File

@@ -0,0 +1,95 @@
// Unit test for boost::lexical_cast.
//
// See http://www.boost.org for most recent version, including documentation.
//
// Copyright Antony Polukhin, 2012.
//
// 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).
#include <boost/config.hpp>
#if defined(__INTEL_COMPILER)
#pragma warning(disable: 193 383 488 981 1418 1419)
#elif defined(BOOST_MSVC)
#pragma warning(disable: 4097 4100 4121 4127 4146 4244 4245 4511 4512 4701 4800)
#endif
#include <boost/lexical_cast.hpp>
#include <boost/test/unit_test.hpp>
#include <boost/range/iterator_range.hpp>
#ifndef BOOST_NO_EXCEPTIONS
#error "This test must be compiled with -DBOOST_NO_EXCEPTIONS"
#endif
bool g_was_exception = false;
namespace boost {
void throw_exception(std::exception const & ) {
g_was_exception = true;
}
}
using namespace boost;
struct Escape
{
Escape(){}
Escape(const std::string& s)
: str_(s)
{}
std::string str_;
};
inline std::ostream& operator<< (std::ostream& o, const Escape& rhs)
{
return o << rhs.str_;
}
inline std::istream& operator>> (std::istream& i, Escape& rhs)
{
return i >> rhs.str_;
}
void test_exceptions_off()
{
Escape v("");
g_was_exception = false;
lexical_cast<char>(v);
BOOST_CHECK(g_was_exception);
g_was_exception = false;
lexical_cast<unsigned char>(v);
BOOST_CHECK(g_was_exception);
v = lexical_cast<Escape>(100);
BOOST_CHECK_EQUAL(lexical_cast<int>(v), 100);
BOOST_CHECK_EQUAL(lexical_cast<unsigned int>(v), 100u);
v = lexical_cast<Escape>(0.0);
BOOST_CHECK_EQUAL(lexical_cast<double>(v), 0.0);
BOOST_CHECK_EQUAL(lexical_cast<short>(100), 100);
BOOST_CHECK_EQUAL(lexical_cast<float>(0.0), 0.0);
g_was_exception = false;
lexical_cast<short>(700000);
BOOST_CHECK(g_was_exception);
}
unit_test::test_suite *init_unit_test_suite(int, char *[])
{
unit_test::test_suite *suite =
BOOST_TEST_SUITE("lexical_cast. Testing with BOOST_NO_EXCEPTIONS");
suite->add(BOOST_TEST_CASE(&test_exceptions_off));
return suite;
}