forked from boostorg/conversion
Updates #5800 (partially fix lexical cast compilation with disabled exceptions)
[SVN r77116]
This commit is contained in:
@@ -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).
|
||||
|
@@ -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)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -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 ]
|
||||
|
||||
|
95
test/lexical_cast_no_exceptions_test.cpp
Executable file
95
test/lexical_cast_no_exceptions_test.cpp
Executable 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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user