Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-19 09:47:36

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