You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and dots ('.'), can be up to 35 characters long. Letters must be lowercase.
363 lines
12 KiB
363 lines
12 KiB
/*============================================================================= |
|
Copyright (c) 2001-2011 Joel de Guzman |
|
Copyright (c) 2001-2011 Hartmut Kaiser |
|
http://spirit.sourceforge.net/ |
|
|
|
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) |
|
=============================================================================*/ |
|
#if !defined(BOOST_SPIRIT_ASSIGN_TO_APR_16_2006_0812PM) |
|
#define BOOST_SPIRIT_ASSIGN_TO_APR_16_2006_0812PM |
|
|
|
#if defined(_MSC_VER) |
|
#pragma once |
|
#endif |
|
|
|
#include <boost/spirit/home/qi/detail/construct.hpp> |
|
#include <boost/spirit/home/support/unused.hpp> |
|
#include <boost/spirit/home/qi/detail/attributes.hpp> |
|
#include <boost/spirit/home/support/container.hpp> |
|
#include <boost/fusion/include/copy.hpp> |
|
#include <boost/ref.hpp> |
|
#include <boost/range/iterator_range.hpp> |
|
|
|
namespace boost { namespace spirit { namespace traits |
|
{ |
|
/////////////////////////////////////////////////////////////////////////// |
|
// This file contains assignment utilities. The utilities provided also |
|
// accept spirit's unused_type; all no-ops. Compiler optimization will |
|
// easily strip these away. |
|
/////////////////////////////////////////////////////////////////////////// |
|
template <typename Attribute, typename Iterator, typename Enable> |
|
struct assign_to_attribute_from_iterators |
|
{ |
|
static void |
|
call(Iterator const& first, Iterator const& last, Attribute& attr) |
|
{ |
|
if (traits::is_empty(attr)) |
|
attr = Attribute(first, last); |
|
else { |
|
for (Iterator i = first; i != last; ++i) |
|
push_back(attr, *i); |
|
} |
|
} |
|
}; |
|
|
|
template <typename Attribute, typename Iterator> |
|
struct assign_to_attribute_from_iterators< |
|
reference_wrapper<Attribute>, Iterator> |
|
{ |
|
static void |
|
call(Iterator const& first, Iterator const& last |
|
, reference_wrapper<Attribute> attr) |
|
{ |
|
if (traits::is_empty(attr)) |
|
attr = Attribute(first, last); |
|
else { |
|
for (Iterator i = first; i != last; ++i) |
|
push_back(attr, *i); |
|
} |
|
} |
|
}; |
|
|
|
template <typename Attribute, typename Iterator> |
|
struct assign_to_attribute_from_iterators< |
|
boost::optional<Attribute>, Iterator> |
|
{ |
|
static void |
|
call(Iterator const& first, Iterator const& last |
|
, boost::optional<Attribute>& attr) |
|
{ |
|
Attribute val; |
|
assign_to(first, last, val); |
|
attr = val; |
|
} |
|
}; |
|
|
|
template <typename Iterator> |
|
struct assign_to_attribute_from_iterators< |
|
iterator_range<Iterator>, Iterator> |
|
{ |
|
static void |
|
call(Iterator const& first, Iterator const& last |
|
, iterator_range<Iterator>& attr) |
|
{ |
|
attr = iterator_range<Iterator>(first, last); |
|
} |
|
}; |
|
|
|
template <typename Iterator, typename Attribute> |
|
inline void |
|
assign_to(Iterator const& first, Iterator const& last, Attribute& attr) |
|
{ |
|
assign_to_attribute_from_iterators<Attribute, Iterator>:: |
|
call(first, last, attr); |
|
} |
|
|
|
template <typename Iterator> |
|
inline void |
|
assign_to(Iterator const&, Iterator const&, unused_type) |
|
{ |
|
} |
|
|
|
/////////////////////////////////////////////////////////////////////////// |
|
template <typename T, typename Attribute> |
|
void assign_to(T const& val, Attribute& attr); |
|
|
|
template <typename Attribute, typename T, typename Enable> |
|
struct assign_to_attribute_from_value |
|
{ |
|
typedef typename traits::one_element_sequence<Attribute>::type |
|
is_one_element_sequence; |
|
|
|
typedef typename mpl::eval_if< |
|
is_one_element_sequence |
|
, fusion::result_of::at_c<Attribute, 0> |
|
, mpl::identity<Attribute&> |
|
>::type type; |
|
|
|
template <typename T_> |
|
static void |
|
call(T_ const& val, Attribute& attr, mpl::false_) |
|
{ |
|
attr = static_cast<Attribute>(val); |
|
} |
|
|
|
// This handles the case where the attribute is a single element fusion |
|
// sequence. We silently assign to the only element and treat it as the |
|
// attribute to parse the results into. |
|
template <typename T_> |
|
static void |
|
call(T_ const& val, Attribute& attr, mpl::true_) |
|
{ |
|
typedef typename fusion::result_of::value_at_c<Attribute, 0>::type |
|
element_type; |
|
fusion::at_c<0>(attr) = static_cast<element_type>(val); |
|
} |
|
|
|
static void |
|
call(T const& val, Attribute& attr) |
|
{ |
|
call(val, attr, is_one_element_sequence()); |
|
} |
|
}; |
|
|
|
template <typename Attribute> |
|
struct assign_to_attribute_from_value<Attribute, Attribute> |
|
{ |
|
static void |
|
call(Attribute const& val, Attribute& attr) |
|
{ |
|
attr = val; |
|
} |
|
}; |
|
|
|
template <typename Attribute, typename T> |
|
struct assign_to_attribute_from_value<Attribute, reference_wrapper<T> |
|
, typename disable_if<is_same<Attribute, reference_wrapper<T> > >::type> |
|
{ |
|
static void |
|
call(reference_wrapper<T> const& val, Attribute& attr) |
|
{ |
|
assign_to(val.get(), attr); |
|
} |
|
}; |
|
|
|
template <typename Attribute, typename T> |
|
struct assign_to_attribute_from_value<Attribute, boost::optional<T> |
|
, typename disable_if<is_same<Attribute, boost::optional<T> > >::type> |
|
{ |
|
static void |
|
call(boost::optional<T> const& val, Attribute& attr) |
|
{ |
|
assign_to(val.get(), attr); |
|
} |
|
}; |
|
|
|
namespace detail |
|
{ |
|
template <typename A, typename B> |
|
struct is_same_size_sequence |
|
: mpl::bool_<fusion::result_of::size<A>::value |
|
== fusion::result_of::size<B>::value> |
|
{}; |
|
} |
|
|
|
template <typename Attribute, typename T> |
|
struct assign_to_attribute_from_value<Attribute, T, |
|
mpl::and_< |
|
fusion::traits::is_sequence<Attribute>, |
|
fusion::traits::is_sequence<T>, |
|
detail::is_same_size_sequence<Attribute, T> |
|
> |
|
> |
|
{ |
|
static void |
|
call(T const& val, Attribute& attr) |
|
{ |
|
fusion::copy(val, attr); |
|
} |
|
}; |
|
|
|
/////////////////////////////////////////////////////////////////////////// |
|
template <typename Attribute, typename T, typename Enable> |
|
struct assign_to_container_from_value |
|
{ |
|
// T is not a container and not a string |
|
template <typename T_> |
|
static void call(T_ const& val, Attribute& attr, mpl::false_, mpl::false_) |
|
{ |
|
traits::push_back(attr, val); |
|
} |
|
|
|
// T is a container (but not a string), and T is convertible to the |
|
// value_type of the Attribute container |
|
template <typename T_> |
|
static void |
|
append_to_container_not_string(T_ const& val, Attribute& attr, mpl::true_) |
|
{ |
|
traits::push_back(attr, val); |
|
} |
|
|
|
// T is a container (but not a string), generic overload |
|
template <typename T_> |
|
static void |
|
append_to_container_not_string(T_ const& val, Attribute& attr, mpl::false_) |
|
{ |
|
typedef typename traits::container_iterator<T_ const>::type |
|
iterator_type; |
|
|
|
iterator_type end = traits::end(val); |
|
for (iterator_type i = traits::begin(val); i != end; traits::next(i)) |
|
traits::push_back(attr, traits::deref(i)); |
|
} |
|
|
|
// T is a container (but not a string) |
|
template <typename T_> |
|
static void call(T_ const& val, Attribute& attr, mpl::true_, mpl::false_) |
|
{ |
|
typedef typename container_value<Attribute>::type value_type; |
|
typedef typename is_convertible<T, value_type>::type is_value_type; |
|
|
|
append_to_container_not_string(val, attr, is_value_type()); |
|
} |
|
|
|
/////////////////////////////////////////////////////////////////////// |
|
// T is a string |
|
template <typename Iterator> |
|
static void append_to_string(Attribute& attr, Iterator begin, Iterator end) |
|
{ |
|
for (Iterator i = begin; i != end; ++i) |
|
traits::push_back(attr, *i); |
|
} |
|
|
|
// T is string, but not convertible to value_type of container |
|
template <typename T_> |
|
static void append_to_container(T_ const& val, Attribute& attr, mpl::false_) |
|
{ |
|
typedef typename char_type_of<T_>::type char_type; |
|
|
|
append_to_string(attr, traits::get_begin<char_type>(val) |
|
, traits::get_end<char_type>(val)); |
|
} |
|
|
|
// T is string, and convertible to value_type of container |
|
template <typename T_> |
|
static void append_to_container(T_ const& val, Attribute& attr, mpl::true_) |
|
{ |
|
traits::push_back(attr, val); |
|
} |
|
|
|
template <typename T_, typename Pred> |
|
static void call(T_ const& val, Attribute& attr, Pred, mpl::true_) |
|
{ |
|
typedef typename container_value<Attribute>::type value_type; |
|
typedef typename is_convertible<T, value_type>::type is_value_type; |
|
|
|
append_to_container(val, attr, is_value_type()); |
|
} |
|
|
|
/////////////////////////////////////////////////////////////////////// |
|
static void call(T const& val, Attribute& attr) |
|
{ |
|
typedef typename traits::is_container<T>::type is_container; |
|
typedef typename traits::is_string<T>::type is_string; |
|
|
|
call(val, attr, is_container(), is_string()); |
|
} |
|
}; |
|
|
|
template <typename Attribute> |
|
struct assign_to_container_from_value<Attribute, Attribute> |
|
{ |
|
static void |
|
call(Attribute const& val, Attribute& attr) |
|
{ |
|
attr = val; |
|
} |
|
}; |
|
|
|
template <typename Attribute, typename T> |
|
struct assign_to_container_from_value<Attribute, boost::optional<T> |
|
, typename disable_if<is_same<Attribute, boost::optional<T> > >::type> |
|
{ |
|
static void |
|
call(boost::optional<T> const& val, Attribute& attr) |
|
{ |
|
assign_to(val.get(), attr); |
|
} |
|
}; |
|
|
|
template <typename Attribute, typename T> |
|
struct assign_to_container_from_value<Attribute, reference_wrapper<T> |
|
, typename disable_if<is_same<Attribute, reference_wrapper<T> > >::type> |
|
{ |
|
static void |
|
call(reference_wrapper<T> const& val, Attribute& attr) |
|
{ |
|
assign_to(val.get(), attr); |
|
} |
|
}; |
|
|
|
/////////////////////////////////////////////////////////////////////////// |
|
namespace detail |
|
{ |
|
// overload for non-container attributes |
|
template <typename T, typename Attribute> |
|
inline void |
|
assign_to(T const& val, Attribute& attr, mpl::false_) |
|
{ |
|
assign_to_attribute_from_value<Attribute, T>::call(val, attr); |
|
} |
|
|
|
// overload for containers (but not for variants or optionals |
|
// holding containers) |
|
template <typename T, typename Attribute> |
|
inline void |
|
assign_to(T const& val, Attribute& attr, mpl::true_) |
|
{ |
|
assign_to_container_from_value<Attribute, T>::call(val, attr); |
|
} |
|
} |
|
|
|
template <typename T, typename Attribute> |
|
inline void |
|
assign_to(T const& val, Attribute& attr) |
|
{ |
|
typedef typename mpl::and_< |
|
traits::is_container<Attribute> |
|
, traits::not_is_variant<Attribute> |
|
, traits::not_is_optional<Attribute> |
|
>::type is_not_wrapped_container; |
|
|
|
detail::assign_to(val, attr, is_not_wrapped_container()); |
|
} |
|
|
|
template <typename T> |
|
inline void |
|
assign_to(T const&, unused_type) |
|
{ |
|
} |
|
}}} |
|
|
|
#endif
|
|
|