// Copyright David Abrahams 2002.

// 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)

#ifndef DEF_HELPER_DWA200287_HPP

# define DEF_HELPER_DWA200287_HPP



# include <boost/python/args.hpp>

# include <boost/type_traits/ice.hpp>

# include <boost/type_traits/same_traits.hpp>

# include <boost/python/detail/indirect_traits.hpp>

# include <boost/mpl/not.hpp>

# include <boost/mpl/and.hpp>

# include <boost/mpl/or.hpp>

# include <boost/type_traits/add_reference.hpp>

# include <boost/mpl/lambda.hpp>

# include <boost/mpl/apply.hpp>

# include <boost/tuple/tuple.hpp>

# include <boost/python/detail/not_specified.hpp>

# include <boost/python/detail/def_helper_fwd.hpp>



namespace boost { namespace python {



struct default_call_policies;



namespace detail

{

  // tuple_extract<Tuple,Predicate>::extract(t) returns the first

  // element of a Tuple whose type E satisfies the given Predicate

  // applied to add_reference<E>. The Predicate must be an MPL

  // metafunction class.

  template <class Tuple, class Predicate>

  struct tuple_extract;



  // Implementation class for when the tuple's head type does not

  // satisfy the Predicate

  template <bool matched>

  struct tuple_extract_impl

  {

      template <class Tuple, class Predicate>

      struct apply

      {

          typedef typename Tuple::head_type result_type;

          

          static typename Tuple::head_type extract(Tuple const& x)

          {

              return x.get_head();

          }

      };

  };



  // Implementation specialization for when the tuple's head type

  // satisfies the predicate

  template <>

  struct tuple_extract_impl<false>

  {

      template <class Tuple, class Predicate>

      struct apply

      {

          // recursive application of tuple_extract on the tail of the tuple

          typedef tuple_extract<typename Tuple::tail_type, Predicate> next;

          typedef typename next::result_type result_type;

          

          static result_type extract(Tuple const& x)

          {

              return next::extract(x.get_tail());

          }

      };

  };



  // A metafunction which selects a version of tuple_extract_impl to

  // use for the implementation of tuple_extract

  template <class Tuple, class Predicate>

  struct tuple_extract_base_select

  {

      typedef typename Tuple::head_type head_type;

      typedef typename mpl::apply1<Predicate, typename add_reference<head_type>::type>::type match_t;

      BOOST_STATIC_CONSTANT(bool, match = match_t::value);

      typedef typename tuple_extract_impl<match>::template apply<Tuple,Predicate> type;

  };

  

  template <class Tuple, class Predicate>

  struct tuple_extract

      : tuple_extract_base_select<

         Tuple

         , typename mpl::lambda<Predicate>::type

      >::type

  {

  };





  //

  // Specialized extractors for the docstring, keywords, CallPolicies,

  // and default implementation of virtual functions

  //



  template <class Tuple>

  struct doc_extract

      : tuple_extract<

        Tuple

        , mpl::not_<

           mpl::or_<

               indirect_traits::is_reference_to_class<mpl::_1>

             , indirect_traits::is_reference_to_member_function_pointer<mpl::_1 >

           >

        >

     >

  {

  };

  

  template <class Tuple>

  struct keyword_extract

      : tuple_extract<Tuple, is_reference_to_keywords<mpl::_1 > >

  {

  };



  template <class Tuple>

  struct policy_extract

      : tuple_extract<

          Tuple

          , mpl::and_<

             mpl::not_<is_same<not_specified const&,mpl::_1> >

              , indirect_traits::is_reference_to_class<mpl::_1 >

              , mpl::not_<is_reference_to_keywords<mpl::_1 > >

          >

        >

  {

  };



  template <class Tuple>

  struct default_implementation_extract

      : tuple_extract<

          Tuple

          , indirect_traits::is_reference_to_member_function_pointer<mpl::_1 >

          >

  {

  };



  //

  // A helper class for decoding the optional arguments to def()

  // invocations, which can be supplied in any order and are

  // discriminated by their type properties. The template parameters

  // are expected to be the types of the actual (optional) arguments

  // passed to def().

  //

  template <class T1, class T2, class T3, class T4>

  struct def_helper

  {

      // A tuple type which begins with references to the supplied

      // arguments and ends with actual representatives of the default

      // types.

      typedef boost::tuples::tuple<

          T1 const&

          , T2 const&

          , T3 const&

          , T4 const&

          , default_call_policies

          , detail::keywords<0>

          , char const*

          , void(not_specified::*)()   // A function pointer type which is never an

                                       // appropriate default implementation

          > all_t;



      // Constructors; these initialize an member of the tuple type

      // shown above.

      def_helper(T1 const& a1) : m_all(a1,m_nil,m_nil,m_nil) {}

      def_helper(T1 const& a1, T2 const& a2) : m_all(a1,a2,m_nil,m_nil) {}

      def_helper(T1 const& a1, T2 const& a2, T3 const& a3) : m_all(a1,a2,a3,m_nil) {}

      def_helper(T1 const& a1, T2 const& a2, T3 const& a3, T4 const& a4) : m_all(a1,a2,a3,a4) {}



   private: // types

      typedef typename default_implementation_extract<all_t>::result_type default_implementation_t;

      

   public: // Constants which can be used for static assertions.



      // Users must not supply a default implementation for non-class

      // methods.

      BOOST_STATIC_CONSTANT(

          bool, has_default_implementation = (

              !is_same<default_implementation_t, void(not_specified::*)()>::value));

      

   public: // Extractor functions which pull the appropriate value out

           // of the tuple

      char const* doc() const

      {

          return doc_extract<all_t>::extract(m_all);

      }

      

      typename keyword_extract<all_t>::result_type keywords() const

      {

          return keyword_extract<all_t>::extract(m_all);

      }

      

      typename policy_extract<all_t>::result_type policies() const

      {

          return policy_extract<all_t>::extract(m_all);

      }



      default_implementation_t default_implementation() const

      {

          return default_implementation_extract<all_t>::extract(m_all);

      }

      

   private: // data members

      all_t m_all; 

      not_specified m_nil; // for filling in not_specified slots

  };

}



}} // namespace boost::python::detail



#endif // DEF_HELPER_DWA200287_HPP

