Added some tests for try_lexical_convert and fixed some issues.

This commit is contained in:
Antony Polukhin
2014-01-01 21:47:09 +04:00
parent 91b77e7373
commit 1707131ac3
3 changed files with 143 additions and 107 deletions

View File

@@ -1394,14 +1394,7 @@ namespace boost {
} }
template<typename InputStreamable> template<typename InputStreamable>
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
bool shl_input_streamable(InputStreamable&& input) {
typedef InputStreamable&& forward_type;
#else
bool shl_input_streamable(InputStreamable& input) { bool shl_input_streamable(InputStreamable& input) {
typedef InputStreamable& forward_type;
#endif // BOOST_NO_CXX11_RVALUE_REFERENCES
#if defined(BOOST_NO_STRINGSTREAM) || defined(BOOST_NO_STD_LOCALE) #if defined(BOOST_NO_STRINGSTREAM) || defined(BOOST_NO_STD_LOCALE)
// If you have compilation error at this point, than your STL library // If you have compilation error at this point, than your STL library
// does not support such conversions. Try updating it. // does not support such conversions. Try updating it.
@@ -1412,7 +1405,7 @@ namespace boost {
out_stream.exceptions(std::ios::badbit); out_stream.exceptions(std::ios::badbit);
try { try {
#endif #endif
bool const result = !(out_stream << static_cast<forward_type>(input)).fail(); bool const result = !(out_stream << input).fail();
const buffer_t* const p = static_cast<buffer_t*>( const buffer_t* const p = static_cast<buffer_t*>(
static_cast<std::basic_streambuf<CharT, Traits>*>(out_stream.rdbuf()) static_cast<std::basic_streambuf<CharT, Traits>*>(out_stream.rdbuf())
); );
@@ -1673,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); }
}; };
@@ -2081,21 +2073,14 @@ namespace boost {
BOOST_DEDUCED_TYPENAME stream_trait::traits BOOST_DEDUCED_TYPENAME stream_trait::traits
> o_interpreter_type; > o_interpreter_type;
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
template <class T>
static inline bool try_convert(T&& arg, Target& result) {
typedef T&& forward_type;
#else
static inline bool try_convert(const Source& arg, Target& result) { static inline bool try_convert(const Source& arg, Target& result) {
typedef const Source& forward_type;
#endif
i_interpreter_type i_interpreter; i_interpreter_type i_interpreter;
// Disabling ADL, by directly specifying operators. // Disabling ADL, by directly specifying operators.
// //
// For compilers with perfect forwarding `static_cast<forward_type>(arg)` is // For compilers with perfect forwarding `static_cast<forward_type>(arg)` is
// eqaul to `std::forward<T>(arg)`. // eqaul to `std::forward<T>(arg)`.
if (!(i_interpreter.operator <<(static_cast<forward_type>(arg)))) if (!(i_interpreter.operator <<(arg)))
return false; return false;
o_interpreter_type out(i_interpreter.cbegin(), i_interpreter.cend()); o_interpreter_type out(i_interpreter.cbegin(), i_interpreter.cend());
@@ -2263,56 +2248,76 @@ namespace boost {
}; };
} }
namespace conversion { namespace detail {
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
template <typename Target, typename Source> template <typename Target, typename Source>
inline bool try_lexical_convert(Source&& arg, Target& result) inline bool try_lexical_convert(Source&& arg, Target& result)
{ {
typedef BOOST_DEDUCED_TYPENAME boost::remove_const< typedef BOOST_DEDUCED_TYPENAME boost::remove_const<
BOOST_DEDUCED_TYPENAME boost::remove_reference<Source>::type BOOST_DEDUCED_TYPENAME boost::remove_reference<Source>::type
>::type no_cr_source_t; >::type no_cr_source_t;
typedef Source&& forward_type; typedef Source&& forward_type;
#else #else
template <typename Target, typename Source> template <typename Target, typename Source>
inline bool try_lexical_convert(const Source& arg, Target& result) inline bool try_lexical_convert(const Source& arg, Target& result)
{ {
typedef Source no_cr_source_t; typedef Source no_cr_source_t;
typedef const Source& forward_type; typedef const Source& forward_type;
#endif #endif
typedef BOOST_DEDUCED_TYPENAME boost::detail::array_to_pointer_decay<no_cr_source_t>::type src; typedef BOOST_DEDUCED_TYPENAME boost::detail::array_to_pointer_decay<no_cr_source_t>::type src;
typedef BOOST_DEDUCED_TYPENAME boost::type_traits::ice_or< typedef BOOST_DEDUCED_TYPENAME boost::type_traits::ice_or<
boost::detail::is_xchar_to_xchar<Target, src >::value, boost::detail::is_xchar_to_xchar<Target, src >::value,
boost::detail::is_char_array_to_stdstring<Target, src >::value, boost::detail::is_char_array_to_stdstring<Target, src >::value,
boost::type_traits::ice_and< boost::type_traits::ice_and<
boost::is_same<Target, src >::value, boost::is_same<Target, src >::value,
boost::detail::is_stdstring<Target >::value boost::detail::is_stdstring<Target >::value
>::value, >::value,
boost::type_traits::ice_and< boost::type_traits::ice_and<
boost::is_same<Target, src >::value, boost::is_same<Target, src >::value,
boost::detail::is_character<Target >::value boost::detail::is_character<Target >::value
>::value >::value
> shall_we_copy_t; > shall_we_copy_t;
typedef boost::detail::is_arithmetic_and_not_xchars<Target, src > typedef boost::detail::is_arithmetic_and_not_xchars<Target, src >
shall_we_copy_with_dynamic_check_t; shall_we_copy_with_dynamic_check_t;
// We do evaluate second `if_` lazily to avoid unnecessary instantiations // We do evaluate second `if_` lazily to avoid unnecessary instantiations
// 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::copy_converter_impl<Target, 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::dynamic_num_converter_impl<Target, src >, boost::detail::dynamic_num_converter_impl<Target, src >,
boost::detail::lexical_converter_impl<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::try_convert(static_cast<forward_type>(arg), result); return caster_type::try_convert(static_cast<forward_type>(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> template <typename Target, typename Source>
@@ -2320,7 +2325,7 @@ namespace boost {
{ {
Target result; Target result;
if (!try_lexical_convert(arg, result)) if (!boost::conversion::detail::try_lexical_convert(arg, result))
BOOST_LCAST_THROW_BAD_CAST(Source, Target); BOOST_LCAST_THROW_BAD_CAST(Source, Target);
return result; return result;
@@ -2334,27 +2339,11 @@ namespace boost {
); );
} }
template <typename Target>
inline bool try_lexical_convert(const char* chars, std::size_t count, Target& result)
{
return ::boost::try_lexical_convert(
::boost::iterator_range<const char*>(chars, chars + count), result
);
}
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)
{ {
return ::boost::lexical_cast<Target>( return ::boost::lexical_cast<Target>(
::boost::iterator_range<const unsigned char*>(chars, chars + count) ::boost::iterator_range<const unsigned char*>(chars, chars + count)
);
}
template <typename Target>
inline bool try_lexical_convert(const unsigned char* chars, std::size_t count, Target& result)
{
return ::boost::try_lexical_convert(
::boost::iterator_range<const unsigned char*>(chars, chars + count), result
); );
} }
@@ -2366,14 +2355,6 @@ namespace boost {
); );
} }
template <typename Target>
inline bool try_lexical_convert(const signed char* chars, std::size_t count, Target& result)
{
return ::boost::try_lexical_convert(
::boost::iterator_range<const signed char*>(chars, chars + count), result
);
}
#ifndef BOOST_LCAST_NO_WCHAR_T #ifndef BOOST_LCAST_NO_WCHAR_T
template <typename Target> template <typename Target>
inline Target lexical_cast(const wchar_t* chars, std::size_t count) inline Target lexical_cast(const wchar_t* chars, std::size_t count)
@@ -2382,14 +2363,6 @@ namespace boost {
::boost::iterator_range<const wchar_t*>(chars, chars + count) ::boost::iterator_range<const wchar_t*>(chars, chars + count)
); );
} }
template <typename Target>
inline bool try_lexical_convert(const wchar_t* chars, std::size_t count, Target& result)
{
return ::boost::try_lexical_convert(
::boost::iterator_range<const wchar_t*>(chars, chars + count), result
);
}
#endif #endif
#ifndef BOOST_NO_CXX11_CHAR16_T #ifndef BOOST_NO_CXX11_CHAR16_T
template <typename Target> template <typename Target>
@@ -2399,14 +2372,6 @@ namespace boost {
::boost::iterator_range<const char16_t*>(chars, chars + count) ::boost::iterator_range<const char16_t*>(chars, chars + count)
); );
} }
template <typename Target>
inline bool try_lexical_convert(const char16_t* chars, std::size_t count, Target& result)
{
return ::boost::try_lexical_convert(
::boost::iterator_range<const char16_t*>(chars, chars + count), result
);
}
#endif #endif
#ifndef BOOST_NO_CXX11_CHAR32_T #ifndef BOOST_NO_CXX11_CHAR32_T
template <typename Target> template <typename Target>
@@ -2416,14 +2381,6 @@ namespace boost {
::boost::iterator_range<const char32_t*>(chars, chars + count) ::boost::iterator_range<const char32_t*>(chars, chars + count)
); );
} }
template <typename Target>
inline bool try_lexical_convert(const char32_t* chars, std::size_t count, Target& result)
{
return ::boost::try_lexical_convert(
::boost::iterator_range<const char32_t*>(chars, chars + count), result
);
}
#endif #endif
} // namespace boost } // namespace boost

