Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2024-11-15 09:31:47

0001 /*=============================================================================
0002     Copyright (c) 2001-2011 Joel de Guzman
0003     Copyright (c) 2001-2011 Hartmut Kaiser
0004 
0005     Distributed under the Boost Software License, Version 1.0. (See accompanying
0006     file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0007 =============================================================================*/
0008 #ifndef BOOST_SPIRIT_QI_DETAIL_PASS_CONTAINER_HPP
0009 #define BOOST_SPIRIT_QI_DETAIL_PASS_CONTAINER_HPP
0010 
0011 #if defined(_MSC_VER)
0012 #pragma once
0013 #endif
0014 
0015 #include <boost/spirit/home/qi/detail/attributes.hpp>
0016 #include <boost/spirit/home/support/container.hpp>
0017 #include <boost/spirit/home/support/handles_container.hpp>
0018 #include <boost/type_traits/is_base_of.hpp>
0019 #include <boost/type_traits/is_convertible.hpp>
0020 #include <boost/mpl/bool.hpp>
0021 #include <boost/mpl/and.hpp>
0022 #include <boost/mpl/or.hpp>
0023 #include <boost/preprocessor/cat.hpp>
0024 #include <boost/preprocessor/repetition/repeat.hpp>
0025 
0026 namespace boost { namespace spirit { namespace qi { namespace detail
0027 {
0028     // Helper meta-function allowing to evaluate weak substitutability and
0029     // negate the result if the predicate (Sequence) is not true
0030     template <typename Sequence, typename Attribute, typename ValueType>
0031     struct negate_weak_substitute_if_not
0032       : mpl::if_<
0033             Sequence
0034           , typename traits::is_weak_substitute<Attribute, ValueType>::type
0035           , typename mpl::not_<
0036                 traits::is_weak_substitute<Attribute, ValueType>
0037             >::type>
0038     {};
0039 
0040     // pass_through_container: utility to check decide whether a provided
0041     // container attribute needs to be passed through to the current component
0042     // or of we need to split the container by passing along instances of its
0043     // value type
0044 
0045     // if the expected attribute of the current component is neither a Fusion
0046     // sequence nor a container, we will pass through the provided container
0047     // only if its value type is not compatible with the component
0048     template <typename Container, typename ValueType, typename Attribute
0049       , typename Sequence, typename Enable = void>
0050     struct pass_through_container_base
0051       : negate_weak_substitute_if_not<Sequence, Attribute, ValueType>
0052     {};
0053 
0054     // Specialization for fusion sequences, in this case we check whether all
0055     // the types in the sequence are convertible to the lhs attribute.
0056     //
0057     // We return false if the rhs attribute itself is a fusion sequence, which
0058     // is compatible with the LHS sequence (we want to pass through this
0059     // attribute without it being split apart).
0060     template <typename Container, typename ValueType, typename Attribute
0061       , typename Sequence = mpl::true_>
0062     struct not_compatible_element
0063       : mpl::and_<
0064             negate_weak_substitute_if_not<Sequence, Attribute, Container>
0065           , negate_weak_substitute_if_not<Sequence, Attribute, ValueType> >
0066     {};
0067 
0068     // If the value type of the container is not a Fusion sequence, we pass
0069     // through the container if each of the elements of the Attribute
0070     // sequence is compatible with either the container or its value type.
0071     template <typename Container, typename ValueType, typename Attribute
0072       , typename Sequence
0073       , bool IsSequence = fusion::traits::is_sequence<ValueType>::value>
0074     struct pass_through_container_fusion_sequence
0075     {
0076         typedef typename mpl::find_if<
0077             Attribute, not_compatible_element<Container, ValueType, mpl::_1>
0078         >::type iter;
0079         typedef typename mpl::end<Attribute>::type end;
0080 
0081         typedef typename is_same<iter, end>::type type;
0082     };
0083 
0084     // If both, the Attribute and the value type of the provided container
0085     // are Fusion sequences, we pass the container only if the two
0086     // sequences are not compatible.
0087     template <typename Container, typename ValueType, typename Attribute
0088       , typename Sequence>
0089     struct pass_through_container_fusion_sequence<
0090             Container, ValueType, Attribute, Sequence, true>
0091     {
0092         typedef typename mpl::find_if<
0093             Attribute
0094           , not_compatible_element<Container, ValueType, mpl::_1, Sequence>
0095         >::type iter;
0096         typedef typename mpl::end<Attribute>::type end;
0097 
0098         typedef typename is_same<iter, end>::type type;
0099     };
0100 
0101     template <typename Container, typename ValueType, typename Attribute
0102       , typename Sequence>
0103     struct pass_through_container_base<Container, ValueType, Attribute
0104           , Sequence
0105           , typename enable_if<fusion::traits::is_sequence<Attribute> >::type>
0106       : pass_through_container_fusion_sequence<
0107             Container, ValueType, Attribute, Sequence>
0108     {};
0109 
0110     // Specialization for containers
0111     //
0112     // If the value type of the attribute of the current component is not
0113     // a Fusion sequence, we have to pass through the provided container if
0114     // both are compatible.
0115     template <typename Container, typename ValueType, typename Attribute
0116       , typename Sequence, typename AttributeValueType
0117       , bool IsSequence = fusion::traits::is_sequence<AttributeValueType>::value>
0118     struct pass_through_container_container
0119       : mpl::or_<
0120             traits::is_weak_substitute<Attribute, Container>
0121           , traits::is_weak_substitute<AttributeValueType, Container> >
0122     {};
0123 
0124     // If the value type of the exposed container attribute is a Fusion
0125     // sequence, we use the already existing logic for those.
0126     template <typename Container, typename ValueType, typename Attribute
0127       , typename Sequence, typename AttributeValueType>
0128     struct pass_through_container_container<
0129             Container, ValueType, Attribute, Sequence, AttributeValueType, true>
0130       : pass_through_container_fusion_sequence<
0131             Container, ValueType, AttributeValueType, Sequence>
0132     {};
0133 
0134     template <typename Container, typename ValueType, typename Attribute
0135       , typename Sequence>
0136     struct pass_through_container_base<
0137             Container, ValueType, Attribute, Sequence
0138           , typename enable_if<traits::is_container<Attribute> >::type>
0139       : detail::pass_through_container_container<
0140             Container, ValueType, Attribute, Sequence
0141           , typename traits::container_value<Attribute>::type>
0142     {};
0143 
0144     // Specialization for exposed optional attributes
0145     //
0146     // If the type embedded in the exposed optional is not a Fusion
0147     // sequence we pass through the container attribute if it is compatible
0148     // either to the optionals embedded type or to the containers value
0149     // type.
0150     template <typename Container, typename ValueType, typename Attribute
0151       , typename Sequence
0152       , bool IsSequence = fusion::traits::is_sequence<Attribute>::value>
0153     struct pass_through_container_optional
0154       : mpl::or_<
0155             traits::is_weak_substitute<Attribute, Container>
0156           , traits::is_weak_substitute<Attribute, ValueType> >
0157     {};
0158 
0159     // If the embedded type of the exposed optional attribute is a Fusion
0160     // sequence, we use the already existing logic for those.
0161     template <typename Container, typename ValueType, typename Attribute
0162       , typename Sequence>
0163     struct pass_through_container_optional<
0164                 Container, ValueType, Attribute, Sequence, true>
0165       : pass_through_container_fusion_sequence<
0166             Container, ValueType, Attribute, Sequence>
0167     {};
0168 
0169     ///////////////////////////////////////////////////////////////////////////
0170     template <typename Container, typename ValueType, typename Attribute
0171       , typename Sequence>
0172     struct pass_through_container
0173       : pass_through_container_base<Container, ValueType, Attribute, Sequence>
0174     {};
0175 
0176     // Handle optional attributes
0177     template <typename Container, typename ValueType, typename Attribute
0178       , typename Sequence>
0179     struct pass_through_container<
0180                 Container, ValueType, boost::optional<Attribute>, Sequence>
0181       : pass_through_container_optional<
0182             Container, ValueType, Attribute, Sequence>
0183     {};
0184 
0185     // If both, the containers value type and the exposed attribute type are
0186     // optionals we are allowed to pass through the container only if the
0187     // embedded types of those optionals are not compatible.
0188     template <typename Container, typename ValueType, typename Attribute
0189       , typename Sequence>
0190     struct pass_through_container<
0191             Container, boost::optional<ValueType>, boost::optional<Attribute>
0192           , Sequence>
0193       : mpl::not_<traits::is_weak_substitute<Attribute, ValueType> >
0194     {};
0195 
0196     // Specialization for exposed variant attributes
0197     //
0198     // We pass through the container attribute if at least one of the embedded
0199     // types in the variant requires to pass through the attribute
0200 
0201 #if !defined(BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES)
0202     template <typename Container, typename ValueType, typename Sequence
0203       , typename T>
0204     struct pass_through_container<Container, ValueType, boost::variant<T>
0205           , Sequence>
0206       : pass_through_container<Container, ValueType, T, Sequence>
0207     {};
0208 
0209     template <typename Container, typename ValueType, typename Sequence
0210       , typename T0, typename ...TN>
0211     struct pass_through_container<Container, ValueType
0212           , boost::variant<T0, TN...>, Sequence>
0213       : mpl::bool_<pass_through_container<
0214             Container, ValueType, T0, Sequence
0215             >::type::value || pass_through_container<
0216                 Container, ValueType, boost::variant<TN...>, Sequence
0217             >::type::value>
0218     {};
0219 #else
0220 #define BOOST_SPIRIT_PASS_THROUGH_CONTAINER(z, N, _)                          \
0221     pass_through_container<Container, ValueType,                              \
0222         BOOST_PP_CAT(T, N), Sequence>::type::value ||                         \
0223     /***/
0224 
0225     // make sure unused variant parameters do not affect the outcome
0226     template <typename Container, typename ValueType, typename Sequence>
0227     struct pass_through_container<Container, ValueType
0228           , boost::detail::variant::void_, Sequence>
0229       : mpl::false_
0230     {};
0231 
0232     template <typename Container, typename ValueType, typename Sequence
0233       , BOOST_VARIANT_ENUM_PARAMS(typename T)>
0234     struct pass_through_container<Container, ValueType
0235           , boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Sequence>
0236       : mpl::bool_<BOOST_PP_REPEAT(BOOST_VARIANT_LIMIT_TYPES
0237           , BOOST_SPIRIT_PASS_THROUGH_CONTAINER, _) false>
0238     {};
0239 
0240 #undef BOOST_SPIRIT_PASS_THROUGH_CONTAINER
0241 #endif
0242 }}}}
0243 
0244 ///////////////////////////////////////////////////////////////////////////////
0245 namespace boost { namespace spirit { namespace traits
0246 {
0247     ///////////////////////////////////////////////////////////////////////////
0248     // forwarding customization point for domain qi::domain
0249     template <typename Container, typename ValueType, typename Attribute
0250       , typename Sequence>
0251     struct pass_through_container<
0252             Container, ValueType, Attribute, Sequence, qi::domain>
0253       : qi::detail::pass_through_container<
0254             Container, ValueType, Attribute, Sequence>
0255     {};
0256 }}}
0257 
0258 namespace boost { namespace spirit { namespace qi { namespace detail
0259 {
0260     ///////////////////////////////////////////////////////////////////////////
0261     // This function handles the case where the attribute (Attr) given
0262     // the sequence is an STL container. This is a wrapper around F.
0263     // The function F does the actual parsing.
0264 #ifdef _MSC_VER
0265 #  pragma warning(push)
0266 #  pragma warning(disable: 4512) // assignment operator could not be generated.
0267 #endif
0268     template <typename F, typename Attr, typename Sequence>
0269     struct pass_container
0270     {
0271         typedef typename F::context_type context_type;
0272         typedef typename F::iterator_type iterator_type;
0273 
0274         pass_container(F const& f_, Attr& attr_)
0275           : f(f_), attr(attr_) {}
0276 
0277         // this is for the case when the current element exposes an attribute
0278         // which is pushed back onto the container
0279         template <typename Component>
0280         bool dispatch_container(Component const& component, mpl::false_) const
0281         {
0282             // synthesized attribute needs to be default constructed
0283             typename traits::container_value<Attr>::type val =
0284                 typename traits::container_value<Attr>::type();
0285 
0286             iterator_type save = f.first;
0287             bool r = f(component, val);
0288             if (!r)
0289             {
0290                 // push the parsed value into our attribute
0291                 r = !traits::push_back(attr, val);
0292                 if (r)
0293                     f.first = save;
0294             }
0295             return r;
0296         }
0297 
0298         // this is for the case when the current element is able to handle an
0299         // attribute which is a container itself, this element will push its
0300         // data directly into the attribute container
0301         template <typename Component>
0302         bool dispatch_container(Component const& component, mpl::true_) const
0303         {
0304             return f(component, attr);
0305         }
0306 
0307         ///////////////////////////////////////////////////////////////////////
0308         // this is for the case when the current element doesn't expect an
0309         // attribute
0310         template <typename Component>
0311         bool dispatch_attribute(Component const& component, mpl::false_) const
0312         {
0313             return f(component, unused);
0314         }
0315 
0316         // the current element expects an attribute
0317         template <typename Component>
0318         bool dispatch_attribute(Component const& component, mpl::true_) const
0319         {
0320             typedef typename traits::container_value<Attr>::type value_type;
0321             typedef typename traits::attribute_of<
0322                 Component, context_type, iterator_type>::type
0323             rhs_attribute;
0324 
0325             // this predicate detects, whether the attribute of the current
0326             // element is a substitute for the value type of the container
0327             // attribute
0328             typedef mpl::and_<
0329                 traits::handles_container<
0330                     Component, Attr, context_type, iterator_type>
0331               , traits::pass_through_container<
0332                     Attr, value_type, rhs_attribute, Sequence, qi::domain>
0333             > predicate;
0334 
0335             return dispatch_container(component, predicate());
0336         }
0337 
0338         // Dispatches to dispatch_main depending on the attribute type
0339         // of the Component
0340         template <typename Component>
0341         bool operator()(Component const& component) const
0342         {
0343             // we need to dispatch depending on the type of the attribute
0344             // of the current element (component). If this is has no attribute
0345             // we shouldn't pass an attribute at all.
0346             typedef typename traits::not_is_unused<
0347                 typename traits::attribute_of<
0348                     Component, context_type, iterator_type
0349                 >::type
0350             >::type predicate;
0351 
0352             // ensure the attribute is actually a container type
0353             traits::make_container(attr);
0354 
0355             return dispatch_attribute(component, predicate());
0356         }
0357 
0358         F f;
0359         Attr& attr;
0360     };
0361 #ifdef _MSC_VER
0362 #  pragma warning(pop)
0363 #endif
0364 
0365     ///////////////////////////////////////////////////////////////////////////
0366     // Utility function to make a pass_container for container components
0367     // (kleene, list, plus, repeat)
0368     template <typename F, typename Attr>
0369     inline pass_container<F, Attr, mpl::false_>
0370     make_pass_container(F const& f, Attr& attr)
0371     {
0372         return pass_container<F, Attr, mpl::false_>(f, attr);
0373     }
0374 
0375     // Utility function to make a pass_container for sequences
0376     template <typename F, typename Attr>
0377     inline pass_container<F, Attr, mpl::true_>
0378     make_sequence_pass_container(F const& f, Attr& attr)
0379     {
0380         return pass_container<F, Attr, mpl::true_>(f, attr);
0381     }
0382 }}}}
0383 
0384 #endif
0385