/*============================================================================= Copyright (c) 2001-2010 Hartmut Kaiser Copyright (c) 2001-2010 Joel de Guzman 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_MAR_15_2009_0114PM) #define SPIRIT_PASS_CONTAINER_MAR_15_2009_0114PM #if defined(_MSC_VER) #pragma once #endif #include #include #include #include #include #include #include #include #include #include #include namespace boost { namespace spirit { namespace karma { namespace detail { // has_same_elements: utility to check if the LHS attribute // is an STL container and that its value_type is convertible // to the RHS. template ::value> struct has_same_elements : mpl::false_ {}; template struct has_same_elements : mpl::or_< is_convertible , is_same > {}; 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< RHS, boost::variant, true> : mpl::bool_ {}; #undef BOOST_SPIRIT_IS_CONVERTIBLE /////////////////////////////////////////////////////////////////////////// // This function handles the case where the attribute (Attr) given // to the sequence is an STL container. This is a wrapper around F. // The function F does the actual generating. template struct pass_container { typedef typename F::context_type context_type; pass_container(F const& f, Iterator begin, Iterator end) : f(f), iter(begin), end(end) {} // this is for the case when the current element expects an attribute // which is taken from the next entry in the container template bool dispatch_attribute_element(Component const& component, mpl::false_) const { // get the next value to generate from container if (!traits::compare(iter, end) && !f(component, traits::deref(iter))) { // needs to return false as long as everything is ok traits::next(iter); return false; } // either no elements available any more or generation failed return true; } // this is for the case when the current element expects an attribute // which is a container itself, this element will get the rest of the // attribute container template bool dispatch_attribute_element(Component const& component, mpl::true_) const { return f(component, make_iterator_range(iter, end)); } // 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 typename traits::attribute_of< Component, context_type>::type attribute_type; typedef mpl::and_< traits::is_container , is_convertible > 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 a STL container or which elements are not // convertible to the target attribute (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 use an element of the container but unused_type // instead typedef traits::not_is_unused< typename traits::attribute_of::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, make_iterator_range(iter, end)); } // 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 rhs; typedef typename traits::attribute_of< Component, context_type>::type lhs_attribute; // false means everything went ok return dispatch_main(component , has_same_elements()); } F f; mutable Iterator iter; mutable Iterator end; private: // silence MSVC warning C4512: assignment operator could not be generated pass_container& operator= (pass_container const&); }; }}}} #endif