/*============================================================================= 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 #include #include #include #include #include #include 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. /////////////////////////////////////////////////////////////////////////// namespace detail { template struct is_iter_range : mpl::false_ {}; template struct is_iter_range > : mpl::true_ {}; template struct is_container_of_ranges : is_iter_range {}; } template struct assign_to_attribute_from_iterators { // Common case static void call(Iterator const& first, Iterator const& last, Attribute& attr, mpl::false_) { if (traits::is_empty(attr)) attr = Attribute(first, last); else { for (Iterator i = first; i != last; ++i) push_back(attr, *i); } } // If Attribute is a container with value_type==iterator_range just push the // iterator_range into it static void call(Iterator const& first, Iterator const& last, Attribute& attr, mpl::true_) { typename Attribute::value_type rng(first, last); push_back(attr, rng); } static void call(Iterator const& first, Iterator const& last, Attribute& attr) { call(first, last, attr, detail::is_container_of_ranges()); } }; template struct assign_to_attribute_from_iterators< reference_wrapper, Iterator> { static void call(Iterator const& first, Iterator const& last , reference_wrapper attr) { if (traits::is_empty(attr)) attr = Attribute(first, last); else { for (Iterator i = first; i != last; ++i) push_back(attr, *i); } } }; template struct assign_to_attribute_from_iterators< boost::optional, Iterator> { static void call(Iterator const& first, Iterator const& last , boost::optional& attr) { Attribute val; assign_to(first, last, val); attr = val; } }; template struct assign_to_attribute_from_iterators< iterator_range, Iterator> { static void call(Iterator const& first, Iterator const& last , iterator_range& attr) { attr = iterator_range(first, last); } }; template inline void assign_to(Iterator const& first, Iterator const& last, Attribute& attr) { assign_to_attribute_from_iterators:: call(first, last, attr); } template inline void assign_to(Iterator const&, Iterator const&, unused_type) { } /////////////////////////////////////////////////////////////////////////// template void assign_to(T const& val, Attribute& attr); template struct assign_to_attribute_from_value { typedef typename traits::one_element_sequence::type is_one_element_sequence; typedef typename mpl::eval_if< is_one_element_sequence , fusion::result_of::at_c , mpl::identity >::type type; template static void call(T_ const& val, Attribute& attr, mpl::false_) { attr = static_cast(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 static void call(T_ const& val, Attribute& attr, mpl::true_) { typedef typename fusion::result_of::value_at_c::type element_type; fusion::at_c<0>(attr) = static_cast(val); } static void call(T const& val, Attribute& attr) { call(val, attr, is_one_element_sequence()); } }; template struct assign_to_attribute_from_value { static void call(Attribute const& val, Attribute& attr) { attr = val; } }; template struct assign_to_attribute_from_value , typename disable_if > >::type> { static void call(reference_wrapper const& val, Attribute& attr) { assign_to(val.get(), attr); } }; template struct assign_to_attribute_from_value , typename disable_if > >::type> { static void call(boost::optional const& val, Attribute& attr) { assign_to(val.get(), attr); } }; namespace detail { template struct is_same_size_sequence : mpl::bool_::value == fusion::result_of::size::value> {}; } template struct assign_to_attribute_from_value, fusion::traits::is_sequence, detail::is_same_size_sequence > > { static void call(T const& val, Attribute& attr) { fusion::copy(val, attr); } }; /////////////////////////////////////////////////////////////////////////// template struct assign_to_container_from_value { // T is not a container and not a string template 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 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 static void append_to_container_not_string(T_ const& val, Attribute& attr, mpl::false_) { typedef typename traits::container_iterator::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 static void call(T_ const& val, Attribute& attr, mpl::true_, mpl::false_) { typedef typename container_value::type value_type; typedef typename is_convertible::type is_value_type; append_to_container_not_string(val, attr, is_value_type()); } /////////////////////////////////////////////////////////////////////// // T is a string template 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 static void append_to_container(T_ const& val, Attribute& attr, mpl::false_) { typedef typename char_type_of::type char_type; append_to_string(attr, traits::get_begin(val) , traits::get_end(val)); } // T is string, and convertible to value_type of container template static void append_to_container(T_ const& val, Attribute& attr, mpl::true_) { traits::push_back(attr, val); } template static void call(T_ const& val, Attribute& attr, Pred, mpl::true_) { typedef typename container_value::type value_type; typedef typename is_convertible::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::type is_container; typedef typename traits::is_string::type is_string; call(val, attr, is_container(), is_string()); } }; template struct assign_to_container_from_value { static void call(Attribute const& val, Attribute& attr) { attr = val; } }; template struct assign_to_container_from_value , typename disable_if > >::type> { static void call(boost::optional const& val, Attribute& attr) { assign_to(val.get(), attr); } }; template struct assign_to_container_from_value , typename disable_if > >::type> { static void call(reference_wrapper const& val, Attribute& attr) { assign_to(val.get(), attr); } }; /////////////////////////////////////////////////////////////////////////// namespace detail { // overload for non-container attributes template inline void assign_to(T const& val, Attribute& attr, mpl::false_) { assign_to_attribute_from_value::call(val, attr); } // overload for containers (but not for variants or optionals // holding containers) template inline void assign_to(T const& val, Attribute& attr, mpl::true_) { assign_to_container_from_value::call(val, attr); } } template inline void assign_to(T const& val, Attribute& attr) { typedef typename mpl::and_< traits::is_container , traits::not_is_variant , traits::not_is_optional >::type is_not_wrapped_container; detail::assign_to(val, attr, is_not_wrapped_container()); } template inline void assign_to(T const&, unused_type) { } }}} #endif