/*============================================================================= Copyright (c) 2001-2010 Joel de Guzman Copyright (c) 2001-2010 Hartmut Kaiser 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(SPIRIT_PASS_CONTAINER_JANUARY_06_2009_0802PM) #define SPIRIT_PASS_CONTAINER_JANUARY_06_2009_0802PM #if defined(_MSC_VER) #pragma once #endif #include #include #include #include #include namespace boost { namespace spirit { namespace qi { namespace detail { // has_same_elements: utility to check if the RHS attribute // is an STL container and that its value_type is convertible // to the LHS. template ::value> struct has_same_elements : mpl::false_ {}; template struct has_same_elements : is_convertible {}; template struct has_same_elements, true> : has_same_elements {}; #define BOOST_SPIRIT_IS_CONVERTIBLE(z, N, data) \ has_same_elements::value || \ /***/ // Note: variants are treated as containers if one of the held types is a // container (see support/container.hpp). template struct has_same_elements< LHS, boost::variant, true> : mpl::bool_ {}; #undef BOOST_SPIRIT_IS_CONVERTIBLE // This function handles the case where the attribute (Attr) given // the sequence is an STL container. This is a wrapper around F. // The function F does the actual parsing. template struct pass_container { typedef typename F::context_type context_type; typedef typename F::iterator_type iterator_type; pass_container(F const& f, Attr& attr) : f(f), attr(attr) {} // this is for the case when the current element exposes an attribute // which is pushed back onto the container template bool dispatch_attribute_element(Component const& component, mpl::false_) const { // synthesized attribute needs to be default constructed typename traits::container_value::type val = typename traits::container_value::type(); iterator_type save = f.first; bool r = f(component, val); if (!r) { // push the parsed value into our attribute r = !traits::push_back(attr, val); if (r) f.first = save; } return r; } // this is for the case when the current element expects an attribute // which is a container itself, this element will push its data // directly into the attribute container template bool dispatch_attribute_element(Component const& component, mpl::true_) const { return f(component, attr); } // This handles the distinction between elements in a sequence expecting // containers themselves and elements expecting non-containers as their // attribute. Note: is_container treats optional, where T is a // container as a container as well. template bool dispatch_attribute(Component const& component, mpl::true_) const { typedef traits::is_container< typename traits::attribute_of< Component, context_type, iterator_type >::type > predicate; return dispatch_attribute_element(component, predicate()); } // this is for the case when the current element doesn't expect an // attribute template bool dispatch_attribute(Component const& component, mpl::false_) const { return f(component, unused); } // This handles the case where the attribute of the component // is not an STL container or its element is not convertible // to the target attribute's (Attr) value_type. template bool dispatch_main(Component const& component, mpl::false_) const { // we need to dispatch again depending on the type of the attribute // of the current element (component). If this is has no attribute // we shouldn't push an element into the container. typedef traits::not_is_unused< typename traits::attribute_of< Component, context_type, iterator_type >::type > predicate; return dispatch_attribute(component, predicate()); } // This handles the case where the attribute of the component is // an STL container *and* its value_type is convertible to the // target attribute's (Attr) value_type. template bool dispatch_main(Component const& component, mpl::true_) const { return f(component, attr); } // Dispatches to dispatch_main depending on the attribute type // of the Component template bool operator()(Component const& component) const { typedef typename traits::container_value::type lhs; typedef typename traits::attribute_of< Component, context_type, iterator_type>::type rhs_attribute; return dispatch_main(component , has_same_elements()); } F f; Attr& attr; private: // silence MSVC warning C4512: assignment operator could not be generated pass_container& operator= (pass_container const&); }; // Utility function to make a pass_container template pass_container inline make_pass_container(F const& f, Attr& attr) { return pass_container(f, attr); } }}}} #endif