Optimizations for boost and std array (refs #7065)

[SVN r79230]
This commit is contained in:
Antony Polukhin
2012-07-02 18:30:21 +00:00
parent c6318e3819
commit e3cd0ca7fa
3 changed files with 421 additions and 17 deletions

View File

@@ -138,6 +138,12 @@ namespace boost
#include <cmath>
#include <istream>
#if !defined(BOOST_NO_CXX11_HDR_ARRAY) && defined(BOOST_HAS_TR1_ARRAY)
#include <array>
#endif
#include <boost/array.hpp>
#include <boost/numeric/conversion/cast.hpp>
#include <boost/type_traits/make_unsigned.hpp>
#include <boost/type_traits/is_signed.hpp>
@@ -224,42 +230,56 @@ namespace boost {
typedef char type;
};
template<typename CharT>
template <typename CharT>
struct stream_char<CharT*>
{
typedef BOOST_DEDUCED_TYPENAME stream_char<CharT>::type type;
};
template<typename CharT>
template <typename CharT>
struct stream_char<const CharT*>
{
typedef BOOST_DEDUCED_TYPENAME stream_char<CharT>::type type;
};
template<typename CharT>
template <typename CharT>
struct stream_char<iterator_range<CharT*> >
{
typedef BOOST_DEDUCED_TYPENAME stream_char<CharT*>::type type;
};
template<typename CharT>
template <typename CharT>
struct stream_char<iterator_range<const CharT*> >
{
typedef BOOST_DEDUCED_TYPENAME stream_char<const CharT*>::type type;
};
template<class CharT, class Traits, class Alloc>
template <class CharT, class Traits, class Alloc>
struct stream_char< std::basic_string<CharT, Traits, Alloc> >
{
typedef CharT type;
};
template<class CharT, class Traits, class Alloc>
template <class CharT, class Traits, class Alloc>
struct stream_char< ::boost::container::basic_string<CharT, Traits, Alloc> >
{
typedef CharT type;
};
template<typename CharT, std::size_t N>
struct stream_char<boost::array<CharT, N> >
{
typedef BOOST_DEDUCED_TYPENAME stream_char<CharT>::type type;
};
#if !defined(BOOST_NO_CXX11_HDR_ARRAY) && defined(BOOST_HAS_TR1_ARRAY)
template <typename CharT, std::size_t N>
struct stream_char<std::array<CharT, N> >
{
typedef BOOST_DEDUCED_TYPENAME stream_char<CharT>::type type;
};
#endif // !defined(BOOST_NO_CXX11_HDR_ARRAY) && defined(BOOST_HAS_TR1_ARRAY)
#if !defined(BOOST_LCAST_NO_WCHAR_T) && defined(BOOST_NO_INTRINSIC_WCHAR_T)
template<>
struct stream_char<wchar_t>
@@ -1259,7 +1279,6 @@ namespace boost {
return true;
}
#ifndef BOOST_LCAST_NO_WCHAR_T
template <class T>
bool shl_char_array(T const* str)
{
@@ -1268,7 +1287,13 @@ namespace boost {
"Use boost::locale instead" );
return shl_input_streamable(str);
}
#endif
bool shl_char_array_limited(CharT const* str, std::size_t max_size)
{
start = const_cast<CharT*>(str);
finish = std::find(start, start + max_size, static_cast<CharT>(0));
return true;
}
template<typename InputStreamable>
bool shl_input_streamable(InputStreamable& input)
@@ -1494,8 +1519,58 @@ namespace boost {
return shl_real_type(static_cast<double>(val), start, finish);
#endif
}
template <std::size_t N>
bool operator<<(boost::array<CharT, N> const& input)
{ return shl_char_array_limited(input.begin(), N); }
template<class InStreamable>
template <std::size_t N>
bool operator<<(boost::array<unsigned char, N> const& input)
{ return ((*this) << reinterpret_cast<boost::array<char, N> const& >(input)); }
template <std::size_t N>
bool operator<<(boost::array<signed char, N> const& input)
{ return ((*this) << reinterpret_cast<boost::array<char, N> const& >(input)); }
template <std::size_t N>
bool operator<<(boost::array<const CharT, N> const& input)
{ return shl_char_array_limited(input.begin(), N); }
template <std::size_t N>
bool operator<<(boost::array<const unsigned char, N> const& input)
{ return ((*this) << reinterpret_cast<boost::array<const char, N> const& >(input)); }
template <std::size_t N>
bool operator<<(boost::array<const signed char, N> const& input)
{ return ((*this) << reinterpret_cast<boost::array<const char, N> const& >(input)); }
#if !defined(BOOST_NO_CXX11_HDR_ARRAY) && defined(BOOST_HAS_TR1_ARRAY)
template <std::size_t N>
bool operator<<(std::array<CharT, N> const& input)
{ return shl_char_array_limited(input.begin(), N); }
template <std::size_t N>
bool operator<<(std::array<unsigned char, N> const& input)
{ return ((*this) << reinterpret_cast<boost::array<char, N> const& >(input)); }
template <std::size_t N>
bool operator<<(std::array<signed char, N> const& input)
{ return ((*this) << reinterpret_cast<boost::array<char, N> const& >(input)); }
template <std::size_t N>
bool operator<<(std::array<const CharT, N> const& input)
{ return shl_char_array_limited(input.begin(), N); }
template <std::size_t N>
bool operator<<(std::array<const unsigned char, N> const& input)
{ return ((*this) << reinterpret_cast<boost::array<const char, N> const& >(input)); }
template <std::size_t N>
bool operator<<(std::array<const signed char, N> const& input)
{ return ((*this) << reinterpret_cast<boost::array<const char, N> const& >(input)); }
#endif // !defined(BOOST_NO_CXX11_HDR_ARRAY) && defined(BOOST_HAS_TR1_ARRAY)
template <class InStreamable>
bool operator<<(const InStreamable& input) { return shl_input_streamable(input); }
/************************************ HELPER FUNCTIONS FOR OPERATORS >> ( ... ) ********************************/
@@ -1674,6 +1749,70 @@ namespace boost {
template<class Alloc>
bool operator>>(::boost::container::basic_string<CharT,Traits,Alloc>& str) { str.assign(start, finish); return true; }
private:
template <std::size_t N, class ArrayT>
bool shr_std_array(ArrayT& output, boost::mpl::bool_<true> /*is_T_char_tag*/)
{
using namespace std;
const std::size_t size = finish - start;
if (size > N - 1) { // `-1` because we need to store \0 at the end
return false;
}
memcpy(output.begin(), start, size * sizeof(CharT));
*(output.begin() + size) = static_cast<CharT>(0);
return true;
}
template <std::size_t N, class ArrayT>
bool shr_std_array(ArrayT& output, boost::mpl::bool_<false> /*is_T_char_tag*/)
{
return shr_using_base_class(output); // Array consist of non character types or unmatching character type
}
public:
template <std::size_t N>
bool operator>>(boost::array<CharT, N>& output)
{
typedef boost::mpl::bool_<true> tag_type;
return shr_std_array<N>(output, tag_type());
}
template <std::size_t N>
bool operator>>(boost::array<unsigned char, N>& output)
{
return ((*this) >> reinterpret_cast<boost::array<char, N>& >(output));
}
template <std::size_t N>
bool operator>>(boost::array<signed char, N>& output)
{
return ((*this) >> reinterpret_cast<boost::array<char, N>& >(output));
}
#if !defined(BOOST_NO_CXX11_HDR_ARRAY) && defined(BOOST_HAS_TR1_ARRAY)
template <std::size_t N>
bool operator>>(std::array<CharT, N>& output)
{
typedef boost::mpl::bool_<true> tag_type;
return shr_std_array<N>(output, tag_type());
}
template <std::size_t N>
bool operator>>(std::array<unsigned char, N>& output)
{
return ((*this) >> reinterpret_cast<std::array<char, N>& >(output));
}
template <std::size_t N>
bool operator>>(std::array<signed char, N>& in)
{
return ((*this) >> reinterpret_cast<std::array<char, N>& >(output));
}
#endif // !defined(BOOST_NO_CXX11_HDR_ARRAY) && defined(BOOST_HAS_TR1_ARRAY)
/*
* case "-0" || "0" || "+0" : output = false; return true;
* case "1" || "+1": output = true; return true;
@@ -1937,11 +2076,6 @@ namespace boost {
"Your compiler does not have full support for char32_t" );
#endif
typedef detail::lcast_src_length<src > lcast_src_length;
std::size_t const src_len = lcast_src_length::value;
char_type buf[src_len + 1];
lcast_src_length::check_coverage();
typedef BOOST_DEDUCED_TYPENAME ::boost::detail::deduce_char_traits<
char_type, Target, Source
>::type traits;
@@ -1959,20 +2093,29 @@ namespace boost {
::boost::detail::is_char_or_wchar<src_char_type >::value
> is_source_input_optimized_t;
// Target type must be default constructible
Target result;
// If we have an optimized conversion for
// Source, we do not need to construct stringbuf.
const bool requires_stringbuf = ::boost::type_traits::ice_or<
is_string_widening_required_t::value,
::boost::type_traits::ice_not< is_source_input_optimized_t::value >::value
>::value;
typedef detail::lexical_stream_limited_src<char_type, traits, requires_stringbuf > interpreter_type;
detail::lexical_stream_limited_src<char_type, traits, requires_stringbuf >
interpreter(buf, buf + src_len);
typedef detail::lcast_src_length<src > lcast_src_length;
std::size_t const src_len = lcast_src_length::value;
char_type buf[src_len + 1];
lcast_src_length::check_coverage();
interpreter_type interpreter(buf, buf + src_len);
Target result;
// Disabling ADL, by directly specifying operators.
if(!(interpreter.operator <<(arg) && interpreter.operator >>(result)))
BOOST_LCAST_THROW_BAD_CAST(Source, Target);
return result;
}
};

View File

@@ -47,5 +47,6 @@ test-suite conversion
<toolset>gcc-4.7:<cflags>-fno-exceptions
]
[ run lexical_cast_iterator_range_test.cpp ]
[ run lexical_cast_arrays_test.cpp ]
;

View File

@@ -0,0 +1,260 @@
// Testing boost::lexical_cast with boost::container::string.
//
// 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/lexical_cast.hpp>
#include <boost/test/unit_test.hpp>
#include <boost/array.hpp>
void testing_boost_array_output_conversion();
void testing_std_array_output_conversion();
void testing_boost_array_input_conversion();
void testing_std_array_input_conversion();
using namespace boost;
boost::unit_test::test_suite *init_unit_test_suite(int, char *[])
{
unit_test::test_suite *suite =
BOOST_TEST_SUITE("Testing boost::lexical_cast with boost::array and std::array");
suite->add(BOOST_TEST_CASE(testing_boost_array_output_conversion));
suite->add(BOOST_TEST_CASE(testing_std_array_output_conversion));
suite->add(BOOST_TEST_CASE(testing_boost_array_input_conversion));
suite->add(BOOST_TEST_CASE(testing_std_array_input_conversion));
return suite;
}
template <template <class, std::size_t> class ArrayT, class T>
static void testing_template_array_output_on_spec_value(T val)
{
typedef ArrayT<char, 300> arr_type;
typedef ArrayT<char, 1> short_arr_type;
typedef ArrayT<unsigned char, 300> uarr_type;
typedef ArrayT<unsigned char, 1> ushort_arr_type;
typedef ArrayT<signed char, 4> sarr_type;
typedef ArrayT<signed char, 3> sshort_arr_type;
std::string ethalon("100");
using namespace std;
{
arr_type res1 = lexical_cast<arr_type>(val);
BOOST_CHECK_EQUAL(res1.begin(), ethalon);
const arr_type res2 = lexical_cast<arr_type>(val);
BOOST_CHECK_EQUAL(res2.begin(), ethalon);
BOOST_CHECK_THROW(lexical_cast<short_arr_type>(val), boost::bad_lexical_cast);
}
{
uarr_type res1 = lexical_cast<uarr_type>(val);
BOOST_CHECK_EQUAL(reinterpret_cast<char*>(res1.begin()), ethalon);
const uarr_type res2 = lexical_cast<uarr_type>(val);
BOOST_CHECK_EQUAL(reinterpret_cast<const char*>(res2.begin()), ethalon);
BOOST_CHECK_THROW(lexical_cast<ushort_arr_type>(val), boost::bad_lexical_cast);
}
{
sarr_type res1 = lexical_cast<sarr_type>(val);
BOOST_CHECK_EQUAL(reinterpret_cast<char*>(res1.begin()), ethalon);
const sarr_type res2 = lexical_cast<sarr_type>(val);
BOOST_CHECK_EQUAL(reinterpret_cast<const char*>(res2.begin()), ethalon);
BOOST_CHECK_THROW(lexical_cast<sshort_arr_type>(val), boost::bad_lexical_cast);
}
#if !defined(BOOST_NO_STRINGSTREAM) && !defined(BOOST_NO_STD_WSTRING)
typedef ArrayT<wchar_t, 300> warr_type;
typedef ArrayT<wchar_t, 3> wshort_arr_type;
std::wstring wethalon(L"100");
{
warr_type res = lexical_cast<warr_type>(val);
BOOST_CHECK(res.begin() == wethalon);
warr_type res3 = lexical_cast<warr_type>(wethalon);
BOOST_CHECK(res.begin() == wethalon);
}
{
const warr_type res = lexical_cast<warr_type>(val);
BOOST_CHECK(res.begin() == wethalon);
const warr_type res3 = lexical_cast<warr_type>(wethalon);
BOOST_CHECK(res.begin() == wethalon);
}
BOOST_CHECK_THROW(lexical_cast<wshort_arr_type>(val), boost::bad_lexical_cast);
#endif
#if !defined(BOOST_NO_CHAR16_T) && !defined(BOOST_NO_UNICODE_LITERALS)
typedef ArrayT<char16_t, 300> u16arr_type;
typedef ArrayT<char16_t, 3> u16short_arr_type;
std::u16string u16ethalon(u"100");
{
u16arr_type res = lexical_cast<u16arr_type>(val);
BOOST_CHECK(res.begin() == u16ethalon);
u16arr_type res3 = lexical_cast<u16arr_type>(u16ethalon);
BOOST_CHECK(res3.begin() == u16ethalon);
}
{
const u16arr_type res = lexical_cast<u16arr_type>(val);
BOOST_CHECK(res.begin() == u16ethalon);
const u16arr_type res3 = lexical_cast<u16arr_type>(u16ethalon);
BOOST_CHECK(res3.begin() == u16ethalon);
}
BOOST_CHECK_THROW(lexical_cast<u16short_arr_type>(val), boost::bad_lexical_cast);
#endif
#if !defined(BOOST_NO_CHAR32_T) && !defined(BOOST_NO_UNICODE_LITERALS)
typedef ArrayT<char32_t, 300> u32arr_type;
typedef ArrayT<char32_t, 3> u32short_arr_type;
std::u32string u32ethalon(U"100");
{
u32arr_type res = lexical_cast<u32arr_type>(val);
BOOST_CHECK(res.begin() == u32ethalon);
u32arr_type res3 = lexical_cast<u32arr_type>(u32ethalon);
BOOST_CHECK(res3.begin() == u32ethalon);
}
{
const u32arr_type res = lexical_cast<u32arr_type>(val);
BOOST_CHECK(res.begin() == u32ethalon);
const u32arr_type res3 = lexical_cast<u32arr_type>(u32ethalon);
BOOST_CHECK(res3.begin() == u32ethalon);
}
BOOST_CHECK_THROW(lexical_cast<u32short_arr_type>(val), boost::bad_lexical_cast);
#endif
}
void testing_boost_array_output_conversion()
{
testing_template_array_output_on_spec_value<boost::array>("100");
testing_template_array_output_on_spec_value<boost::array>(100);
testing_template_array_output_on_spec_value<boost::array>(static_cast<short>(100));
testing_template_array_output_on_spec_value<boost::array>(static_cast<unsigned short>(100));
testing_template_array_output_on_spec_value<boost::array>(static_cast<unsigned int>(100));
}
void testing_std_array_output_conversion()
{
#if !defined(BOOST_NO_CXX11_HDR_ARRAY) && defined(BOOST_HAS_TR1_ARRAY)
testing_template_array_output_on_spec_value<std::array>("100");
testing_template_array_output_on_spec_value<std::array>(100);
testing_template_array_output_on_spec_value<std::array>(static_cast<short>(100));
testing_template_array_output_on_spec_value<std::array>(static_cast<unsigned short>(100));
testing_template_array_output_on_spec_value<std::array>(static_cast<unsigned int>(100));
#endif
BOOST_CHECK(true);
}
template <template <class, std::size_t> class ArrayT>
static void testing_generic_array_input_conversion()
{
{
ArrayT<char, 4> var_zero_terminated = {{ '1', '0', '0', '\0'}};
BOOST_CHECK_EQUAL(lexical_cast<std::string>(var_zero_terminated), "100");
ArrayT<char, 3> var_none_terminated = {{ '1', '0', '0'}};
BOOST_CHECK_EQUAL(lexical_cast<std::string>(var_none_terminated), "100");
ArrayT<const char, 4> var_zero_terminated_const_char = {{ '1', '0', '0', '\0'}};
BOOST_CHECK_EQUAL(lexical_cast<std::string>(var_zero_terminated_const_char), "100");
ArrayT<const char, 3> var_none_terminated_const_char = {{ '1', '0', '0'}};
BOOST_CHECK_EQUAL(lexical_cast<std::string>(var_none_terminated_const_char), "100");
const ArrayT<char, 4> var_zero_terminated_const_var = {{ '1', '0', '0', '\0'}};
BOOST_CHECK_EQUAL(lexical_cast<std::string>(var_zero_terminated_const_var), "100");
const ArrayT<char, 3> var_none_terminated_const_var = {{ '1', '0', '0'}};
BOOST_CHECK_EQUAL(lexical_cast<std::string>(var_none_terminated_const_var), "100");
const ArrayT<const char, 4> var_zero_terminated_const_var_const_char = {{ '1', '0', '0', '\0'}};
BOOST_CHECK_EQUAL(lexical_cast<std::string>(var_zero_terminated_const_var_const_char), "100");
const ArrayT<const char, 3> var_none_terminated_const_var_const_char = {{ '1', '0', '0'}};
BOOST_CHECK_EQUAL(lexical_cast<std::string>(var_none_terminated_const_var_const_char), "100");
}
{
const ArrayT<const unsigned char, 4> var_zero_terminated_const_var_const_char = {{ '1', '0', '0', '\0'}};
BOOST_CHECK_EQUAL(lexical_cast<std::string>(var_zero_terminated_const_var_const_char), "100");
const ArrayT<const unsigned char, 3> var_none_terminated_const_var_const_char = {{ '1', '0', '0'}};
BOOST_CHECK_EQUAL(lexical_cast<std::string>(var_none_terminated_const_var_const_char), "100");
}
{
const ArrayT<const signed char, 4> var_zero_terminated_const_var_const_char = {{ '1', '0', '0', '\0'}};
BOOST_CHECK_EQUAL(lexical_cast<std::string>(var_zero_terminated_const_var_const_char), "100");
const ArrayT<const signed char, 3> var_none_terminated_const_var_const_char = {{ '1', '0', '0'}};
BOOST_CHECK_EQUAL(lexical_cast<std::string>(var_none_terminated_const_var_const_char), "100");
}
#if !defined(BOOST_NO_STRINGSTREAM) && !defined(BOOST_NO_STD_WSTRING)
{
const ArrayT<const wchar_t, 4> var_zero_terminated_const_var_const_char = {{ L'1', L'0', L'0', L'\0'}};
BOOST_CHECK(lexical_cast<std::wstring>(var_zero_terminated_const_var_const_char) == L"100");
const ArrayT<const wchar_t, 3> var_none_terminated_const_var_const_char = {{ L'1', L'0', L'0'}};
BOOST_CHECK(lexical_cast<std::wstring>(var_none_terminated_const_var_const_char) == L"100");
}
#endif
#if !defined(BOOST_NO_CHAR16_T) && !defined(BOOST_NO_UNICODE_LITERALS)
{
const ArrayT<const char16_t, 4> var_zero_terminated_const_var_const_char = {{ u'1', u'0', u'0', u'\0'}};
BOOST_CHECK(lexical_cast<std::u16string>(var_zero_terminated_const_var_const_char) == u"100");
const ArrayT<const char16_t, 3> var_none_terminated_const_var_const_char = {{ u'1', u'0', u'0'}};
BOOST_CHECK(lexical_cast<std::u16string>(var_none_terminated_const_var_const_char) == u"100");
}
#endif
#if !defined(BOOST_NO_CHAR32_T) && !defined(BOOST_NO_UNICODE_LITERALS)
{
const ArrayT<const char32_t, 4> var_zero_terminated_const_var_const_char = {{ U'1', U'0', U'0', U'\0'}};
BOOST_CHECK(lexical_cast<std::u32string>(var_zero_terminated_const_var_const_char) == U"100");
const ArrayT<const char32_t, 3> var_none_terminated_const_var_const_char = {{ U'1', U'0', U'0'}};
BOOST_CHECK(lexical_cast<std::u32string>(var_none_terminated_const_var_const_char) == U"100");
}
#endif
}
void testing_boost_array_input_conversion()
{
testing_generic_array_input_conversion<boost::array>();
}
void testing_std_array_input_conversion()
{
#if !defined(BOOST_NO_CXX11_HDR_ARRAY) && defined(BOOST_HAS_TR1_ARRAY)
testing_generic_array_input_conversion<std::array>();
#endif
BOOST_CHECK(true);
}