// ---------------------------------------------------------------------------- | |
// 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 |