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