222 lines
6.7 KiB
C++
222 lines
6.7 KiB
C++
|
// ----------------------------------------------------------------------------
|
||
|
// 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
|