changes to correct errors in usage of codecvt for utf8

Key change is to change utf8 codecvt facet to use Boost.Locale rather than boost/detail.  This fixed an issue with gcc.
This commit is contained in:
Robert Ramey
2015-10-30 16:26:11 -07:00
parent 41fd59b77b
commit e3b67eb299
21 changed files with 150 additions and 321 deletions

View File

@@ -143,7 +143,7 @@ public:
// the optimized load_array dispatches to load_binary
template <class ValueType>
void load_array(serialization::array<ValueType>& a, unsigned int)
void load_array(serialization::array_wrapper<ValueType>& a, unsigned int)
{
load_binary(a.address(),a.count()*sizeof(ValueType));
}

View File

@@ -137,11 +137,10 @@ public:
struct apply : public boost::serialization::is_bitwise_serializable< T > {};
#endif
};
// the optimized save_array dispatches to save_binary
template <class ValueType>
void save_array(boost::serialization::array<ValueType> const& a, unsigned int)
void save_array(boost::serialization::array_wrapper<ValueType> const& a, unsigned int)
{
save_binary(a.address(),a.count()*sizeof(ValueType));
}

View File

@@ -60,27 +60,43 @@ private:
};
template < typename Ch, class Tr >
class basic_ios_locale_saver :
class basic_istream_locale_saver :
private boost::noncopyable
{
public:
explicit basic_ios_locale_saver(std::basic_ios<Ch, Tr> &s) :
m_ios(s),
explicit basic_istream_locale_saver(std::basic_istream<Ch, Tr> &s) :
m_istream(s),
m_locale(s.getloc())
{}
~basic_ios_locale_saver(){
// libc++ doesn't support std::[w]ostream.sync()
// but gcc will throw an error if sync() isn't invoked
#ifndef _LIBCPP_VERSION
m_ios.sync();
#endif
m_ios.imbue(m_locale);
~basic_istream_locale_saver(){
// libstdc++ crashes without this
m_istream.sync();
m_istream.imbue(m_locale);
}
private:
std::basic_ios<Ch, Tr> & m_ios;
std::basic_istream<Ch, Tr> & m_istream;
std::locale const m_locale;
};
template < typename Ch, class Tr >
class basic_ostream_locale_saver :
private boost::noncopyable
{
public:
explicit basic_ostream_locale_saver(std::basic_ostream<Ch, Tr> &s) :
m_ostream(s),
m_locale(s.getloc())
{}
~basic_ostream_locale_saver(){
m_ostream.flush();
m_ostream.imbue(m_locale);
}
private:
std::basic_ostream<Ch, Tr> & m_ostream;
std::locale const m_locale;
};
} // archive
} // boost

View File

@@ -77,7 +77,7 @@ protected:
// f) destroy new codecvt facet
boost::archive::codecvt_null<typename IStream::char_type> codecvt_null_facet;
std::locale archive_locale;
basic_ios_locale_saver<
basic_istream_locale_saver<
typename IStream::char_type,
typename IStream::traits_type
> locale_saver;

View File

@@ -80,7 +80,7 @@ protected:
// f) destroy new codecvt facet
boost::archive::codecvt_null<typename OStream::char_type> codecvt_null_facet;
std::locale archive_locale;
basic_ios_locale_saver<
basic_ostream_locale_saver<
typename OStream::char_type,
typename OStream::traits_type
> locale_saver;

View File

