/*============================================================================= Copyright (c) 2001-2011 Hartmut Kaiser Copyright (c) 2001-2011 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 #include #include #include namespace boost { namespace spirit { namespace karma { namespace detail { // Helper meta-function allowing to evaluate weak substitutability and // negate the result if the predicate (Sequence) is not true template struct negate_weak_substitute_if_not : mpl::if_< Sequence , typename traits::is_weak_substitute::type , typename mpl::not_< traits::is_weak_substitute >::type> {}; // pass_through_container: utility to check decide whether a provided // container attribute needs to be passed through to the current component // or of we need to split the container by passing along instances of its // value type // if the expected attribute of the current component is neither a Fusion // sequence nor a container, we will pass through the provided container // only if its value type is not compatible with the component template struct pass_through_container_base : negate_weak_substitute_if_not {}; // Specialization for fusion sequences, in this case we check whether all // the types in the sequence are convertible to the lhs attribute. // // We return false if the rhs attribute itself is a fusion sequence, which // is compatible with the LHS sequence (we want to pass through this // attribute without it being split apart). template struct not_compatible_element : mpl::and_< negate_weak_substitute_if_not , negate_weak_substitute_if_not > {}; // If the value type of the container is not a Fusion sequence, we pass // through the container if each of the elements of the Attribute // sequence is compatible with either the container or its value type. template ::value> struct pass_through_container_fusion_sequence { typedef typename mpl::find_if< Attribute, not_compatible_element >::type iter; typedef typename mpl::end::type end; typedef typename is_same::type type; }; // If both, the Attribute and the value type of the provided container // are Fusion sequences, we pass the container only if the two // sequences are not compatible. template struct pass_through_container_fusion_sequence< Container, ValueType, Attribute, Sequence, true> { typedef typename mpl::find_if< Attribute , not_compatible_element >::type iter; typedef typename mpl::end::type end; typedef typename is_same::type type; }; template struct pass_through_container_base >::type> : pass_through_container_fusion_sequence< Container, ValueType, Attribute, Sequence> {}; // Specialization for containers // // If the value type of the attribute of the current component is not // a Fusion sequence, we have to pass through the provided container if // both are compatible. template ::value> struct pass_through_container_container : mpl::or_< traits::is_weak_substitute , traits::is_weak_substitute > {}; // If the value type of the exposed container attribute is a Fusion // sequence, we use the already existing logic for those. template struct pass_through_container_container< Container, ValueType, Attribute, Sequence, AttributeValueType, true> : pass_through_container_fusion_sequence< Container, ValueType, AttributeValueType, Sequence> {}; template struct pass_through_container_base >::type> : detail::pass_through_container_container< Container, ValueType, Attribute, Sequence , typename traits::container_value::type> {}; // Specialization for exposed optional attributes // // If the type embedded in the exposed optional is not a Fusion // sequence we pass through the container attribute if it is compatible // either to the optionals embedded type or to the containers value // type. template ::value> struct pass_through_container_optional : mpl::or_< traits::is_weak_substitute , traits::is_weak_substitute > {}; // If the embedded type of the exposed optional attribute is a Fusion // sequence, we use the already existing logic for those. template struct pass_through_container_optional< Container, ValueType, Attribute, Sequence, true> : pass_through_container_fusion_sequence< Container, ValueType, Attribute, Sequence> {}; /////////////////////////////////////////////////////////////////////////// template struct pass_through_container : pass_through_container_base {}; // Handle optional attributes template struct pass_through_container< Container, ValueType, boost::optional, Sequence> : pass_through_container_optional< Container, ValueType, Attribute, Sequence> {}; // If both, the containers value type and the exposed attribute type are // optionals we are allowed to pass through the container only if the // embedded types of those optionals are not compatible. template struct pass_through_container< Container, boost::optional, boost::optional , Sequence> : mpl::not_ > {}; // Specialization for exposed variant attributes // // We pass through the container attribute if at least one of the embedded // types in the variant requires to pass through the attribute #if !defined(BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES) template struct pass_through_container , Sequence> : pass_through_container {}; template struct pass_through_container, Sequence> : mpl::bool_::type::value || pass_through_container< Container, ValueType, boost::variant, Sequence >::type::value> {}; #else #define BOOST_SPIRIT_PASS_THROUGH_CONTAINER(z, N, _) \ pass_through_container::type::value || \ /***/ // make sure unused variant parameters do not affect the outcome template struct pass_through_container : mpl::false_ {}; template struct pass_through_container, Sequence> : mpl::bool_ {}; #undef BOOST_SPIRIT_PASS_THROUGH_CONTAINER #endif }}}} /////////////////////////////////////////////////////////////////////////////// namespace boost { namespace spirit { namespace traits { /////////////////////////////////////////////////////////////////////////// // forwarding customization point for domain karma::domain template struct pass_through_container< Container, ValueType, Attribute, Sequence, karma::domain> : karma::detail::pass_through_container< Container, ValueType, Attribute, Sequence> {}; }}} namespace boost { namespace spirit { namespace karma { namespace detail { template struct pass_container_base { pass_container_base(Iterator begin, Iterator end) : iter(begin), end(end) {} mutable Iterator iter; mutable Iterator end; }; template struct pass_container_base { pass_container_base(Iterator& begin, Iterator& end) : iter(begin), end(end) {} Iterator& iter; Iterator& end; }; /////////////////////////////////////////////////////////////////////////// // 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 : pass_container_base { typedef pass_container_base base_type; typedef typename F::context_type context_type; pass_container(F const& f, Iterator begin, Iterator end) : base_type(begin, end) , f(f) {} bool is_at_end() const { return traits::compare(this->iter, this->end); } void next() { traits::next(this->iter); } // 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_container(Component const& component, mpl::false_) const { // get the next value to generate from container if (!is_at_end() && !f(component, traits::deref(this->iter))) { // needs to return false as long as everything is ok traits::next(this->iter); return false; } // either no elements available any more or generation failed return true; } // this is for the case when the current element is able to handle an // attribute which is a container itself, this element will push its // data directly into the attribute container template bool dispatch_container(Component const& component, mpl::true_) const { return f(component, make_iterator_range(this->iter, this->end)); } /////////////////////////////////////////////////////////////////////// // 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); } // the current element expects an attribute template bool dispatch_attribute(Component const& component, mpl::true_) const { typedef typename traits::container_value::type value_type; typedef typename traits::attribute_of::type lhs_attribute; // this predicate detects, whether the value type of the container // attribute is a substitute for the attribute of the current // element typedef mpl::and_< traits::handles_container , traits::pass_through_container< Attr, value_type, lhs_attribute, Sequence, karma::domain> > predicate; return dispatch_container(component, predicate()); } // Dispatches to dispatch_main depending on the attribute type // of the Component template bool operator()(Component const& component) const { // we need to dispatch 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()); } F f; private: // silence MSVC warning C4512: assignment operator could not be generated pass_container& operator= (pass_container const&); }; }}}} #endif