forked from boostorg/conversion
Fixes #5417. Much better performance on casts to integral types.
Adds more tests for overflow detection. Workaround for bugs of vc8 (lexical_cast_vc8_bug_test.cpp now passes) Fixes some inspection errors. [SVN r72056]
This commit is contained in:
@ -577,6 +577,84 @@ namespace boost
|
||||
}
|
||||
}
|
||||
|
||||
namespace detail // lcast_ret_unsigned
|
||||
{
|
||||
template<class Traits, class T, class CharT>
|
||||
inline bool lcast_ret_unsigned(T& value, const CharT* const begin, const CharT* end)
|
||||
{
|
||||
#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
|
||||
BOOST_STATIC_ASSERT(!std::numeric_limits<T>::is_signed);
|
||||
#endif
|
||||
typedef typename Traits::int_type int_type;
|
||||
CharT const czero = lcast_char_constants<CharT>::zero;
|
||||
--end;
|
||||
value = 0;
|
||||
|
||||
if ( *end < czero || *end >= czero + 10 || begin > end)
|
||||
return false;
|
||||
value = *end - czero;
|
||||
--end;
|
||||
T multiplier = 1;
|
||||
|
||||
#ifndef BOOST_LEXICAL_CAST_ASSUME_C_LOCALE
|
||||
// TODO: use BOOST_NO_STD_LOCALE
|
||||
std::locale loc;
|
||||
typedef std::numpunct<CharT> numpunct;
|
||||
numpunct const& np = BOOST_USE_FACET(numpunct, loc);
|
||||
std::string const& grouping = np.grouping();
|
||||
std::string::size_type const grouping_size = grouping.size();
|
||||
|
||||
/* According to [22.2.2.1.2] of Programming languages — C++ we MUST check for correct grouping */
|
||||
if (grouping_size)
|
||||
{
|
||||
unsigned char current_grouping = 0;
|
||||
CharT const thousands_sep = grouping_size ? np.thousands_sep() : 0;
|
||||
char remained = grouping[current_grouping] - 1;
|
||||
|
||||
for(;end>=begin; --end)
|
||||
{
|
||||
if (remained) {
|
||||
T const new_sub_value = multiplier * 10 * (*end - czero);
|
||||
|
||||
if (*end < czero || *end >= czero + 10
|
||||
/* detecting overflow */
|
||||
|| new_sub_value/10 != multiplier * (*end - czero)
|
||||
|| static_cast<T>((std::numeric_limits<T>::max)()-new_sub_value) < value
|
||||
)
|
||||
return false;
|
||||
|
||||
value += new_sub_value;
|
||||
multiplier *= 10;
|
||||
--remained;
|
||||
} else {
|
||||
if ( !Traits::eq(*end, thousands_sep) || begin == end ) return false;
|
||||
if (current_grouping < grouping_size-1 ) ++current_grouping;
|
||||
remained = grouping[current_grouping];
|
||||
}
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
while ( begin <= end )
|
||||
{
|
||||
T const new_sub_value = multiplier * 10 * (*end - czero);
|
||||
|
||||
if (*end < czero || *end >= czero + 10
|
||||
/* detecting overflow */
|
||||
|| new_sub_value/10 != multiplier * (*end - czero)
|
||||
|| static_cast<T>((std::numeric_limits<T>::max)()-new_sub_value) < value
|
||||
)
|
||||
return false;
|
||||
|
||||
value += new_sub_value;
|
||||
multiplier *= 10;
|
||||
--end;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
namespace detail // stream wrapper for handling lexical conversions
|
||||
{
|
||||
template<typename Target, typename Source, typename Traits>
|
||||
@ -762,8 +840,130 @@ namespace boost
|
||||
bool operator<<(double);
|
||||
bool operator<<(long double);
|
||||
|
||||
private:
|
||||
|
||||
template <typename Type>
|
||||
bool input_operator_helper_unsigned(Type& output)
|
||||
{
|
||||
CharT const minus = lcast_char_constants<CharT>::minus;
|
||||
bool const has_minus = Traits::eq(minus,*start);
|
||||
bool const succeed = lcast_ret_unsigned<Traits>(output, has_minus ? start+1 : start, finish);
|
||||
#if (defined _MSC_VER)
|
||||
# pragma warning( push )
|
||||
// C4146: unary minus operator applied to unsigned type, result still unsigned
|
||||
# pragma warning( disable : 4146 )
|
||||
#elif defined( __BORLANDC__ )
|
||||
# pragma option push -w-8041
|
||||
#endif
|
||||
if (has_minus) output = static_cast<Type>(-output);
|
||||
#if (defined _MSC_VER)
|
||||
# pragma warning( pop )
|
||||
#elif defined( __BORLANDC__ )
|
||||
# pragma option pop
|
||||
#endif
|
||||
return succeed;
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
bool input_operator_helper_signed(Type& output)
|
||||
{
|
||||
CharT const minus = lcast_char_constants<CharT>::minus;
|
||||
typedef BOOST_DEDUCED_TYPENAME make_unsigned<Type>::type utype;
|
||||
utype out_tmp =0;
|
||||
bool const has_minus = Traits::eq(minus,*start);
|
||||
bool succeed = lcast_ret_unsigned<Traits>(out_tmp, has_minus ? start+1 : start, finish);
|
||||
if (has_minus) {
|
||||
#if (defined _MSC_VER)
|
||||
# pragma warning( push )
|
||||
// C4146: unary minus operator applied to unsigned type, result still unsigned
|
||||
# pragma warning( disable : 4146 )
|
||||
#elif defined( __BORLANDC__ )
|
||||
# pragma option push -w-8041
|
||||
#endif
|
||||
utype const comp_val = static_cast<utype>(-(std::numeric_limits<Type>::min)());
|
||||
succeed = succeed && out_tmp<=comp_val;
|
||||
output = -out_tmp;
|
||||
#if (defined _MSC_VER)
|
||||
# pragma warning( pop )
|
||||
#elif defined( __BORLANDC__ )
|
||||
# pragma option pop
|
||||
#endif
|
||||
} else {
|
||||
utype const comp_val = static_cast<utype>((std::numeric_limits<Type>::max)());
|
||||
succeed = succeed && out_tmp<=comp_val;
|
||||
output = out_tmp;
|
||||
}
|
||||
return succeed;
|
||||
}
|
||||
|
||||
public: // input
|
||||
|
||||
bool operator>>(unsigned short& output)
|
||||
{
|
||||
return input_operator_helper_unsigned(output);
|
||||
}
|
||||
|
||||
bool operator>>(unsigned int& output)
|
||||
{
|
||||
return input_operator_helper_unsigned(output);
|
||||
}
|
||||
|
||||
bool operator>>(unsigned long int& output)
|
||||
{
|
||||
return input_operator_helper_unsigned(output);
|
||||
}
|
||||
|
||||
bool operator>>(short& output)
|
||||
{
|
||||
return input_operator_helper_signed(output);
|
||||
}
|
||||
|
||||
bool operator>>(int& output)
|
||||
{
|
||||
return input_operator_helper_signed(output);
|
||||
}
|
||||
|
||||
bool operator>>(long int& output)
|
||||
{
|
||||
return input_operator_helper_signed(output);
|
||||
}
|
||||
|
||||
|
||||
#if defined(BOOST_HAS_LONG_LONG)
|
||||
bool operator>>( boost::ulong_long_type& output)
|
||||
{
|
||||
return input_operator_helper_unsigned(output);
|
||||
}
|
||||
|
||||
bool operator>>(boost::long_long_type& output)
|
||||
{
|
||||
return input_operator_helper_signed(output);
|
||||
}
|
||||
|
||||
#elif defined(BOOST_HAS_MS_INT64)
|
||||
bool operator>>(unsigned __int64& output)
|
||||
{
|
||||
return input_operator_helper_unsigned(output);
|
||||
}
|
||||
|
||||
bool operator>>(__int64& output)
|
||||
{
|
||||
return input_operator_helper_signed(output);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
bool operator>>(bool& output)
|
||||
{
|
||||
output = (start[0] == lcast_char_constants<CharT>::zero + 1);
|
||||
return finish-start==1
|
||||
&& (
|
||||
start[0] == lcast_char_constants<CharT>::zero
|
||||
|| start[0] == lcast_char_constants<CharT>::zero + 1
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// Generic istream-based algorithm.
|
||||
// lcast_streambuf_for_target<InputStreamable>::value is true.
|
||||
template<typename InputStreamable>
|
||||
@ -1059,23 +1259,17 @@ namespace boost
|
||||
template<class Target>
|
||||
struct lcast_streambuf_for_target
|
||||
{
|
||||
BOOST_STATIC_CONSTANT(bool, value = true);
|
||||
BOOST_STATIC_CONSTANT(bool, value =
|
||||
(
|
||||
::boost::type_traits::ice_or<
|
||||
::boost::type_traits::ice_not< is_integral<Target>::value >::value,
|
||||
is_same<Target, signed char>::value,
|
||||
is_same<Target, unsigned char>::value
|
||||
>::value
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
template<>
|
||||
struct lcast_streambuf_for_target<char>
|
||||
{
|
||||
BOOST_STATIC_CONSTANT(bool, value = false);
|
||||
};
|
||||
|
||||
#if !defined(BOOST_LCAST_NO_WCHAR_T) && !defined(BOOST_NO_INTRINSIC_WCHAR_T)
|
||||
template<>
|
||||
struct lcast_streambuf_for_target<wchar_t>
|
||||
{
|
||||
BOOST_STATIC_CONSTANT(bool, value = false);
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||
template<class Traits, class Alloc>
|
||||
struct lcast_streambuf_for_target<
|
||||
@ -1328,7 +1522,7 @@ namespace boost
|
||||
> Converter ;
|
||||
|
||||
return Converter::convert(arg);
|
||||
} catch(...) {
|
||||
} catch( ::boost::numeric::bad_numeric_cast const& ) {
|
||||
BOOST_LCAST_THROW_BAD_CAST(Source, Target);
|
||||
}
|
||||
}
|
||||
@ -1354,7 +1548,7 @@ namespace boost
|
||||
} else {
|
||||
return Converter::convert(arg);
|
||||
}
|
||||
} catch(...) {
|
||||
} catch( ::boost::numeric::bad_numeric_cast const& ) {
|
||||
BOOST_LCAST_THROW_BAD_CAST(Source, Target);
|
||||
}
|
||||
}
|
||||
|
@ -267,7 +267,8 @@ Eliminate an overhead of <code>std::locale</code> if your program runs in the "C
|
||||
<h2><a name="changes">Changes</a></h2>
|
||||
<h3>May 2011:</h3>
|
||||
<ul type="square">
|
||||
<li>Better performance for conversions from arithmetic type to arithmetic type.</li>
|
||||
<li>Better performance and less memory usage for conversions to arithmetic types.</li>
|
||||
<li>Better performance and less memory usage for conversions from arithmetic type to arithmetic type.</li>
|
||||
<li>Directly construct <code>Target</code> from <code>Source</code> on some conversions (like conversions from string to string, from char array to string, from char to char and others).</li>
|
||||
</ul>
|
||||
<h3>August, October 2006:</h3>
|
||||
@ -317,7 +318,7 @@ Eliminate an overhead of <code>std::locale</code> if your program runs in the "C
|
||||
<div align="right"><small><i>Copyright © Antony Polukhin, 2011</i></small></div>
|
||||
<div align="right"><small><i>
|
||||
Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
file LICENSE_1_0.txt or copy at <a href="/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>)</i></small>
|
||||
file LICENSE_1_0.txt or copy at <a href="../../LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>)</i></small>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -4,6 +4,7 @@
|
||||
//
|
||||
// Copyright Terje Sletteb and Kevlin Henney, 2005.
|
||||
// Copyright Alexander Nasonov, 2006.
|
||||
// Copyright Antony Polukhin, 2011.
|
||||
//
|
||||
// Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
@ -32,6 +33,7 @@
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <boost/test/floating_point_comparison.hpp>
|
||||
|
||||
#include <boost/type_traits/integral_promotion.hpp>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
@ -235,6 +237,14 @@ void test_conversion_to_bool()
|
||||
BOOST_CHECK_EQUAL(false, lexical_cast<bool>("0"));
|
||||
BOOST_CHECK_EQUAL(true, lexical_cast<bool>(std::string("1")));
|
||||
BOOST_CHECK_EQUAL(false, lexical_cast<bool>(std::string("0")));
|
||||
|
||||
BOOST_CHECK_THROW(lexical_cast<bool>(1.0001L), bad_lexical_cast);
|
||||
BOOST_CHECK_THROW(lexical_cast<bool>(2), bad_lexical_cast);
|
||||
BOOST_CHECK_THROW(lexical_cast<bool>(2u), bad_lexical_cast);
|
||||
BOOST_CHECK_THROW(lexical_cast<bool>(-1), bad_lexical_cast);
|
||||
BOOST_CHECK_THROW(lexical_cast<bool>(-2), bad_lexical_cast);
|
||||
|
||||
|
||||
BOOST_CHECK_THROW(
|
||||
lexical_cast<bool>(std::string("")), bad_lexical_cast);
|
||||
BOOST_CHECK_THROW(
|
||||
@ -564,25 +574,46 @@ void test_conversion_from_string_to_integral(CharT)
|
||||
BOOST_CHECK_EQUAL(lexical_cast<T>(s), min_val);
|
||||
if(limits::is_signed)
|
||||
{
|
||||
#if defined(BOOST_MSVC) && BOOST_MSVC == 1400
|
||||
// VC++ 8.0 bug, see libs/conversion/test/lexical_cast_vc8_bug_test.cpp
|
||||
if(sizeof(T) < sizeof(boost::intmax_t))
|
||||
#endif
|
||||
{
|
||||
BOOST_CHECK_THROW(lexical_cast<T>(s + zero), bad_lexical_cast);
|
||||
BOOST_CHECK_THROW(lexical_cast<T>(s + nine), bad_lexical_cast);
|
||||
}
|
||||
BOOST_CHECK_THROW(lexical_cast<T>(s + zero), bad_lexical_cast);
|
||||
BOOST_CHECK_THROW(lexical_cast<T>(s + nine), bad_lexical_cast);
|
||||
}
|
||||
|
||||
s = to_str<CharT>(max_val);
|
||||
BOOST_CHECK_EQUAL(lexical_cast<T>(s), max_val);
|
||||
#if defined(BOOST_MSVC) && BOOST_MSVC == 1400
|
||||
// VC++ 8.0 bug, see libs/conversion/test/lexical_cast_vc8_bug_test.cpp
|
||||
if(sizeof(T) != sizeof(boost::intmax_t))
|
||||
#endif
|
||||
{
|
||||
BOOST_CHECK_THROW(lexical_cast<T>(s + zero), bad_lexical_cast);
|
||||
BOOST_CHECK_THROW(lexical_cast<T>(s + nine), bad_lexical_cast);
|
||||
|
||||
s = to_str<CharT>(max_val);
|
||||
for (int i =1; i <=10; ++i) {
|
||||
s[s.size()-1] += 1;
|
||||
BOOST_CHECK_THROW(lexical_cast<T>( s ), bad_lexical_cast);
|
||||
}
|
||||
|
||||
s = to_str<CharT>(max_val);
|
||||
std::locale loc;
|
||||
typedef std::numpunct<char> numpunct;
|
||||
if ( BOOST_USE_FACET(numpunct, loc).grouping().empty() ) {
|
||||
// Following tests work well for locale C
|
||||
BOOST_CHECK_EQUAL(lexical_cast<T>(to_str<CharT>(0)+s), max_val);
|
||||
BOOST_CHECK_EQUAL(lexical_cast<T>(to_str<CharT>(0)+to_str<CharT>(0)+s), max_val);
|
||||
BOOST_CHECK_EQUAL(lexical_cast<T>(to_str<CharT>(0)+to_str<CharT>(0)+to_str<CharT>(0)+s), max_val);
|
||||
}
|
||||
|
||||
for (int i =1; i <=256; ++i) {
|
||||
BOOST_CHECK_THROW(lexical_cast<T>( to_str<CharT>(i)+s ), bad_lexical_cast);
|
||||
}
|
||||
|
||||
typedef BOOST_DEDUCED_TYPENAME boost::integral_promotion<T>::type promoted;
|
||||
if ( !(boost::is_same<T, promoted>::value) )
|
||||
{
|
||||
promoted prom = max_val;
|
||||
s = to_str<CharT>(max_val);
|
||||
for (int i =1; i <=256; ++i) {
|
||||
BOOST_CHECK_THROW(lexical_cast<T>( to_str<CharT>(prom+i) ), bad_lexical_cast);
|
||||
BOOST_CHECK_THROW(lexical_cast<T>( to_str<CharT>(i)+s ), bad_lexical_cast);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(limits::digits <= 16 && lcast_test_small_integral_types_completely)
|
||||
@ -627,6 +658,18 @@ void test_conversion_from_string_to_integral(CharT)
|
||||
template<class T>
|
||||
void test_conversion_from_to_integral_for_locale()
|
||||
{
|
||||
std::locale current_locale;
|
||||
typedef std::numpunct<char> numpunct;
|
||||
numpunct const& np = BOOST_USE_FACET(numpunct, current_locale);
|
||||
if ( !np.grouping().empty() )
|
||||
{
|
||||
BOOST_CHECK_THROW(
|
||||
lexical_cast<T>( std::string("100") + np.thousands_sep() + np.thousands_sep() + "0" )
|
||||
, bad_lexical_cast);
|
||||
BOOST_CHECK_THROW(lexical_cast<T>( std::string("100") + np.thousands_sep() ), bad_lexical_cast);
|
||||
BOOST_CHECK_THROW(lexical_cast<T>( np.thousands_sep() + std::string("100") ), bad_lexical_cast);
|
||||
}
|
||||
|
||||
test_conversion_from_integral_to_integral<T>();
|
||||
test_conversion_from_integral_to_string<T>('0');
|
||||
test_conversion_from_string_to_integral<T>('0');
|
||||
@ -773,18 +816,6 @@ void test_conversion_from_to_uintmax_t()
|
||||
test_conversion_from_to_integral<boost::uintmax_t>();
|
||||
}
|
||||
|
||||
#if defined(BOOST_HAS_LONG_LONG)
|
||||
|
||||
void test_conversion_from_to_longlong()
|
||||
{
|
||||
test_conversion_from_to_integral<boost::long_long_type>();
|
||||
}
|
||||
|
||||
void test_conversion_from_to_ulonglong()
|
||||
{
|
||||
test_conversion_from_to_integral<boost::ulong_long_type>();
|
||||
}
|
||||
|
||||
void test_conversion_from_to_float()
|
||||
{
|
||||
test_conversion_from_to_float<float>();
|
||||
@ -798,7 +829,19 @@ void test_conversion_from_to_long_double()
|
||||
test_conversion_from_to_float<long double>();
|
||||
}
|
||||
|
||||
#elif defined(LCAST_TEST_LONGLONG)
|
||||
#if defined(BOOST_HAS_LONG_LONG)
|
||||
|
||||
void test_conversion_from_to_longlong()
|
||||
{
|
||||
test_conversion_from_to_integral<boost::long_long_type>();
|
||||
}
|
||||
|
||||
void test_conversion_from_to_ulonglong()
|
||||
{
|
||||
test_conversion_from_to_integral<boost::ulong_long_type>();
|
||||
}
|
||||
|
||||
#elif defined(BOOST_HAS_MS_INT64)
|
||||
|
||||
void test_conversion_from_to_longlong()
|
||||
{
|
||||
|
@ -1,3 +1,17 @@
|
||||
// Unit test for boost::lexical_cast.
|
||||
//
|
||||
// See http://www.boost.org for most recent version, including documentation.
|
||||
//
|
||||
// Copyright Alexander Nasonov, 2007.
|
||||
//
|
||||
// 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).
|
||||
//
|
||||
// This tests now must pass on vc8, because lexical_cast
|
||||
// implementation has changed and it does not use stringstream for casts
|
||||
// to integral types
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
|
Reference in New Issue
Block a user