@@ -9,22 +9,24 @@
#include <boost/config.hpp>
#define BOOST_UTF8_BEGIN_NAMESPACE \
namespace boost { namespace archive { namespace detail {
#define BOOST_UTF8_END_NAMESPACE }}}
#ifdef BOOST_NO_CXX11_HDR_CODECVT
#define BOOST_UTF8_BEGIN_NAMESPACE \
namespace boost { namespace archive { namespace detail {
#define BOOST_UTF8_DECL
#define BOOST_UTF8_END_NAMESPACE }}}
#include <boost/detail/utf8_codecvt_facet.hpp>
#undef BOOST_UTF8_END_NAMESPACE
#undef BOOST_UTF8_DECL
#undef BOOST_UTF8_BEGIN_NAMESPACE
#include <boost/locale/utf8_codecvt.hpp>
BOOST_UTF8_BEGIN_NAMESPACE
typedef boost::locale::utf8_codecvt<wchar_t> utf8_codecvt_facet;
BOOST_UTF8_END_NAMESPACE
#else
#include <codecvt>
namespace boost { namespace archive { namespace detail {
BOOST_UTF8_BEGIN_NAMESPACE
typedef std::codecvt_utf8<wchar_t> utf8_codecvt_facet;
} } }
BOOST_UTF8_END_NAMESPACE
#endif // BOOST_NO_CXX11_HDR_CODECVT
#undef BOOST_UTF8_BEGIN_NAMESPACE
#undef BOOST_UTF8_END_NAMESPACE
#endif // BOOST_ARCHIVE_DETAIL_UTF8_CODECVT_FACET_HPP

View File

@@ -161,42 +161,11 @@ basic_binary_iprimitive<Archive, Elem, Tr>::basic_binary_iprimitive(
{}
#endif
// some libraries including stl and libcomo fail if the
// buffer isn't flushed before the code_cvt facet is changed.
// I think this is a bug. We explicity invoke sync to when
// we're done with the streambuf to work around this problem.
// Note that sync is a protected member of stream buff so we
// have to invoke it through a contrived derived class.
namespace detail {
// note: use "using" to get past msvc bug
using namespace std;
template<class Elem, class Tr>
class input_streambuf_access : public std::basic_streambuf<Elem, Tr> {
public:
virtual int sync(){
#if BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3206))
return this->basic_streambuf::sync();
#else
return this->basic_streambuf<Elem, Tr>::sync();
#endif
}
};
} // detail
// scoped_ptr requires that archive_locale be a complete type at time of
// scoped_ptr requires that g be a complete type at time of
// destruction so define destructor here rather than in the header
template<class Archive, class Elem, class Tr>
BOOST_ARCHIVE_OR_WARCHIVE_DECL
basic_binary_iprimitive<Archive, Elem, Tr>::~basic_binary_iprimitive(){
// push back unread characters
//destructor can't throw !
BOOST_TRY{
static_cast<detail::input_streambuf_access<Elem, Tr> &>(m_sb).sync();
}
BOOST_CATCH(...){
}
BOOST_CATCH_END
}
basic_binary_iprimitive<Archive, Elem, Tr>::~basic_binary_iprimitive(){}
} // namespace archive
} // namespace boost

View File

@@ -114,30 +114,6 @@ basic_binary_oprimitive<Archive, Elem, Tr>::basic_binary_oprimitive(
{}
#endif
/*
// some libraries including stl and libcomo fail if the
// buffer isn't flushed before the code_cvt facet is changed.
// I think this is a bug. We explicity invoke sync to when
// we're done with the streambuf to work around this problem.
// Note that sync is a protected member of stream buff so we
// have to invoke it through a contrived derived class.
namespace detail {
// note: use "using" to get past msvc bug
using namespace std;
template<class Elem, class Tr>
class output_streambuf_access : public std::basic_streambuf<Elem, Tr> {
public:
virtual int sync(){
#if BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3206))
return this->basic_streambuf::sync();
#else
return this->basic_streambuf<Elem, Tr>::sync();
#endif
}
};
} // detail
*/
// scoped_ptr requires that g be a complete type at time of
// destruction so define destructor here rather than in the header
template<class Archive, class Elem, class Tr>

View File

@@ -10,7 +10,7 @@
#include <cstddef> // NULL
#include <algorithm> // std::copy
#include <exception> // std::uncaught_exception
#include <boost/config.hpp>
#if defined(BOOST_NO_STDC_NAMESPACE)
namespace std{
@@ -93,11 +93,7 @@ basic_text_oprimitive<OStream>::basic_text_oprimitive(
locale_saver(os)
{
if(! no_codecvt){
// libc++ doesn't support std::wostream.sync()
// but gcc will throw an error if sync() isn't invoked
#ifndef _LIBCPP_VERSION
os_.sync();
#endif
os_.flush();
os_.imbue(archive_locale);
}
os_ << std::noboolalpha;
@@ -110,6 +106,8 @@ basic_text_oprimitive<OStream>::basic_text_oprimitive(
template<class OStream>
BOOST_ARCHIVE_OR_WARCHIVE_DECL
basic_text_oprimitive<OStream>::~basic_text_oprimitive(){
if(std::uncaught_exception())
return;
os << std::endl;
}

View File

@@ -11,6 +11,8 @@
#include <boost/config.hpp>
#include <cstring> // memcpy
#include <cstddef> // NULL
#include <exception>
#if defined(BOOST_NO_STDC_NAMESPACE)
namespace std{
using ::memcpy;
@@ -187,6 +189,8 @@ xml_iarchive_impl<Archive>::xml_iarchive_impl(
template<class Archive>
BOOST_ARCHIVE_DECL
xml_iarchive_impl<Archive>::~xml_iarchive_impl(){
if(std::uncaught_exception())
return;
if(0 == (this->get_flags() & no_header)){
gimpl->windup(is);
}

View File

@@ -10,6 +10,7 @@
#include <iomanip>
#include <algorithm> // std::copy
#include <string>
#include <exception>
#include <cstring> // strlen
#include <boost/config.hpp> // msvc 6.0 needs this to suppress warnings
@@ -116,6 +117,8 @@ xml_oarchive_impl<Archive>::xml_oarchive_impl(
template<class Archive>
BOOST_ARCHIVE_DECL
xml_oarchive_impl<Archive>::~xml_oarchive_impl(){
if(std::uncaught_exception())
return;
if(0 == (this->get_flags() & no_header)){
save("</boost_serialization>\n");
}

View File

@@ -20,7 +20,7 @@ namespace std{
#include <boost/assert.hpp>
#include <algorithm> // std::copy
#include <exception> // uncaught exception
#include <boost/detail/workaround.hpp> // Dinkumware and RogueWave
#if BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB, == 1)
#include <boost/archive/dinkumware.hpp>
@@ -36,6 +36,8 @@ namespace std{
#include <boost/archive/xml_archive_exception.hpp>
#include <boost/archive/iterators/mb_from_wchar.hpp>
#include <boost/archive/detail/utf8_codecvt_facet.hpp>
#include "basic_xml_grammar.hpp"
namespace boost {
@@ -163,6 +165,7 @@ xml_wiarchive_impl<Archive>::xml_wiarchive_impl(
is_.getloc(),
new boost::archive::detail::utf8_codecvt_facet
);
// libstdc++ crashes without this
is_.sync();
is_.imbue(l);
}
@@ -173,6 +176,8 @@ xml_wiarchive_impl<Archive>::xml_wiarchive_impl(
template<class Archive>
BOOST_WARCHIVE_DECL
xml_wiarchive_impl<Archive>::~xml_wiarchive_impl(){
if(std::uncaught_exception())
return;
if(0 == (this->get_flags() & no_header)){
gimpl->windup(is);
}

View File

@@ -13,6 +13,7 @@
#include <string>
#include <algorithm> // std::copy
#include <locale>
#include <exception>
#include <cstring> // strlen
#include <cstdlib> // mbtowc
@@ -30,6 +31,8 @@ namespace std{
#endif
#include <boost/archive/xml_woarchive.hpp>
#include <boost/archive/detail/utf8_codecvt_facet.hpp>
#include <boost/serialization/throw_exception.hpp>
#include <boost/archive/iterators/xml_escape.hpp>
@@ -125,11 +128,7 @@ xml_woarchive_impl<Archive>::xml_woarchive_impl(
os_.getloc(),
new boost::archive::detail::utf8_codecvt_facet
);
// libc++ doesn't support std::[w]ostream.sync()
// but gcc will throw an error if sync() isn't invoked
#ifndef _LIBCPP_VERSION
os_.sync();
#endif
os_.flush();
os_.imbue(l);
}
if(0 == (flags & no_header))
@@ -139,6 +138,8 @@ xml_woarchive_impl<Archive>::xml_woarchive_impl(
template<class Archive>
BOOST_WARCHIVE_DECL
xml_woarchive_impl<Archive>::~xml_woarchive_impl(){
if(std::uncaught_exception())
return;
if(0 == (this->get_flags() & no_header)){
save(L"</boost_serialization>\n");
}

View File

@@ -6,13 +6,9 @@
// 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> // msvc 6.0 needs this for warning suppression
//#include <iostream>
#include <iostream>
#include <cstddef> // std::size_t
#ifndef BOOST_NO_CXX11_HDR_ARRAY
#include <array>
#endif
#include <boost/config.hpp> // msvc 6.0 needs this for warning suppression
#if defined(BOOST_NO_STDC_NAMESPACE)
namespace std{
@@ -23,11 +19,13 @@ namespace std{
#include <boost/serialization/nvp.hpp>
#include <boost/serialization/split_member.hpp>
#include <boost/serialization/wrapper.hpp>
#include <boost/serialization/collection_size_type.hpp>
#include <boost/mpl/always.hpp>
#include <boost/mpl/apply.hpp>
#include <boost/mpl/bool.hpp>
#include <boost/type_traits/remove_const.hpp>
#include <boost/array.hpp>
#include <boost/type_traits/is_integral.hpp>
#include <boost/static_assert.hpp>
namespace boost { namespace serialization {
@@ -37,24 +35,27 @@ template <class Archive>
struct use_array_optimization : boost::mpl::always<boost::mpl::false_> {};
template<class T>
class array :
public wrapper_traits<const array< T > >
class array_wrapper :
public wrapper_traits<const array_wrapper< T > >
{
public:
typedef T value_type;
array(value_type* t, std::size_t s) :
m_t(t),
m_element_count(s)
{}
array(const array & rhs) :
private:
array_wrapper & operator=(const array_wrapper & rhs);
public:
// note: I would like to make the copy constructor private but this breaks
// make_array. So I try to make make_array a friend - but that doesn't
// build. Need a C++ guru to explain this!
template<class S>
friend const boost::serialization::array_wrapper<T> make_array( T* t, S s);
array_wrapper(const array_wrapper & rhs) :
m_t(rhs.m_t),
m_element_count(rhs.m_element_count)
{}
array & operator=(const array & rhs){
m_t = rhs.m_t;
m_element_count = rhs.m_element_count;
}
public:
array_wrapper(T * t, std::size_t s) :
m_t(t),
m_element_count(s)
{}
// default implementation
template<class Archive>
@@ -62,7 +63,7 @@ public:
{
// default implemention does the loop
std::size_t c = count();
value_type * t = address();
T * t = address();
while(0 < c--)
ar & boost::serialization::make_nvp("item", *t++);
}
@@ -99,7 +100,7 @@ public:
serialize_optimized(ar,version,use_optimized());
}
value_type* address() const
T * address() const
{
return m_t;
}
@@ -108,26 +109,32 @@ public:
{
return m_element_count;
}
private:
value_type* m_t;
std::size_t m_element_count;
T * const m_t;
const std::size_t m_element_count;
};
template<class T>
template<class T, class S>
inline
const array< T > make_array( T* t, std::size_t s){
return array< T >(t, s);
const array_wrapper< T > make_array( T* t, S s){
const array_wrapper< T > a(t, s);
return a;
}
// implement serialization for boost::array
template <class Archive, class T, std::size_t N>
void serialize(Archive& ar, boost::array<T,N>& a, const unsigned int /* version */)
{
ar & boost::serialization::make_nvp("elems", a.elems);
}
} } // end namespace boost::serialization
// I can't figure out why BOOST_NO_CXX11_HDR_ARRAY
// has been set for clang-11. So just make sure
// it's reset now. Needs further research!!!
#if defined(_LIBCPP_VERSION)
#undef BOOST_NO_CXX11_HDR_ARRAY
#endif
#ifndef BOOST_NO_CXX11_HDR_ARRAY
#include <array>
namespace boost { namespace serialization {
// implement serialization for std::array
template <class Archive, class T, std::size_t N>
void serialize(Archive& ar, std::array<T,N>& a, const unsigned int /* version */)
@@ -138,8 +145,19 @@ void serialize(Archive& ar, std::array<T,N>& a, const unsigned int /* version */
);
}
} } // end namespace boost::serialization
#endif
#include <boost/array.hpp>
namespace boost { namespace serialization {
// implement serialization for boost::array
template <class Archive, class T, std::size_t N>
void serialize(Archive& ar, boost::array<T,N>& a, const unsigned int /* version */)
{
ar & boost::serialization::make_nvp("elems", a.elems);
}
} } // end namespace boost::serialization
#define BOOST_SERIALIZATION_USE_ARRAY_OPTIMIZATION(Archive) \

View File

@@ -39,15 +39,18 @@ struct nvp :
public std::pair<const char *, T *>,
public wrapper_traits<const nvp< T > >
{
//private:
//friend const nvp< T > make_nvp(const char * name, T & t);
nvp(const nvp & rhs) :
// note: redundant cast works around borland issue
std::pair<const char *, T *>(rhs.first, (T*)rhs.second)
{}
public:
explicit nvp(const char * name_, T & t) :
// note: redundant cast works around borland issue
// note: added _ to suppress useless gcc warning
std::pair<const char *, T *>(name_, (T*)(& t))
{}
nvp(const nvp & rhs) :
// note: redundant cast works around borland issue
std::pair<const char *, T *>(rhs.first, (T*)rhs.second)
{}
const char * name() const {
return this->first;

View File

@@ -40,20 +40,20 @@ namespace serialization {
template<class Archive, class U>
void save( Archive & ar, const STD::valarray<U> &t, const unsigned int /*file_version*/ )
{
const collection_size_type count(t.size());
ar << BOOST_SERIALIZATION_NVP(count);
if (t.size())
ar << make_array(detail::get_data(t), t.size());
const collection_size_type count(t.size());
ar << BOOST_SERIALIZATION_NVP(count);
if (t.size())
ar << make_array(detail::get_data(t), t.size());
}
template<class Archive, class U>
void load( Archive & ar, STD::valarray<U> &t, const unsigned int /*file_version*/ )
{
collection_size_type count;
ar >> BOOST_SERIALIZATION_NVP(count);
t.resize(count);
if (t.size())
ar >> make_array(detail::get_data(t), t.size());
collection_size_type count;
ar >> BOOST_SERIALIZATION_NVP(count);
t.resize(count);
if (t.size())
ar >> make_array(detail::get_data(t), t.size());
}
// split non-intrusive serialization function member into separate