View File

@@ -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.

View 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;
void try_uncommon_cases()
{
std::string sres;
const bool res1 = conversion::try_lexical_convert(std::string("Test string"), sres);
BOOST_CHECK(res1);
BOOST_CHECK_EQUAL(sres, "Test string");
volatile int vires;
const bool res2 = conversion::try_lexical_convert(100, vires);
BOOST_CHECK(res2);
BOOST_CHECK_EQUAL(vires, 100);
const bool res3 = conversion::try_lexical_convert("Test string", sres);
BOOST_CHECK(res3);
BOOST_CHECK_EQUAL(sres, "Test string");
const bool res4 = conversion::try_lexical_convert("Test string", sizeof("Test string") - 1, sres);
BOOST_CHECK(res4);
BOOST_CHECK_EQUAL(sres, "Test string");
int ires;
BOOST_CHECK(!conversion::try_lexical_convert("Test string", ires));
BOOST_CHECK(!conversion::try_lexical_convert(1.1, ires));
BOOST_CHECK(!conversion::try_lexical_convert(-1.9, ires));
BOOST_CHECK(!conversion::try_lexical_convert("1.1", ires));
BOOST_CHECK(!conversion::try_lexical_convert("1000000000000000000000000000000000000000", ires));
}
void try_common_cases()
{
int ires = 0;
const bool res1 = conversion::try_lexical_convert(std::string("100"), ires);
BOOST_CHECK(res1);
BOOST_CHECK_EQUAL(ires, 100);
ires = 0;
const bool res2 = conversion::try_lexical_convert("-100", ires);
BOOST_CHECK(res2);
BOOST_CHECK_EQUAL(ires, -100);
float fres = 1.0f;
const bool res3 = conversion::try_lexical_convert("0.0", fres);
BOOST_CHECK(res3);
BOOST_CHECK_EQUAL(fres, 0.0f);
fres = 1.0f;
const bool res4 = conversion::try_lexical_convert("0.0", sizeof("0.0") - 1, fres);
BOOST_CHECK(res4);
BOOST_CHECK_EQUAL(fres, 0.0f);
}
unit_test::test_suite *init_unit_test_suite(int, char *[])
{
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;
}