// ---------------------------------------------------------------------------- // Copyright (C) 2009 Sebastian Redl // // 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) // // For more information, see www.boost.org // ---------------------------------------------------------------------------- #ifndef BOOST_PROPERTY_TREE_STREAM_TRANSLATOR_HPP_INCLUDED #define BOOST_PROPERTY_TREE_STREAM_TRANSLATOR_HPP_INCLUDED #include <boost/property_tree/ptree_fwd.hpp> #include <boost/optional.hpp> #include <boost/optional/optional_io.hpp> #include <boost/utility/enable_if.hpp> #include <boost/type_traits/decay.hpp> #include <boost/type_traits/integral_constant.hpp> #include <sstream> #include <string> #include <locale> #include <limits> namespace boost { namespace property_tree { template <typename Ch, typename Traits, typename E, typename Enabler = void> struct customize_stream { static void insert(std::basic_ostream<Ch, Traits>& s, const E& e) { s << e; } static void extract(std::basic_istream<Ch, Traits>& s, E& e) { s >> e; if(!s.eof()) { s >> std::ws; } } }; // No whitespace skipping for single characters. template <typename Ch, typename Traits> struct customize_stream<Ch, Traits, Ch, void> { static void insert(std::basic_ostream<Ch, Traits>& s, Ch e) { s << e; } static void extract(std::basic_istream<Ch, Traits>& s, Ch& e) { s.unsetf(std::ios_base::skipws); s >> e; } }; // Ugly workaround for numeric_traits that don't have members when not // specialized, e.g. MSVC. namespace detail { template <bool is_specialized> struct is_inexact_impl { template <typename T> struct test { typedef boost::false_type type; }; }; template <> struct is_inexact_impl<true> { template <typename T> struct test { typedef boost::integral_constant<bool, !std::numeric_limits<T>::is_exact> type; }; }; template <typename F> struct is_inexact { typedef typename boost::decay<F>::type decayed; typedef typename is_inexact_impl< std::numeric_limits<decayed>::is_specialized >::BOOST_NESTED_TEMPLATE test<decayed>::type type; static const bool value = type::value; }; } template <typename Ch, typename Traits, typename F> struct customize_stream<Ch, Traits, F, typename boost::enable_if< detail::is_inexact<F> >::type > { static void insert(std::basic_ostream<Ch, Traits>& s, const F& e) { s.precision(std::numeric_limits<F>::digits10 + 1); s << e; } static void extract(std::basic_istream<Ch, Traits>& s, F& e) { s >> e; if(!s.eof()) { s >> std::ws; } } }; template <typename Ch, typename Traits> struct customize_stream<Ch, Traits, bool, void> { static void insert(std::basic_ostream<Ch, Traits>& s, bool e) { s.setf(std::ios_base::boolalpha); s << e; } static void extract(std::basic_istream<Ch, Traits>& s, bool& e) { s >> e; if(s.fail()) { // Try again in word form. s.clear(); s.setf(std::ios_base::boolalpha); s >> e; } if(!s.eof()) { s >> std::ws; } } }; template <typename Ch, typename Traits> struct customize_stream<Ch, Traits, signed char, void> { static void insert(std::basic_ostream<Ch, Traits>& s, signed char e) { s << (int)e; } static void extract(std::basic_istream<Ch, Traits>& s, signed char& e) { int i; s >> i; // out of range? if(i > (std::numeric_limits<signed char>::max)() || i < (std::numeric_limits<signed char>::min)()) { s.clear(); // guarantees eof to be unset return; } e = (signed char)i; if(!s.eof()) { s >> std::ws; } } }; template <typename Ch, typename Traits> struct customize_stream<Ch, Traits, unsigned char, void> { static void insert(std::basic_ostream<Ch, Traits>& s, unsigned char e) { s << (unsigned)e; } static void extract(std::basic_istream<Ch,Traits>& s, unsigned char& e){ unsigned i; s >> i; // out of range? if(i > (std::numeric_limits<unsigned char>::max)()) { s.clear(); // guarantees eof to be unset return; } e = (unsigned char)i; if(!s.eof()) { s >> std::ws; } } }; /// Implementation of Translator that uses the stream overloads. template <typename Ch, typename Traits, typename Alloc, typename E> class stream_translator { typedef customize_stream<Ch, Traits, E> customized; public: typedef std::basic_string<Ch, Traits, Alloc> internal_type; typedef E external_type; explicit stream_translator(std::locale loc = std::locale()) : m_loc(loc) {} boost::optional<E> get_value(const internal_type &v) { std::basic_istringstream<Ch, Traits, Alloc> iss(v); iss.imbue(m_loc); E e; customized::extract(iss, e); if(iss.fail() || iss.bad() || iss.get() != Traits::eof()) { return boost::optional<E>(); } return e; } boost::optional<internal_type> put_value(const E &v) { std::basic_ostringstream<Ch, Traits, Alloc> oss; oss.imbue(m_loc); customized::insert(oss, v); if(oss) { return oss.str(); } return boost::optional<internal_type>(); } private: std::locale m_loc; }; // This is the default translator when basic_string is the internal type. // Unless the external type is also basic_string, in which case // id_translator takes over. template <typename Ch, typename Traits, typename Alloc, typename E> struct translator_between<std::basic_string<Ch, Traits, Alloc>, E> { typedef stream_translator<Ch, Traits, Alloc, E> type; }; }} #endif