mirror of
https://github.com/boostorg/conversion.git
synced 2025-08-03 22:44:32 +02:00
Merge branch 'develop'
This commit is contained in:
@@ -3,7 +3,7 @@
|
|||||||
[version 1.0]
|
[version 1.0]
|
||||||
[copyright 2000-2005 Kevlin Henney]
|
[copyright 2000-2005 Kevlin Henney]
|
||||||
[copyright 2006-2010 Alexander Nasonov]
|
[copyright 2006-2010 Alexander Nasonov]
|
||||||
[copyright 2011-2013 Antony Polukhin]
|
[copyright 2011-2014 Antony Polukhin]
|
||||||
[category String and text processing]
|
[category String and text processing]
|
||||||
[category Miscellaneous]
|
[category Miscellaneous]
|
||||||
[license
|
[license
|
||||||
@@ -68,7 +68,17 @@ Library features defined in [@boost:boost/lexical_cast.hpp boost/lexical_cast.hp
|
|||||||
|
|
||||||
template <typename Target>
|
template <typename Target>
|
||||||
Target lexical_cast(const AnyCharacterType* chars, std::size_t count);
|
Target lexical_cast(const AnyCharacterType* chars, std::size_t count);
|
||||||
}
|
|
||||||
|
namespace conversion
|
||||||
|
{
|
||||||
|
template<typename Target, typename Source>
|
||||||
|
bool try_lexical_convert(const Source& arg, Target& result);
|
||||||
|
|
||||||
|
template <typename AnyCharacterType, typename Target>
|
||||||
|
bool try_lexical_convert(const AnyCharacterType* chars, std::size_t count, Target& result);
|
||||||
|
|
||||||
|
} // namespace conversion
|
||||||
|
} // namespace boost
|
||||||
``
|
``
|
||||||
|
|
||||||
[section lexical_cast]
|
[section lexical_cast]
|
||||||
@@ -122,6 +132,37 @@ Where a higher degree of control is required over conversions, `std::stringstrea
|
|||||||
Exception used to indicate runtime lexical_cast failure.
|
Exception used to indicate runtime lexical_cast failure.
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
|
[section try_lexical_convert]
|
||||||
|
`boost::lexical_cast` remains the main interface for lexical conversions. It must be used by default in most cases. However
|
||||||
|
some developers wish to make their own conversion functions, reusing all the optimizations of the `boost::lexical_cast`.
|
||||||
|
That's where the `boost::conversion::try_lexical_convert` function steps in.
|
||||||
|
|
||||||
|
`try_lexical_convert` returns `true` if conversion succeeded, otherwise returns `false`. If conversion
|
||||||
|
failed and `false` was returned, state of `result` output variable is undefined.
|
||||||
|
|
||||||
|
Actually, `boost::lexical_cast` is implemented using `try_lexical_convert`:
|
||||||
|
``
|
||||||
|
template <typename Target, typename Source>
|
||||||
|
inline Target lexical_cast(const Source &arg)
|
||||||
|
{
|
||||||
|
Target result;
|
||||||
|
|
||||||
|
if (!conversion::try_lexical_convert(arg, result))
|
||||||
|
throw bad_lexical_cast();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
``
|
||||||
|
|
||||||
|
`try_lexical_convert` relaxes the CopyConstructible and DefaultConstructible requirements for `Target` type.
|
||||||
|
Following requirements for `Target` and `Source` remain:
|
||||||
|
|
||||||
|
* Source must be OutputStreamable, meaning that an `operator<<` is defined that takes a `std::ostream` or `std::wostream` object on the left hand side and an instance of the argument type on the right.
|
||||||
|
* Target must be InputStreamable, meaning that an `operator>>` is defined that takes a `std::istream` or `std::wistream` object on the left hand side and an instance of the result type on the right.
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
[section Frequently Asked Questions]
|
[section Frequently Asked Questions]
|
||||||
@@ -194,6 +235,10 @@ limitation of compiler options that you use.
|
|||||||
|
|
||||||
[section Changes]
|
[section Changes]
|
||||||
|
|
||||||
|
* [*boost 1.56.0 :]
|
||||||
|
|
||||||
|
* Added `boost::conversion::try_lexical_convert` functions.
|
||||||
|
|
||||||
* [*boost 1.54.0 :]
|
* [*boost 1.54.0 :]
|
||||||
|
|
||||||
* Fix some issues with `boost::int128_type` and `boost::uint128_type` conversions. Notify user at compile time
|
* Fix some issues with `boost::int128_type` and `boost::uint128_type` conversions. Notify user at compile time
|
||||||
|
@@ -19,7 +19,7 @@
|
|||||||
// Beman Dawes, Dave Abrahams, Daryle Walker, Peter Dimov,
|
// Beman Dawes, Dave Abrahams, Daryle Walker, Peter Dimov,
|
||||||
// Alexander Nasonov, Antony Polukhin, Justin Viiret, Michael Hofmann,
|
// Alexander Nasonov, Antony Polukhin, Justin Viiret, Michael Hofmann,
|
||||||
// Cheng Yang, Matthew Bradbury, David W. Birdsall, Pavel Korzh and other Boosters
|
// Cheng Yang, Matthew Bradbury, David W. Birdsall, Pavel Korzh and other Boosters
|
||||||
// when: November 2000, March 2003, June 2005, June 2006, March 2011 - 2013
|
// when: November 2000, March 2003, June 2005, June 2006, March 2011 - 2014
|
||||||
|
|
||||||
#include <boost/config.hpp>
|
#include <boost/config.hpp>
|
||||||
#if defined(BOOST_NO_STRINGSTREAM) || defined(BOOST_NO_STD_WSTRING)
|
#if defined(BOOST_NO_STRINGSTREAM) || defined(BOOST_NO_STD_WSTRING)
|
||||||
@@ -1666,7 +1666,6 @@ namespace boost {
|
|||||||
return ((*this) << reinterpret_cast<boost::array<C, N> const& >(input));
|
return ((*this) << reinterpret_cast<boost::array<C, N> const& >(input));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
template <class InStreamable>
|
template <class InStreamable>
|
||||||
bool operator<<(const InStreamable& input) { return shl_input_streamable(input); }
|
bool operator<<(const InStreamable& input) { return shl_input_streamable(input); }
|
||||||
};
|
};
|
||||||
@@ -2058,9 +2057,7 @@ namespace boost {
|
|||||||
{};
|
{};
|
||||||
|
|
||||||
template<typename Target, typename Source>
|
template<typename Target, typename Source>
|
||||||
struct lexical_cast_do_cast
|
struct lexical_converter_impl
|
||||||
{
|
|
||||||
static inline Target lexical_cast_impl(const Source& arg)
|
|
||||||
{
|
{
|
||||||
typedef lexical_cast_stream_traits<Source, Target> stream_trait;
|
typedef lexical_cast_stream_traits<Source, Target> stream_trait;
|
||||||
|
|
||||||
@@ -2076,52 +2073,58 @@ namespace boost {
|
|||||||
BOOST_DEDUCED_TYPENAME stream_trait::traits
|
BOOST_DEDUCED_TYPENAME stream_trait::traits
|
||||||
> o_interpreter_type;
|
> o_interpreter_type;
|
||||||
|
|
||||||
// Target type must be default constructible
|
static inline bool try_convert(const Source& arg, Target& result) {
|
||||||
Target result;
|
|
||||||
|
|
||||||
i_interpreter_type i_interpreter;
|
i_interpreter_type i_interpreter;
|
||||||
|
|
||||||
// Disabling ADL, by directly specifying operators.
|
// Disabling ADL, by directly specifying operators.
|
||||||
const bool input_ok = (i_interpreter.operator <<(arg));
|
if (!(i_interpreter.operator <<(arg)))
|
||||||
|
return false;
|
||||||
|
|
||||||
o_interpreter_type out(i_interpreter.cbegin(), i_interpreter.cend());
|
o_interpreter_type out(i_interpreter.cbegin(), i_interpreter.cend());
|
||||||
|
|
||||||
// Disabling ADL, by directly specifying operators.
|
// Disabling ADL, by directly specifying operators.
|
||||||
if(!input_ok || !(out.operator >>(result)))
|
if(!(out.operator >>(result)))
|
||||||
BOOST_LCAST_THROW_BAD_CAST(Source, Target);
|
return false;
|
||||||
|
|
||||||
return result;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Source>
|
template <typename Target, typename Source>
|
||||||
struct lexical_cast_copy
|
struct copy_converter_impl
|
||||||
{
|
{
|
||||||
static inline const Source& lexical_cast_impl(const Source &arg) BOOST_NOEXCEPT
|
// MSVC fail to forward an array (DevDiv#555157 "SILENT BAD CODEGEN triggered by perfect forwarding",
|
||||||
{
|
// fixed in 2013 RTM).
|
||||||
return arg;
|
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && (!defined(BOOST_MSVC) || BOOST_MSVC >= 1800)
|
||||||
|
template <class T>
|
||||||
|
static inline bool try_convert(T&& arg, Target& result) {
|
||||||
|
result = static_cast<T&&>(arg); // eqaul to `result = std::forward<T>(arg);`
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
static inline bool try_convert(const Source& arg, Target& result) {
|
||||||
|
result = arg;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class Source, class Target >
|
template <class Source >
|
||||||
struct detect_precision_loss
|
struct detect_precision_loss
|
||||||
{
|
{
|
||||||
typedef boost::numeric::Trunc<Source> Rounder;
|
|
||||||
typedef Source source_type;
|
typedef Source source_type;
|
||||||
|
typedef boost::numeric::Trunc<Source> Rounder;
|
||||||
typedef BOOST_DEDUCED_TYPENAME mpl::if_<
|
typedef BOOST_DEDUCED_TYPENAME mpl::if_<
|
||||||
boost::is_arithmetic<Source>, Source, Source const&
|
boost::is_arithmetic<Source>, Source, Source const&
|
||||||
>::type argument_type ;
|
>::type argument_type ;
|
||||||
|
|
||||||
static source_type nearbyint ( argument_type s )
|
static inline source_type nearbyint(argument_type s, bool& is_ok) BOOST_NOEXCEPT {
|
||||||
{
|
|
||||||
const source_type near_int = Rounder::nearbyint(s);
|
const source_type near_int = Rounder::nearbyint(s);
|
||||||
if (near_int) {
|
if (near_int && is_ok) {
|
||||||
const source_type orig_div_round = s / near_int;
|
const source_type orig_div_round = s / near_int;
|
||||||
const source_type eps = std::numeric_limits<source_type>::epsilon();
|
const source_type eps = std::numeric_limits<source_type>::epsilon();
|
||||||
|
|
||||||
if ((orig_div_round > 1 ? orig_div_round - 1 : 1 - orig_div_round) > eps)
|
is_ok = !((orig_div_round > 1 ? orig_div_round - 1 : 1 - orig_div_round) > eps);
|
||||||
BOOST_LCAST_THROW_BAD_CAST(Source, Target);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
@@ -2130,53 +2133,72 @@ namespace boost {
|
|||||||
typedef typename Rounder::round_style round_style;
|
typedef typename Rounder::round_style round_style;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class Source, class Target >
|
template <typename Base, class Source>
|
||||||
|
struct fake_precision_loss: public Base
|
||||||
|
{
|
||||||
|
typedef Source source_type ;
|
||||||
|
typedef BOOST_DEDUCED_TYPENAME mpl::if_<
|
||||||
|
boost::is_arithmetic<Source>, Source, Source const&
|
||||||
|
>::type argument_type ;
|
||||||
|
|
||||||
|
static inline source_type nearbyint(argument_type s, bool& /*is_ok*/) BOOST_NOEXCEPT {
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct nothrow_overflow_handler
|
struct nothrow_overflow_handler
|
||||||
{
|
{
|
||||||
void operator() ( boost::numeric::range_check_result r )
|
inline bool operator() ( boost::numeric::range_check_result r ) const BOOST_NOEXCEPT {
|
||||||
{
|
return (r == boost::numeric::cInRange);
|
||||||
if (r != boost::numeric::cInRange)
|
|
||||||
BOOST_LCAST_THROW_BAD_CAST(Source, Target);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Target, typename Source>
|
template <typename Target, typename Source>
|
||||||
struct lexical_cast_dynamic_num_not_ignoring_minus
|
inline bool noexcept_numeric_convert(const Source& arg, Target& result) BOOST_NOEXCEPT {
|
||||||
{
|
typedef boost::numeric::converter<
|
||||||
static inline Target lexical_cast_impl(const Source &arg)
|
|
||||||
{
|
|
||||||
return boost::numeric::converter<
|
|
||||||
Target,
|
Target,
|
||||||
Source,
|
Source,
|
||||||
boost::numeric::conversion_traits<Target, Source >,
|
boost::numeric::conversion_traits<Target, Source >,
|
||||||
nothrow_overflow_handler<Source, Target>,
|
nothrow_overflow_handler,
|
||||||
detect_precision_loss<Source, Target>
|
detect_precision_loss<Source >
|
||||||
>::convert(arg);
|
> converter_orig_t;
|
||||||
|
|
||||||
|
typedef BOOST_DEDUCED_TYPENAME boost::mpl::if_c<
|
||||||
|
boost::is_base_of< detect_precision_loss<Source >, converter_orig_t >::value,
|
||||||
|
converter_orig_t,
|
||||||
|
fake_precision_loss<converter_orig_t, Source>
|
||||||
|
>::type converter_t;
|
||||||
|
|
||||||
|
bool res = nothrow_overflow_handler()(converter_t::out_of_range(arg));
|
||||||
|
result = converter_t::low_level_convert(converter_t::nearbyint(arg, res));
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Target, typename Source>
|
||||||
|
struct lexical_cast_dynamic_num_not_ignoring_minus
|
||||||
|
{
|
||||||
|
static inline bool try_convert(const Source &arg, Target& result) BOOST_NOEXCEPT {
|
||||||
|
return noexcept_numeric_convert<Target, Source >(arg, result);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Target, typename Source>
|
template <typename Target, typename Source>
|
||||||
struct lexical_cast_dynamic_num_ignoring_minus
|
struct lexical_cast_dynamic_num_ignoring_minus
|
||||||
{
|
{
|
||||||
static inline Target lexical_cast_impl(const Source &arg)
|
static inline bool try_convert(const Source &arg, Target& result) BOOST_NOEXCEPT {
|
||||||
{
|
|
||||||
typedef BOOST_DEDUCED_TYPENAME boost::mpl::eval_if_c<
|
typedef BOOST_DEDUCED_TYPENAME boost::mpl::eval_if_c<
|
||||||
boost::is_float<Source>::value,
|
boost::is_float<Source>::value,
|
||||||
boost::mpl::identity<Source>,
|
boost::mpl::identity<Source>,
|
||||||
boost::make_unsigned<Source>
|
boost::make_unsigned<Source>
|
||||||
>::type usource_t;
|
>::type usource_t;
|
||||||
|
|
||||||
typedef boost::numeric::converter<
|
if (arg < 0) {
|
||||||
Target,
|
const bool res = noexcept_numeric_convert<Target, usource_t>(0u - arg, result);
|
||||||
usource_t,
|
result = static_cast<Target>(0u - result);
|
||||||
boost::numeric::conversion_traits<Target,usource_t>,
|
return res;
|
||||||
nothrow_overflow_handler<usource_t, Target>,
|
} else {
|
||||||
detect_precision_loss<usource_t, Target>
|
return noexcept_numeric_convert<Target, usource_t>(arg, result);
|
||||||
> converter_t;
|
}
|
||||||
|
|
||||||
return (
|
|
||||||
arg < 0 ? static_cast<Target>(0u - converter_t::convert(0u - arg)) : converter_t::convert(arg)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -2199,10 +2221,9 @@ namespace boost {
|
|||||||
* and the result will be the two's complement.
|
* and the result will be the two's complement.
|
||||||
*/
|
*/
|
||||||
template <typename Target, typename Source>
|
template <typename Target, typename Source>
|
||||||
struct lexical_cast_dynamic_num
|
struct dynamic_num_converter_impl
|
||||||
{
|
|
||||||
static inline Target lexical_cast_impl(const Source &arg)
|
|
||||||
{
|
{
|
||||||
|
static inline bool try_convert(const Source &arg, Target& result) BOOST_NOEXCEPT {
|
||||||
typedef BOOST_DEDUCED_TYPENAME boost::mpl::if_c<
|
typedef BOOST_DEDUCED_TYPENAME boost::mpl::if_c<
|
||||||
boost::type_traits::ice_and<
|
boost::type_traits::ice_and<
|
||||||
boost::is_unsigned<Target>::value,
|
boost::is_unsigned<Target>::value,
|
||||||
@@ -2221,13 +2242,15 @@ namespace boost {
|
|||||||
lexical_cast_dynamic_num_not_ignoring_minus<Target, Source>
|
lexical_cast_dynamic_num_not_ignoring_minus<Target, Source>
|
||||||
>::type caster_type;
|
>::type caster_type;
|
||||||
|
|
||||||
return caster_type::lexical_cast_impl(arg);
|
return caster_type::try_convert(arg, result);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace conversion { namespace detail {
|
||||||
|
|
||||||
template <typename Target, typename Source>
|
template <typename Target, typename Source>
|
||||||
inline Target lexical_cast(const Source &arg)
|
inline bool try_lexical_convert(const Source& arg, Target& result)
|
||||||
{
|
{
|
||||||
typedef BOOST_DEDUCED_TYPENAME boost::detail::array_to_pointer_decay<Source>::type src;
|
typedef BOOST_DEDUCED_TYPENAME boost::detail::array_to_pointer_decay<Source>::type src;
|
||||||
|
|
||||||
@@ -2251,17 +2274,47 @@ namespace boost {
|
|||||||
// of `shall_we_copy_with_dynamic_check_t` and improve compilation times.
|
// of `shall_we_copy_with_dynamic_check_t` and improve compilation times.
|
||||||
typedef BOOST_DEDUCED_TYPENAME boost::mpl::if_c<
|
typedef BOOST_DEDUCED_TYPENAME boost::mpl::if_c<
|
||||||
shall_we_copy_t::value,
|
shall_we_copy_t::value,
|
||||||
boost::mpl::identity<boost::detail::lexical_cast_copy<src > >,
|
boost::mpl::identity<boost::detail::copy_converter_impl<Target, src > >,
|
||||||
boost::mpl::if_<
|
boost::mpl::if_<
|
||||||
shall_we_copy_with_dynamic_check_t,
|
shall_we_copy_with_dynamic_check_t,
|
||||||
boost::detail::lexical_cast_dynamic_num<Target, src >,
|
boost::detail::dynamic_num_converter_impl<Target, src >,
|
||||||
boost::detail::lexical_cast_do_cast<Target, src >
|
boost::detail::lexical_converter_impl<Target, src >
|
||||||
>
|
>
|
||||||
>::type caster_type_lazy;
|
>::type caster_type_lazy;
|
||||||
|
|
||||||
typedef BOOST_DEDUCED_TYPENAME caster_type_lazy::type caster_type;
|
typedef BOOST_DEDUCED_TYPENAME caster_type_lazy::type caster_type;
|
||||||
|
|
||||||
return caster_type::lexical_cast_impl(arg);
|
return caster_type::try_convert(arg, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Target, typename CharacterT>
|
||||||
|
inline bool try_lexical_convert(const CharacterT* chars, std::size_t count, Target& result)
|
||||||
|
{
|
||||||
|
BOOST_STATIC_ASSERT_MSG(
|
||||||
|
boost::detail::is_character<CharacterT>::value,
|
||||||
|
"This overload of try_lexical_convert is meant to be used only with arrays of characters."
|
||||||
|
);
|
||||||
|
return ::boost::conversion::detail::try_lexical_convert(
|
||||||
|
::boost::iterator_range<const CharacterT*>(chars, chars + count), result
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}} // namespace conversion::detail
|
||||||
|
|
||||||
|
namespace conversion {
|
||||||
|
// ADL barrier
|
||||||
|
using ::boost::conversion::detail::try_lexical_convert;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Target, typename Source>
|
||||||
|
inline Target lexical_cast(const Source &arg)
|
||||||
|
{
|
||||||
|
Target result;
|
||||||
|
|
||||||
|
if (!boost::conversion::detail::try_lexical_convert(arg, result))
|
||||||
|
BOOST_LCAST_THROW_BAD_CAST(Source, Target);
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Target>
|
template <typename Target>
|
||||||
@@ -2272,7 +2325,6 @@ namespace boost {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <typename Target>
|
template <typename Target>
|
||||||
inline Target lexical_cast(const unsigned char* chars, std::size_t count)
|
inline Target lexical_cast(const unsigned char* chars, std::size_t count)
|
||||||
{
|
{
|
||||||
@@ -2447,7 +2499,7 @@ namespace boost {
|
|||||||
|
|
||||||
// Copyright Kevlin Henney, 2000-2005.
|
// Copyright Kevlin Henney, 2000-2005.
|
||||||
// Copyright Alexander Nasonov, 2006-2010.
|
// Copyright Alexander Nasonov, 2006-2010.
|
||||||
// Copyright Antony Polukhin, 2011-2013.
|
// Copyright Antony Polukhin, 2011-2014.
|
||||||
//
|
//
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See
|
// Distributed under the Boost Software License, Version 1.0. (See
|
||||||
// accompanying file LICENSE_1_0.txt or copy at
|
// accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
@@ -62,6 +62,7 @@ test-suite conversion
|
|||||||
[ run lexical_cast_stream_traits_test.cpp ]
|
[ run lexical_cast_stream_traits_test.cpp ]
|
||||||
[ compile-fail lexical_cast_to_pointer_test.cpp ]
|
[ compile-fail lexical_cast_to_pointer_test.cpp ]
|
||||||
[ run lexical_cast_filesystem_test.cpp ../../filesystem/build//boost_filesystem/<link>static ]
|
[ run lexical_cast_filesystem_test.cpp ../../filesystem/build//boost_filesystem/<link>static ]
|
||||||
|
[ run lexical_cast_try_lexical_convert.cpp ]
|
||||||
;
|
;
|
||||||
|
|
||||||
# Assuring that examples compile and run. Adding sources from `example` directory to the `conversion` test suite.
|
# Assuring that examples compile and run. Adding sources from `example` directory to the `conversion` test suite.
|
||||||
|
@@ -111,7 +111,7 @@ void test_conversion_from_to_float_for_locale()
|
|||||||
#ifndef BOOST_LCAST_NO_WCHAR_T
|
#ifndef BOOST_LCAST_NO_WCHAR_T
|
||||||
#define CHECK_CLOSE_ABS_DIFF(VAL,PREFIX) \
|
#define CHECK_CLOSE_ABS_DIFF(VAL,PREFIX) \
|
||||||
converted_val = lexical_cast<test_t>(#VAL); \
|
converted_val = lexical_cast<test_t>(#VAL); \
|
||||||
BOOST_CHECK_CLOSE_FRACTION( (VAL ## L? VAL ## L : std::numeric_limits<test_t>::epsilon()), \
|
BOOST_CHECK_CLOSE_FRACTION( (static_cast<bool>(VAL ## L)? VAL ## L : std::numeric_limits<test_t>::epsilon()), \
|
||||||
(converted_val ? converted_val : std::numeric_limits<test_t>::epsilon()),\
|
(converted_val ? converted_val : std::numeric_limits<test_t>::epsilon()),\
|
||||||
std::numeric_limits<test_t>::epsilon() \
|
std::numeric_limits<test_t>::epsilon() \
|
||||||
); \
|
); \
|
||||||
@@ -120,7 +120,7 @@ void test_conversion_from_to_float_for_locale()
|
|||||||
#else
|
#else
|
||||||
#define CHECK_CLOSE_ABS_DIFF(VAL,TYPE) \
|
#define CHECK_CLOSE_ABS_DIFF(VAL,TYPE) \
|
||||||
converted_val = lexical_cast<test_t>(#VAL); \
|
converted_val = lexical_cast<test_t>(#VAL); \
|
||||||
BOOST_CHECK_CLOSE_FRACTION( (VAL ## L? VAL ## L : std::numeric_limits<test_t>::epsilon()), \
|
BOOST_CHECK_CLOSE_FRACTION( (static_cast<bool>(VAL ## L)? VAL ## L : std::numeric_limits<test_t>::epsilon()), \
|
||||||
(converted_val ? converted_val : std::numeric_limits<test_t>::epsilon()),\
|
(converted_val ? converted_val : std::numeric_limits<test_t>::epsilon()),\
|
||||||
std::numeric_limits<test_t>::epsilon() \
|
std::numeric_limits<test_t>::epsilon() \
|
||||||
);
|
);
|
||||||
|
78
test/lexical_cast_try_lexical_convert.cpp
Normal file
78
test/lexical_cast_try_lexical_convert.cpp
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
// Unit test for boost::lexical_cast.
|
||||||
|
//
|
||||||
|
// See http://www.boost.org for most recent version, including documentation.
|
||||||
|
//
|
||||||
|
// Copyright Antony Polukhin, 2014.
|
||||||
|
//
|
||||||
|
// 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>
|
||||||
|
|
||||||
|
#include <boost/lexical_cast.hpp>
|
||||||
|
#include <boost/test/unit_test.hpp>
|
||||||
|
|
||||||
|
using namespace boost::conversion;
|
||||||
|
|
||||||
|
void try_uncommon_cases()
|
||||||
|
{
|
||||||
|
std::string sres;
|
||||||
|
const bool res1 = try_lexical_convert(std::string("Test string"), sres);
|
||||||
|
BOOST_CHECK(res1);
|
||||||
|
BOOST_CHECK_EQUAL(sres, "Test string");
|
||||||
|
|
||||||
|
volatile int vires;
|
||||||
|
const bool res2 = try_lexical_convert(100, vires);
|
||||||
|
BOOST_CHECK(res2);
|
||||||
|
BOOST_CHECK_EQUAL(vires, 100);
|
||||||
|
|
||||||
|
const bool res3 = try_lexical_convert("Test string", sres);
|
||||||
|
BOOST_CHECK(res3);
|
||||||
|
BOOST_CHECK_EQUAL(sres, "Test string");
|
||||||
|
|
||||||
|
const bool res4 = try_lexical_convert("Test string", sizeof("Test string") - 1, sres);
|
||||||
|
BOOST_CHECK(res4);
|
||||||
|
BOOST_CHECK_EQUAL(sres, "Test string");
|
||||||
|
|
||||||
|
int ires;
|
||||||
|
BOOST_CHECK(!try_lexical_convert("Test string", ires));
|
||||||
|
BOOST_CHECK(!try_lexical_convert(1.1, ires));
|
||||||
|
BOOST_CHECK(!try_lexical_convert(-1.9, ires));
|
||||||
|
BOOST_CHECK(!try_lexical_convert("1.1", ires));
|
||||||
|
BOOST_CHECK(!try_lexical_convert("1000000000000000000000000000000000000000", ires));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void try_common_cases()
|
||||||
|
{
|
||||||
|
int ires = 0;
|
||||||
|
const bool res1 = try_lexical_convert(std::string("100"), ires);
|
||||||
|
BOOST_CHECK(res1);
|
||||||
|
BOOST_CHECK_EQUAL(ires, 100);
|
||||||
|
|
||||||
|
ires = 0;
|
||||||
|
const bool res2 = try_lexical_convert("-100", ires);
|
||||||
|
BOOST_CHECK(res2);
|
||||||
|
BOOST_CHECK_EQUAL(ires, -100);
|
||||||
|
|
||||||
|
float fres = 1.0f;
|
||||||
|
const bool res3 = try_lexical_convert("0.0", fres);
|
||||||
|
BOOST_CHECK(res3);
|
||||||
|
BOOST_CHECK_EQUAL(fres, 0.0f);
|
||||||
|
|
||||||
|
fres = 1.0f;
|
||||||
|
const bool res4 = try_lexical_convert("0.0", sizeof("0.0") - 1, fres);
|
||||||
|
BOOST_CHECK(res4);
|
||||||
|
BOOST_CHECK_EQUAL(fres, 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::unit_test::test_suite *init_unit_test_suite(int, char *[])
|
||||||
|
{
|
||||||
|
boost::unit_test::test_suite *suite =
|
||||||
|
BOOST_TEST_SUITE("Tests for try_lexical_convert");
|
||||||
|
suite->add(BOOST_TEST_CASE(&try_uncommon_cases));
|
||||||
|
suite->add(BOOST_TEST_CASE(&try_common_cases));
|
||||||
|
|
||||||
|
return suite;
|
||||||
|
}
|
Reference in New Issue
Block a user