PageRenderTime 36ms CodeModel.GetById 10ms app.highlight 21ms RepoModel.GetById 1ms app.codeStats 0ms

/Src/Dependencies/Boost/boost/spirit/home/karma/detail/pass_container.hpp

http://hadesmem.googlecode.com/
C++ Header | 350 lines | 225 code | 42 blank | 83 comment | 3 complexity | 3acd396be550dde14927fe8933bff4d4 MD5 | raw file
  1/*=============================================================================
  2    Copyright (c) 2001-2011 Hartmut Kaiser
  3    Copyright (c) 2001-2011 Joel de Guzman
  4
  5    Distributed under the Boost Software License, Version 1.0. (See accompanying
  6    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  7=============================================================================*/
  8#if !defined(SPIRIT_PASS_CONTAINER_MAR_15_2009_0114PM)
  9#define SPIRIT_PASS_CONTAINER_MAR_15_2009_0114PM
 10
 11#if defined(_MSC_VER)
 12#pragma once
 13#endif
 14
 15#include <boost/spirit/home/karma/detail/attributes.hpp>
 16#include <boost/spirit/home/support/container.hpp>
 17#include <boost/spirit/home/support/handles_container.hpp>
 18#include <boost/spirit/home/support/detail/hold_any.hpp>
 19#include <boost/type_traits/is_base_of.hpp>
 20#include <boost/type_traits/is_convertible.hpp>
 21#include <boost/mpl/bool.hpp>
 22#include <boost/mpl/and.hpp>
 23#include <boost/mpl/or.hpp>
 24#include <boost/preprocessor/cat.hpp>
 25#include <boost/preprocessor/repetition/repeat.hpp>
 26#include <boost/range/iterator_range.hpp>
 27#include <boost/fusion/include/deduce_sequence.hpp>
 28
 29#include <boost/mpl/print.hpp>
 30
 31namespace boost { namespace spirit { namespace karma { namespace detail
 32{
 33    // Helper meta-function allowing to evaluate weak substitutability and
 34    // negate the result if the predicate (Sequence) is not true
 35    template <typename Sequence, typename Attribute, typename ValueType>
 36    struct negate_weak_substitute_if_not
 37      : mpl::if_<
 38            Sequence
 39          , typename traits::is_weak_substitute<Attribute, ValueType>::type
 40          , typename mpl::not_<
 41                traits::is_weak_substitute<Attribute, ValueType> 
 42            >::type>
 43    {};
 44
 45    // pass_through_container: utility to check decide whether a provided 
 46    // container attribute needs to be passed through to the current component 
 47    // or of we need to split the container by passing along instances of its
 48    // value type
 49
 50    // if the expected attribute of the current component is neither a Fusion 
 51    // sequence nor a container, we will pass through the provided container 
 52    // only if its value type is not compatible with the component
 53    template <typename Container, typename ValueType, typename Attribute
 54      , typename Sequence, typename Enable = void>
 55    struct pass_through_container_base
 56      : negate_weak_substitute_if_not<Sequence, ValueType, Attribute>
 57    {};
 58
 59    // Specialization for fusion sequences, in this case we check whether all
 60    // the types in the sequence are convertible to the lhs attribute.
 61    // 
 62    // We return false if the rhs attribute itself is a fusion sequence, which
 63    // is compatible with the LHS sequence (we want to pass through this 
 64    // attribute without it being split apart).
 65    template <typename Container, typename ValueType, typename Attribute
 66      , typename Sequence = mpl::true_>
 67    struct not_compatible_element
 68      : mpl::and_<
 69            negate_weak_substitute_if_not<Sequence, Container, Attribute>
 70          , negate_weak_substitute_if_not<Sequence, ValueType, Attribute> >
 71    {};
 72
 73    // If the value type of the container is not a Fusion sequence, we pass
 74    // through the container if each of the elements of the Attribute 
 75    // sequence is compatible with either the container or its value type.
 76    template <typename Container, typename ValueType, typename Attribute
 77      , typename Sequence
 78      , bool IsSequence = fusion::traits::is_sequence<ValueType>::value>
 79    struct pass_through_container_fusion_sequence
 80    {
 81        typedef typename mpl::find_if<
 82            Attribute, not_compatible_element<Container, ValueType, mpl::_1>
 83        >::type iter;
 84        typedef typename mpl::end<Attribute>::type end;
 85
 86        typedef typename is_same<iter, end>::type type;
 87    };
 88
 89    // If both, the Attribute and the value type of the provided container
 90    // are Fusion sequences, we pass the container only if the two 
 91    // sequences are not compatible.
 92    template <typename Container, typename ValueType, typename Attribute
 93      , typename Sequence>
 94    struct pass_through_container_fusion_sequence<
 95            Container, ValueType, Attribute, Sequence, true>
 96    {
 97        typedef typename mpl::find_if<
 98            Attribute
 99          , not_compatible_element<Container, ValueType, mpl::_1, Sequence>
100        >::type iter;
101        typedef typename mpl::end<Attribute>::type end;
102
103        typedef typename is_same<iter, end>::type type;
104    };
105
106    template <typename Container, typename ValueType, typename Attribute
107      , typename Sequence>
108    struct pass_through_container_base<Container, ValueType, Attribute
109          , Sequence
110          , typename enable_if<fusion::traits::is_sequence<Attribute> >::type>
111      : pass_through_container_fusion_sequence<
112            Container, ValueType, Attribute, Sequence>
113    {};
114
115    // Specialization for containers
116    //
117    // If the value type of the attribute of the current component is not
118    // a Fusion sequence, we have to pass through the provided container if 
119    // both are compatible.
120    template <typename Container, typename ValueType, typename Attribute
121      , typename Sequence, typename AttributeValueType
122      , bool IsSequence = fusion::traits::is_sequence<AttributeValueType>::value>
123    struct pass_through_container_container
124      : mpl::or_<
125            traits::is_weak_substitute<Container, Attribute> 
126          , traits::is_weak_substitute<Container, AttributeValueType> >
127    {};
128
129    // If the value type of the exposed container attribute is a Fusion
130    // sequence, we use the already existing logic for those.
131    template <typename Container, typename ValueType, typename Attribute
132      , typename Sequence, typename AttributeValueType>
133    struct pass_through_container_container<
134            Container, ValueType, Attribute, Sequence, AttributeValueType, true>
135      : pass_through_container_fusion_sequence<
136            Container, ValueType, AttributeValueType, Sequence>
137    {};
138
139    template <typename Container, typename ValueType, typename Attribute
140      , typename Sequence>
141    struct pass_through_container_base<Container, ValueType, Attribute
142          , Sequence
143          , typename enable_if<traits::is_container<Attribute> >::type>
144      : detail::pass_through_container_container<
145          Container, ValueType, Attribute, Sequence
146        , typename traits::container_value<Attribute>::type>
147    {};
148
149    // Specialization for exposed optional attributes
150    //
151    // If the type embedded in the exposed optional is not a Fusion 
152    // sequence we pass through the container attribute if it is compatible
153    // either to the optionals embedded type or to the containers value 
154    // type.
155    template <typename Container, typename ValueType, typename Attribute
156      , typename Sequence
157      , bool IsSequence = fusion::traits::is_sequence<Attribute>::value>
158    struct pass_through_container_optional
159      : mpl::or_<
160            traits::is_weak_substitute<Container, Attribute> 
161          , traits::is_weak_substitute<ValueType, Attribute> >
162    {};
163
164    // If the embedded type of the exposed optional attribute is a Fusion
165    // sequence, we use the already existing logic for those.
166    template <typename Container, typename ValueType, typename Attribute
167      , typename Sequence>
168    struct pass_through_container_optional<
169            Container, ValueType, Attribute, Sequence, true>
170      : pass_through_container_fusion_sequence<
171            Container, ValueType, Attribute, Sequence>
172    {};
173
174    ///////////////////////////////////////////////////////////////////////////
175    template <typename Container, typename ValueType, typename Attribute
176      , typename Sequence>
177    struct pass_through_container
178      : pass_through_container_base<Container, ValueType, Attribute, Sequence> 
179    {};
180
181    // Handle optional attributes
182    template <typename Container, typename ValueType, typename Attribute
183      , typename Sequence>
184    struct pass_through_container<
185            Container, ValueType, boost::optional<Attribute>, Sequence>
186      : pass_through_container_optional<
187            Container, ValueType, Attribute, Sequence> 
188    {};
189
190    // If both, the containers value type and the exposed attribute type are
191    // optionals we are allowed to pass through the the container only if the
192    // embedded types of those optionals are not compatible.
193    template <typename Container, typename ValueType, typename Attribute
194      , typename Sequence>
195    struct pass_through_container<
196            Container, boost::optional<ValueType>, boost::optional<Attribute>
197          , Sequence>
198      : mpl::not_<traits::is_weak_substitute<ValueType, Attribute> >
199    {};
200
201    // Specialization for exposed variant attributes
202    // 
203    // We pass through the container attribute if at least one of the embedded 
204    // types in the variant requires to pass through the attribute
205
206#define BOOST_SPIRIT_PASS_THROUGH_CONTAINER(z, N, _)                          \
207    pass_through_container<Container, ValueType,                              \
208        BOOST_PP_CAT(T, N), Sequence>::type::value ||                         \
209    /***/
210
211    // make sure unused variant parameters do not affect the outcome
212    template <typename Container, typename ValueType, typename Sequence>
213    struct pass_through_container<Container, ValueType
214          , boost::detail::variant::void_, Sequence>
215      : mpl::false_
216    {};
217
218    template <typename Container, typename ValueType, typename Sequence
219      , BOOST_VARIANT_ENUM_PARAMS(typename T)>
220    struct pass_through_container<Container, ValueType
221          , boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Sequence>
222      : mpl::bool_<BOOST_PP_REPEAT(BOOST_VARIANT_LIMIT_TYPES
223          , BOOST_SPIRIT_PASS_THROUGH_CONTAINER, _) false>
224    {};
225
226#undef BOOST_SPIRIT_PASS_THROUGH_CONTAINER
227}}}}
228
229///////////////////////////////////////////////////////////////////////////////
230namespace boost { namespace spirit { namespace traits
231{
232    ///////////////////////////////////////////////////////////////////////////
233    // forwarding customization point for domain karma::domain
234    template <typename Container, typename ValueType, typename Attribute
235      , typename Sequence>
236    struct pass_through_container<
237            Container, ValueType, Attribute, Sequence, karma::domain>
238      : karma::detail::pass_through_container<
239            Container, ValueType, Attribute, Sequence>
240    {};
241}}}
242
243namespace boost { namespace spirit { namespace karma { namespace detail
244{
245    ///////////////////////////////////////////////////////////////////////////
246    // This function handles the case where the attribute (Attr) given
247    // to the sequence is an STL container. This is a wrapper around F.
248    // The function F does the actual generating.
249    template <typename F, typename Attr, typename Iterator, typename Sequence>
250    struct pass_container
251    {
252        typedef typename F::context_type context_type;
253
254        pass_container(F const& f, Iterator begin, Iterator end)
255          : f(f), iter(begin), end(end) 
256        {}
257
258        bool is_at_end() const
259        {
260            return traits::compare(iter, end);
261        }
262
263        void next()
264        {
265            traits::next(iter);
266        }
267
268        // this is for the case when the current element expects an attribute
269        // which is taken from the next entry in the container
270        template <typename Component>
271        bool dispatch_container(Component const& component, mpl::false_) const
272        {
273            // get the next value to generate from container
274            if (!is_at_end() && !f(component, traits::deref(iter))) 
275            {
276                // needs to return false as long as everything is ok
277                traits::next(iter);
278                return false;
279            }
280
281            // either no elements available any more or generation failed
282            return true;
283        }
284
285        // this is for the case when the current element is able to handle an 
286        // attribute which is a container itself, this element will push its 
287        // data directly into the attribute container
288        template <typename Component>
289        bool dispatch_container(Component const& component, mpl::true_) const
290        {
291            return f(component, make_iterator_range(iter, end));
292        }
293
294        ///////////////////////////////////////////////////////////////////////
295        // this is for the case when the current element doesn't expect an 
296        // attribute
297        template <typename Component>
298        bool dispatch_attribute(Component const& component, mpl::false_) const
299        {
300            return f(component, unused);
301        }
302
303        // the current element expects an attribute
304        template <typename Component>
305        bool dispatch_attribute(Component const& component, mpl::true_) const
306        {
307            typedef typename traits::container_value<Attr>::type value_type;
308            typedef typename 
309                traits::attribute_of<Component, context_type>::type
310            lhs_attribute;
311
312            // this predicate detects, whether the value type of the container
313            // attribute is a substitute for the attribute of the current 
314            // element 
315            typedef mpl::and_<
316                traits::handles_container<Component, Attr, context_type> 
317              , traits::pass_through_container<
318                    Attr, value_type, lhs_attribute, Sequence, karma::domain>
319            > predicate;
320
321            return dispatch_container(component, predicate());
322        }
323
324        // Dispatches to dispatch_main depending on the attribute type
325        // of the Component
326        template <typename Component>
327        bool operator()(Component const& component) const
328        {
329            // we need to dispatch depending on the type of the attribute
330            // of the current element (component). If this is has no attribute
331            // we shouldn't use an element of the container but unused_type 
332            // instead
333            typedef traits::not_is_unused<
334                typename traits::attribute_of<Component, context_type>::type
335            > predicate;
336
337            return dispatch_attribute(component, predicate());
338        }
339
340        F f;
341        mutable Iterator iter;
342        mutable Iterator end;
343
344    private:
345        // silence MSVC warning C4512: assignment operator could not be generated
346        pass_container& operator= (pass_container const&);
347    };
348}}}}
349
350#endif