source: NonGTP/Boost/boost/python/init.hpp @ 857

Revision 857, 12.1 KB checked in by igarcia, 19 years ago (diff)
RevLine 
[857]1///////////////////////////////////////////////////////////////////////////////
2//
3// Copyright David Abrahams 2002, Joel de Guzman, 2002.
4// Distributed under the Boost Software License, Version 1.0. (See
5// accompanying file LICENSE_1_0.txt or copy at
6// http://www.boost.org/LICENSE_1_0.txt)
7//
8///////////////////////////////////////////////////////////////////////////////
9#ifndef INIT_JDG20020820_HPP
10#define INIT_JDG20020820_HPP
11
12# include <boost/python/detail/prefix.hpp>
13
14#include <boost/python/detail/type_list.hpp>
15#include <boost/python/args_fwd.hpp>
16#include <boost/python/detail/make_keyword_range_fn.hpp>
17#include <boost/python/def_visitor.hpp>
18
19#include <boost/mpl/if.hpp>
20#include <boost/mpl/eval_if.hpp>
21#include <boost/mpl/size.hpp>
22#include <boost/mpl/iterator_range.hpp>
23#include <boost/mpl/empty.hpp>
24#include <boost/mpl/begin_end.hpp>
25#include <boost/mpl/bool.hpp>
26#include <boost/mpl/prior.hpp>
27#include <boost/mpl/joint_view.hpp>
28#include <boost/mpl/back.hpp>
29
30#include <boost/type_traits/is_same.hpp>
31
32#include <boost/preprocessor/enum_params_with_a_default.hpp>
33#include <boost/preprocessor/enum_params.hpp>
34
35#include <utility>
36
37///////////////////////////////////////////////////////////////////////////////
38#define BOOST_PYTHON_OVERLOAD_TYPES_WITH_DEFAULT                                \
39    BOOST_PP_ENUM_PARAMS_WITH_A_DEFAULT(                                        \
40        BOOST_PYTHON_MAX_ARITY,                                                 \
41        class T,                                                                \
42        mpl::void_)                                                             \
43
44#define BOOST_PYTHON_OVERLOAD_TYPES                                             \
45    BOOST_PP_ENUM_PARAMS_Z(1,                                                   \
46        BOOST_PYTHON_MAX_ARITY,                                                 \
47        class T)                                                                \
48
49#define BOOST_PYTHON_OVERLOAD_ARGS                                              \
50    BOOST_PP_ENUM_PARAMS_Z(1,                                                   \
51        BOOST_PYTHON_MAX_ARITY,                                                 \
52        T)                                                                      \
53
54///////////////////////////////////////////////////////////////////////////////
55namespace boost { namespace python {
56
57template <BOOST_PYTHON_OVERLOAD_TYPES_WITH_DEFAULT>
58class init; // forward declaration
59
60
61template <BOOST_PYTHON_OVERLOAD_TYPES_WITH_DEFAULT>
62struct optional; // forward declaration
63
64namespace detail
65{
66  namespace error
67  {
68    template <int keywords, int init_args>
69    struct more_keywords_than_init_arguments
70    {
71        typedef char too_many_keywords[init_args - keywords >= 0 ? 1 : -1];
72    };
73  }
74
75  //  is_optional<T>::value
76  //
77  //      This metaprogram checks if T is an optional
78  //
79#if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
80
81    template <class T>
82    struct is_optional {
83
84    private:
85
86        template <BOOST_PYTHON_OVERLOAD_TYPES>
87        static boost::type_traits::yes_type f(optional<BOOST_PYTHON_OVERLOAD_ARGS>);
88        static boost::type_traits::no_type f(...);
89        static T t();
90
91    public:
92
93        BOOST_STATIC_CONSTANT(
94            bool, value =
95                sizeof(f(t())) == sizeof(::boost::type_traits::yes_type));
96        typedef mpl::bool_<value> type;
97    };
98
99#else
100
101    template <class T>
102    struct is_optional
103      : mpl::false_
104    {};
105
106    template <BOOST_PYTHON_OVERLOAD_TYPES>
107    struct is_optional<optional<BOOST_PYTHON_OVERLOAD_ARGS> >
108      : mpl::true_
109    {};
110 
111#endif
112
113  template <int NDefaults>
114  struct define_class_init_helper;
115
116} // namespace detail
117
118template <class DerivedT>
119struct init_base : def_visitor<DerivedT>
120{
121    init_base(char const* doc_, detail::keyword_range const& keywords_)
122        : m_doc(doc_), m_keywords(keywords_)
123    {}
124       
125    init_base(char const* doc_)
126        : m_doc(doc_)
127    {}
128
129    DerivedT const& derived() const
130    {
131        return *static_cast<DerivedT const*>(this);
132    }
133   
134    char const* doc_string() const
135    {
136        return m_doc;
137    }
138
139    detail::keyword_range const& keywords() const
140    {
141        return m_keywords;
142    }
143
144    static default_call_policies call_policies()
145    {
146        return default_call_policies();
147    }
148
149 private:
150    //  visit
151    //
152    //      Defines a set of n_defaults + 1 constructors for its
153    //      class_<...> argument. Each constructor after the first has
154    //      one less argument to its right. Example:
155    //
156    //          init<int, optional<char, long, double> >
157    //
158    //      Defines:
159    //
160    //          __init__(int, char, long, double)
161    //          __init__(int, char, long)
162    //          __init__(int, char)
163    //          __init__(int)
164    template <class classT>
165    void visit(classT& cl) const
166    {
167        typedef typename DerivedT::signature signature;
168        typedef typename DerivedT::n_arguments n_arguments;
169        typedef typename DerivedT::n_defaults n_defaults;
170   
171        detail::define_class_init_helper<n_defaults::value>::apply(
172            cl
173          , derived().call_policies()
174          , signature()
175          , n_arguments()
176          , derived().doc_string()
177          , derived().keywords());
178    }
179   
180    friend class python::def_visitor_access;
181   
182 private: // data members
183    char const* m_doc;
184    detail::keyword_range m_keywords;
185};
186
187template <class CallPoliciesT, class InitT>
188class init_with_call_policies
189    : public init_base<init_with_call_policies<CallPoliciesT, InitT> >
190{
191    typedef init_base<init_with_call_policies<CallPoliciesT, InitT> > base;
192 public:
193    typedef typename InitT::n_arguments n_arguments;
194    typedef typename InitT::n_defaults n_defaults;
195    typedef typename InitT::signature signature;
196
197    init_with_call_policies(
198        CallPoliciesT const& policies_
199        , char const* doc_
200        , detail::keyword_range const& keywords
201        )
202        : base(doc_, keywords)
203        , m_policies(policies_)
204    {}
205
206    CallPoliciesT const& call_policies() const
207    {
208        return this->m_policies;
209    }
210   
211 private: // data members
212    CallPoliciesT m_policies;
213};
214
215//
216// drop1<S> is the initial length(S) elements of S
217//
218namespace detail
219{
220  template <class S>
221  struct drop1
222    : mpl::iterator_range<
223          typename mpl::begin<S>::type
224        , typename mpl::prior<
225              typename mpl::end<S>::type
226          >::type
227      >
228  {};
229}
230
231template <BOOST_PYTHON_OVERLOAD_TYPES>
232class init : public init_base<init<BOOST_PYTHON_OVERLOAD_ARGS> >
233{
234    typedef init_base<init<BOOST_PYTHON_OVERLOAD_ARGS> > base;
235 public:
236    typedef init<BOOST_PYTHON_OVERLOAD_ARGS> self_t;
237
238    init(char const* doc_ = 0)
239        : base(doc_)
240    {
241    }
242
243    template <std::size_t N>
244    init(char const* doc_, detail::keywords<N> const& kw)
245        : base(doc_, kw.range())
246    {
247        typedef typename detail::error::more_keywords_than_init_arguments<
248            N, n_arguments::value
249            >::too_many_keywords assertion;
250    }
251
252    template <std::size_t N>
253    init(detail::keywords<N> const& kw, char const* doc_ = 0)
254        : base(doc_, kw.range())
255    {
256        typedef typename detail::error::more_keywords_than_init_arguments<
257            N, n_arguments::value
258            >::too_many_keywords assertion;
259    }
260
261    template <class CallPoliciesT>
262    init_with_call_policies<CallPoliciesT, self_t>
263    operator[](CallPoliciesT const& policies) const
264    {
265        return init_with_call_policies<CallPoliciesT, self_t>(
266            policies, this->doc_string(), this->keywords());
267    }
268
269    typedef detail::type_list<BOOST_PYTHON_OVERLOAD_ARGS> signature_;
270
271    typedef detail::is_optional<
272        typename mpl::eval_if<
273            mpl::empty<signature_>
274          , mpl::false_
275          , mpl::back<signature_>
276        >::type
277    > back_is_optional;
278   
279    typedef typename mpl::eval_if<
280        back_is_optional
281      , mpl::back<signature_>
282      , mpl::vector0<>
283    >::type optional_args;
284
285    typedef typename mpl::eval_if<
286        back_is_optional
287      , mpl::if_<
288            mpl::empty<optional_args>
289          , detail::drop1<signature_>
290          , mpl::joint_view<
291                detail::drop1<signature_>
292              , optional_args
293            >
294        >
295      , signature_
296    >::type signature;
297
298    // TODO: static assert to make sure there are no other optional elements
299
300    // Count the number of default args
301    typedef mpl::size<optional_args> n_defaults;
302    typedef mpl::size<signature> n_arguments;
303};
304
305///////////////////////////////////////////////////////////////////////////////
306//
307//  optional
308//
309//      optional<T0...TN>::type returns a typelist.
310//
311///////////////////////////////////////////////////////////////////////////////
312template <BOOST_PYTHON_OVERLOAD_TYPES>
313struct optional
314    : detail::type_list<BOOST_PYTHON_OVERLOAD_ARGS>
315{
316};
317
318namespace detail
319{
320  template <class ClassT, class CallPoliciesT, class Signature, class NArgs>
321  inline void def_init_aux(
322      ClassT& cl
323      , Signature const&
324      , NArgs
325      , CallPoliciesT const& policies
326      , char const* doc
327      , detail::keyword_range const& keywords_
328      )
329  {
330      cl.def(
331          "__init__"
332        , detail::make_keyword_range_constructor<Signature,NArgs>(
333              policies
334            , keywords_
335            , (typename ClassT::metadata::holder*)0
336          )
337        , doc
338      );
339  }
340
341  ///////////////////////////////////////////////////////////////////////////////
342  //
343  //  define_class_init_helper<N>::apply
344  //
345  //      General case
346  //
347  //      Accepts a class_ and an arguments list. Defines a constructor
348  //      for the class given the arguments and recursively calls
349  //      define_class_init_helper<N-1>::apply with one fewer argument (the
350  //      rightmost argument is shaved off)
351  //
352  ///////////////////////////////////////////////////////////////////////////////
353  template <int NDefaults>
354  struct define_class_init_helper
355  {
356
357      template <class ClassT, class CallPoliciesT, class Signature, class NArgs>
358      static void apply(
359          ClassT& cl
360          , CallPoliciesT const& policies
361          , Signature const& args
362          , NArgs
363          , char const* doc
364          , detail::keyword_range keywords)
365      {
366          detail::def_init_aux(cl, args, NArgs(), policies, 0, keywords);
367
368          if (keywords.second > keywords.first)
369              --keywords.second;
370
371          typedef typename mpl::prior<NArgs>::type next_nargs;
372          define_class_init_helper<NDefaults-1>::apply(
373              cl, policies, Signature(), next_nargs(), doc, keywords);
374      }
375  };
376
377  ///////////////////////////////////////////////////////////////////////////////
378  //
379  //  define_class_init_helper<0>::apply
380  //
381  //      Terminal case
382  //
383  //      Accepts a class_ and an arguments list. Defines a constructor
384  //      for the class given the arguments.
385  //
386  ///////////////////////////////////////////////////////////////////////////////
387  template <>
388  struct define_class_init_helper<0> {
389
390      template <class ClassT, class CallPoliciesT, class Signature, class NArgs>
391      static void apply(
392          ClassT& cl
393        , CallPoliciesT const& policies
394        , Signature const& args
395        , NArgs
396        , char const* doc
397        , detail::keyword_range const& keywords)
398      {
399          detail::def_init_aux(cl, args, NArgs(), policies, doc, keywords);
400      }
401  };
402}
403
404}} // namespace boost::python
405
406#undef BOOST_PYTHON_OVERLOAD_TYPES_WITH_DEFAULT
407#undef BOOST_PYTHON_OVERLOAD_TYPES
408#undef BOOST_PYTHON_OVERLOAD_ARGS
409#undef BOOST_PYTHON_IS_OPTIONAL_VALUE
410#undef BOOST_PYTHON_APPEND_TO_INIT
411
412///////////////////////////////////////////////////////////////////////////////
413#endif // INIT_JDG20020820_HPP
414
415
416
417
418
419
420
421
Note: See TracBrowser for help on using the repository browser.