Chris@16: /*============================================================================= Chris@16: Copyright (c) 2001-2011 Joel de Guzman Chris@16: Copyright (c) 2001-2011 Hartmut Kaiser Chris@16: http://spirit.sourceforge.net/ Chris@16: Chris@16: Distributed under the Boost Software License, Version 1.0. (See accompanying Chris@16: file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Chris@16: =============================================================================*/ Chris@16: #if !defined(BOOST_SPIRIT_ASSIGN_TO_APR_16_2006_0812PM) Chris@16: #define BOOST_SPIRIT_ASSIGN_TO_APR_16_2006_0812PM Chris@16: Chris@16: #if defined(_MSC_VER) Chris@16: #pragma once Chris@16: #endif Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: namespace boost { namespace spirit { namespace traits Chris@16: { Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: // This file contains assignment utilities. The utilities provided also Chris@16: // accept spirit's unused_type; all no-ops. Compiler optimization will Chris@16: // easily strip these away. Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: namespace detail Chris@16: { Chris@16: template Chris@16: struct is_iter_range : mpl::false_ {}; Chris@16: Chris@16: template Chris@16: struct is_iter_range > : mpl::true_ {}; Chris@16: Chris@16: template Chris@16: struct is_container_of_ranges Chris@16: : is_iter_range {}; Chris@16: } Chris@16: Chris@16: template Chris@16: struct assign_to_attribute_from_iterators Chris@16: { Chris@16: // Common case Chris@16: static void Chris@16: call(Iterator const& first, Iterator const& last, Attribute& attr, mpl::false_) Chris@16: { Chris@16: if (traits::is_empty(attr)) Chris@16: attr = Attribute(first, last); Chris@16: else { Chris@16: for (Iterator i = first; i != last; ++i) Chris@16: push_back(attr, *i); Chris@16: } Chris@16: } Chris@16: Chris@16: // If Attribute is a container with value_type==iterator_range just push the Chris@16: // iterator_range into it Chris@16: static void Chris@16: call(Iterator const& first, Iterator const& last, Attribute& attr, mpl::true_) Chris@16: { Chris@16: typename Attribute::value_type rng(first, last); Chris@16: push_back(attr, rng); Chris@16: } Chris@16: Chris@16: static void Chris@16: call(Iterator const& first, Iterator const& last, Attribute& attr) Chris@16: { Chris@16: call(first, last, attr, detail::is_container_of_ranges()); Chris@16: } Chris@16: }; Chris@16: Chris@16: template Chris@16: struct assign_to_attribute_from_iterators< Chris@16: reference_wrapper, Iterator> Chris@16: { Chris@16: static void Chris@16: call(Iterator const& first, Iterator const& last Chris@16: , reference_wrapper attr) Chris@16: { Chris@16: if (traits::is_empty(attr)) Chris@16: attr = Attribute(first, last); Chris@16: else { Chris@16: for (Iterator i = first; i != last; ++i) Chris@16: push_back(attr, *i); Chris@16: } Chris@16: } Chris@16: }; Chris@16: Chris@16: template Chris@16: struct assign_to_attribute_from_iterators< Chris@16: boost::optional, Iterator> Chris@16: { Chris@16: static void Chris@16: call(Iterator const& first, Iterator const& last Chris@16: , boost::optional& attr) Chris@16: { Chris@16: Attribute val; Chris@16: assign_to(first, last, val); Chris@16: attr = val; Chris@16: } Chris@16: }; Chris@16: Chris@16: template Chris@16: struct assign_to_attribute_from_iterators< Chris@16: iterator_range, Iterator> Chris@16: { Chris@16: static void Chris@16: call(Iterator const& first, Iterator const& last Chris@16: , iterator_range& attr) Chris@16: { Chris@16: attr = iterator_range(first, last); Chris@16: } Chris@16: }; Chris@16: Chris@16: template Chris@16: inline void Chris@16: assign_to(Iterator const& first, Iterator const& last, Attribute& attr) Chris@16: { Chris@16: assign_to_attribute_from_iterators:: Chris@16: call(first, last, attr); Chris@16: } Chris@16: Chris@16: template Chris@16: inline void Chris@16: assign_to(Iterator const&, Iterator const&, unused_type) Chris@16: { Chris@16: } Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: void assign_to(T const& val, Attribute& attr); Chris@16: Chris@16: template Chris@16: struct assign_to_attribute_from_value Chris@16: { Chris@16: typedef typename traits::one_element_sequence::type Chris@16: is_one_element_sequence; Chris@16: Chris@16: typedef typename mpl::eval_if< Chris@16: is_one_element_sequence Chris@16: , fusion::result_of::at_c Chris@16: , mpl::identity Chris@16: >::type type; Chris@16: Chris@16: template Chris@16: static void Chris@16: call(T_ const& val, Attribute& attr, mpl::false_) Chris@16: { Chris@16: attr = static_cast(val); Chris@16: } Chris@16: Chris@16: // This handles the case where the attribute is a single element fusion Chris@16: // sequence. We silently assign to the only element and treat it as the Chris@16: // attribute to parse the results into. Chris@16: template Chris@16: static void Chris@16: call(T_ const& val, Attribute& attr, mpl::true_) Chris@16: { Chris@16: typedef typename fusion::result_of::value_at_c::type Chris@16: element_type; Chris@16: fusion::at_c<0>(attr) = static_cast(val); Chris@16: } Chris@16: Chris@16: static void Chris@16: call(T const& val, Attribute& attr) Chris@16: { Chris@16: call(val, attr, is_one_element_sequence()); Chris@16: } Chris@16: }; Chris@16: Chris@16: template Chris@16: struct assign_to_attribute_from_value Chris@16: { Chris@16: static void Chris@16: call(Attribute const& val, Attribute& attr) Chris@16: { Chris@16: attr = val; Chris@16: } Chris@16: }; Chris@16: Chris@16: template Chris@16: struct assign_to_attribute_from_value Chris@16: , typename disable_if > >::type> Chris@16: { Chris@16: static void Chris@16: call(reference_wrapper const& val, Attribute& attr) Chris@16: { Chris@16: assign_to(val.get(), attr); Chris@16: } Chris@16: }; Chris@16: Chris@16: template Chris@16: struct assign_to_attribute_from_value Chris@16: , typename disable_if > >::type> Chris@16: { Chris@16: static void Chris@16: call(boost::optional const& val, Attribute& attr) Chris@16: { Chris@16: assign_to(val.get(), attr); Chris@16: } Chris@16: }; Chris@16: Chris@16: namespace detail Chris@16: { Chris@16: template Chris@16: struct is_same_size_sequence Chris@16: : mpl::bool_::value Chris@16: == fusion::result_of::size::value> Chris@16: {}; Chris@16: } Chris@16: Chris@16: template Chris@16: struct assign_to_attribute_from_value, Chris@16: fusion::traits::is_sequence, Chris@16: detail::is_same_size_sequence Chris@16: > Chris@16: > Chris@16: { Chris@16: static void Chris@16: call(T const& val, Attribute& attr) Chris@16: { Chris@16: fusion::copy(val, attr); Chris@16: } Chris@16: }; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: struct assign_to_container_from_value Chris@16: { Chris@16: // T is not a container and not a string Chris@16: template Chris@16: static void call(T_ const& val, Attribute& attr, mpl::false_, mpl::false_) Chris@16: { Chris@16: traits::push_back(attr, val); Chris@16: } Chris@16: Chris@16: // T is a container (but not a string), and T is convertible to the Chris@16: // value_type of the Attribute container Chris@16: template Chris@16: static void Chris@16: append_to_container_not_string(T_ const& val, Attribute& attr, mpl::true_) Chris@16: { Chris@16: traits::push_back(attr, val); Chris@16: } Chris@16: Chris@16: // T is a container (but not a string), generic overload Chris@16: template Chris@16: static void Chris@16: append_to_container_not_string(T_ const& val, Attribute& attr, mpl::false_) Chris@16: { Chris@16: typedef typename traits::container_iterator::type Chris@16: iterator_type; Chris@16: Chris@16: iterator_type end = traits::end(val); Chris@16: for (iterator_type i = traits::begin(val); i != end; traits::next(i)) Chris@16: traits::push_back(attr, traits::deref(i)); Chris@16: } Chris@16: Chris@16: // T is a container (but not a string) Chris@16: template Chris@16: static void call(T_ const& val, Attribute& attr, mpl::true_, mpl::false_) Chris@16: { Chris@16: typedef typename container_value::type value_type; Chris@16: typedef typename is_convertible::type is_value_type; Chris@16: Chris@16: append_to_container_not_string(val, attr, is_value_type()); Chris@16: } Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////// Chris@16: // T is a string Chris@16: template Chris@16: static void append_to_string(Attribute& attr, Iterator begin, Iterator end) Chris@16: { Chris@16: for (Iterator i = begin; i != end; ++i) Chris@16: traits::push_back(attr, *i); Chris@16: } Chris@16: Chris@16: // T is string, but not convertible to value_type of container Chris@16: template Chris@16: static void append_to_container(T_ const& val, Attribute& attr, mpl::false_) Chris@16: { Chris@16: typedef typename char_type_of::type char_type; Chris@16: Chris@16: append_to_string(attr, traits::get_begin(val) Chris@16: , traits::get_end(val)); Chris@16: } Chris@16: Chris@16: // T is string, and convertible to value_type of container Chris@16: template Chris@16: static void append_to_container(T_ const& val, Attribute& attr, mpl::true_) Chris@16: { Chris@16: traits::push_back(attr, val); Chris@16: } Chris@16: Chris@16: template Chris@16: static void call(T_ const& val, Attribute& attr, Pred, mpl::true_) Chris@16: { Chris@16: typedef typename container_value::type value_type; Chris@16: typedef typename is_convertible::type is_value_type; Chris@16: Chris@16: append_to_container(val, attr, is_value_type()); Chris@16: } Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////// Chris@16: static void call(T const& val, Attribute& attr) Chris@16: { Chris@16: typedef typename traits::is_container::type is_container; Chris@16: typedef typename traits::is_string::type is_string; Chris@16: Chris@16: call(val, attr, is_container(), is_string()); Chris@16: } Chris@16: }; Chris@16: Chris@16: template Chris@16: struct assign_to_container_from_value Chris@16: { Chris@16: static void Chris@16: call(Attribute const& val, Attribute& attr) Chris@16: { Chris@16: attr = val; Chris@16: } Chris@16: }; Chris@16: Chris@16: template Chris@16: struct assign_to_container_from_value Chris@16: , typename disable_if > >::type> Chris@16: { Chris@16: static void Chris@16: call(boost::optional const& val, Attribute& attr) Chris@16: { Chris@16: assign_to(val.get(), attr); Chris@16: } Chris@16: }; Chris@16: Chris@16: template Chris@16: struct assign_to_container_from_value Chris@16: , typename disable_if > >::type> Chris@16: { Chris@16: static void Chris@16: call(reference_wrapper const& val, Attribute& attr) Chris@16: { Chris@16: assign_to(val.get(), attr); Chris@16: } Chris@16: }; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: namespace detail Chris@16: { Chris@16: // overload for non-container attributes Chris@16: template Chris@16: inline void Chris@16: assign_to(T const& val, Attribute& attr, mpl::false_) Chris@16: { Chris@16: assign_to_attribute_from_value::call(val, attr); Chris@16: } Chris@16: Chris@16: // overload for containers (but not for variants or optionals Chris@16: // holding containers) Chris@16: template Chris@16: inline void Chris@16: assign_to(T const& val, Attribute& attr, mpl::true_) Chris@16: { Chris@16: assign_to_container_from_value::call(val, attr); Chris@16: } Chris@16: } Chris@16: Chris@16: template Chris@16: inline void Chris@16: assign_to(T const& val, Attribute& attr) Chris@16: { Chris@16: typedef typename mpl::and_< Chris@16: traits::is_container Chris@16: , traits::not_is_variant Chris@16: , traits::not_is_optional Chris@16: >::type is_not_wrapped_container; Chris@16: Chris@16: detail::assign_to(val, attr, is_not_wrapped_container()); Chris@16: } Chris@16: Chris@16: template Chris@16: inline void Chris@16: assign_to(T const&, unused_type) Chris@16: { Chris@16: } Chris@16: }}} Chris@16: Chris@16: #endif