text: /*=============================================================================
      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 <boost/spirit/home/karma/detail/attributes.hpp>
  #include <boost/spirit/home/support/container.hpp>
  #include <boost/spirit/home/support/handles_container.hpp>
  #include <boost/spirit/home/support/detail/hold_any.hpp>
  #include <boost/type_traits/is_base_of.hpp>
  #include <boost/type_traits/is_convertible.hpp>
  #include <boost/mpl/bool.hpp>
  #include <boost/mpl/or.hpp>
  #include <boost/preprocessor/cat.hpp>
  #include <boost/preprocessor/repeat.hpp>
  #include <boost/range/iterator_range.hpp>
  #include <boost/iterator/iterator_facade.hpp>
  
  namespace boost { namespace spirit { namespace karma { namespace detail
  {
      // has_same_elements: utility to check if the LHS attribute
      // is an STL container and that its value_type is convertible
      // to the RHS.
  
      template <typename RHS, typename LHSAttribute
        , bool IsContainer = traits::is_container<LHSAttribute>::value>
      struct has_same_elements : mpl::false_ {};
  
      template <typename RHS, typename LHSAttribute>
      struct has_same_elements<RHS, LHSAttribute, true>
        : mpl::or_<
              is_convertible<RHS, typename LHSAttribute::value_type>
            , is_same<typename LHSAttribute::value_type, hold_any>
          > {};
  
      template <typename RHS, typename T>
      struct has_same_elements<RHS, optional<T>, true>
        : has_same_elements<RHS, T> {};
  
  #define BOOST_SPIRIT_IS_CONVERTIBLE(z, N, data)                               \
          has_same_elements<RHS, BOOST_PP_CAT(T, N)>::value ||                  \
      /***/
  
      // Note: variants are treated as containers if one of the held types is a
      //       container (see support/container.hpp).
      template <typename RHS, BOOST_VARIANT_ENUM_PARAMS(typename T)>
      struct has_same_elements<
              RHS, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, true>
        : mpl::bool_<BOOST_PP_REPEAT(BOOST_VARIANT_LIMIT_TYPES
            , BOOST_SPIRIT_IS_CONVERTIBLE, _) false> {};
  
  #undef BOOST_SPIRIT_IS_CONVERTIBLE
  
      ///////////////////////////////////////////////////////////////////////////
      // 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 <typename F, typename Attr, typename Iterator, typename Strict>
      struct pass_container
      {
          typedef typename F::context_type context_type;
  
          pass_container(F const& f, Iterator begin, Iterator end)
            : f(f), iter(begin), end(end) 
          {}
  
          // this is for the case when the current element expects an attribute
          // which is taken from the next entry in the container
          template <typename Component>
          bool dispatch_attribute_element(Component const& component, mpl::false_) const
          {
              // get the next value to generate from container
              if (!traits::compare(iter, end) && !f(component, traits::deref(iter))) 
              {
                  // needs to return false as long as everything is ok
                  traits::next(iter);
                  return false;
              }
              // either no elements available any more or generation failed
              return true;
          }
  
          // This is for the case when the current element expects an attribute
          // which is a container itself, this element will get the rest of the 
          // attribute container.
          template <typename Component>
          bool dispatch_attribute_element(Component const& component, mpl::true_) const
          {
              return f(component, make_iterator_range(iter, end));
          }
  
          // This handles the distinction between elements in a sequence expecting
          // containers themselves and elements expecting non-containers as their 
          // attribute. Note: is_container treats optional<T>, where T is a 
          // container as a container as well.
          template <typename Component>
          bool dispatch_attribute(Component const& component, mpl::true_) const
          {
              typedef typename traits::attribute_of<
                  Component, context_type>::type attribute_type;
  
  //             typedef mpl::and_<
  //                 traits::is_container<attribute_type>
  //               , is_convertible<Attr, attribute_type> > predicate;
  
              typedef mpl::and_<
                  traits::is_container<attribute_type>
                , traits::handles_container<Component, Attr, context_type>
              > predicate;
  
              return dispatch_attribute_element(component, predicate());
          }
  
          // this is for the case when the current element doesn't expect an 
          // attribute
          template <typename Component>
          bool dispatch_attribute(Component const& component, mpl::false_) const
          {
              return f(component, unused);
          }
  
          // This handles the case where the attribute of the component
          // is not a STL container or which elements are not 
          // convertible to the target attribute (Attr) value_type.
          template <typename Component>
          bool dispatch_main(Component const& component, mpl::false_) const
          {
              // we need to dispatch again 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<Component, context_type>::type
              > predicate;
  
              return dispatch_attribute(component, predicate());
          }
  
          // This handles the case where the attribute of the component is
          // an STL container *and* its value_type is convertible to the
          // target attribute's (Attr) value_type.
          template <typename Component>
          bool dispatch_main(Component const& component, mpl::true_) const
          {
              return f(component, make_iterator_range(iter, end));
          }
  
          // Dispatches to dispatch_main depending on the attribute type
          // of the Component
          template <typename Component>
          bool operator()(Component const& component) const
          {
              typedef typename traits::container_value<Attr>::type rhs;
              typedef typename traits::attribute_of<
                  Component, context_type>::type lhs_attribute;
  
              typedef mpl::and_<
                  has_same_elements<rhs, lhs_attribute>
                , traits::handles_container<Component, Attr, context_type>
              > predicate;
  
              // false means everything went ok
              return dispatch_main(component, predicate());
          }
  
          F f;
          mutable Iterator iter;
          mutable Iterator end;
  
      private:
          // silence MSVC warning C4512: assignment operator could not be generated
          pass_container& operator= (pass_container const&);
      };
  }}}}
  
  #endif
  