1 // Copyright David Abrahams 2002.
2 // Distributed under the Boost Software License, Version 1.0. (See
3 // accompanying file LICENSE_1_0.txt or copy at
4 // http://www.boost.org/LICENSE_1_0.txt)
5 #ifndef CLASS_DWA200216_HPP
6 # define CLASS_DWA200216_HPP
7 
8 # include <boost/python/detail/prefix.hpp>
9 
10 # include <boost/noncopyable.hpp>
11 
12 # include <boost/python/class_fwd.hpp>
13 # include <boost/python/object/class.hpp>
14 
15 # include <boost/python/object.hpp>
16 # include <boost/python/type_id.hpp>
17 # include <boost/python/data_members.hpp>
18 # include <boost/python/make_function.hpp>
19 # include <boost/python/signature.hpp>
20 # include <boost/python/init.hpp>
21 # include <boost/python/args_fwd.hpp>
22 
23 # include <boost/python/object/class_metadata.hpp>
24 # include <boost/python/object/pickle_support.hpp>
25 # include <boost/python/object/add_to_namespace.hpp>
26 
27 # include <boost/python/detail/overloads_fwd.hpp>
28 # include <boost/python/detail/operator_id.hpp>
29 # include <boost/python/detail/def_helper.hpp>
30 # include <boost/python/detail/force_instantiate.hpp>
31 # include <boost/python/detail/unwrap_type_id.hpp>
32 # include <boost/python/detail/unwrap_wrapper.hpp>
33 
34 # include <boost/type_traits/is_same.hpp>
35 # include <boost/type_traits/is_member_function_pointer.hpp>
36 # include <boost/type_traits/is_polymorphic.hpp>
37 
38 # include <boost/mpl/size.hpp>
39 # include <boost/mpl/for_each.hpp>
40 # include <boost/mpl/bool.hpp>
41 # include <boost/mpl/not.hpp>
42 
43 # include <boost/detail/workaround.hpp>
44 
45 # if BOOST_WORKAROUND(__MWERKS__, <= 0x3004)                        \
46     /* pro9 reintroduced the bug */                                 \
47     || (BOOST_WORKAROUND(__MWERKS__, > 0x3100)                      \
48         && BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3201)))   \
49     || BOOST_WORKAROUND(__GNUC__, < 3)
50 
51 #  define BOOST_PYTHON_NO_MEMBER_POINTER_ORDERING 1
52 
53 # endif
54 
55 # ifdef BOOST_PYTHON_NO_MEMBER_POINTER_ORDERING
56 #  include <boost/mpl/and.hpp>
57 #  include <boost/type_traits/is_member_pointer.hpp>
58 # endif
59 
60 namespace boost { namespace python {
61 
62 template <class DerivedVisitor> class def_visitor;
63 
64 enum no_init_t { no_init };
65 
66 namespace detail
67 {
68   // This function object is used with mpl::for_each to write the id
69   // of the type a pointer to which is passed as its 2nd compile-time
70   // argument. into the iterator pointed to by its runtime argument
71   struct write_type_id
72   {
write_type_idboost::python::detail::write_type_id73       write_type_id(type_info**p) : p(p) {}
74 
75       // Here's the runtime behavior
76       template <class T>
operator ()boost::python::detail::write_type_id77       void operator()(T*) const
78       {
79           *(*p)++ = type_id<T>();
80       }
81 
82       type_info** p;
83   };
84 
85   template <class T>
86   struct is_data_member_pointer
87       : mpl::and_<
88             is_member_pointer<T>
89           , mpl::not_<is_member_function_pointer<T> >
90         >
91   {};
92 
93 # ifdef BOOST_PYTHON_NO_MEMBER_POINTER_ORDERING
94 #  define BOOST_PYTHON_DATA_MEMBER_HELPER(D) , detail::is_data_member_pointer<D>()
95 #  define BOOST_PYTHON_YES_DATA_MEMBER , mpl::true_
96 #  define BOOST_PYTHON_NO_DATA_MEMBER , mpl::false_
97 # elif defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING)
98 #  define BOOST_PYTHON_DATA_MEMBER_HELPER(D) , 0
99 #  define BOOST_PYTHON_YES_DATA_MEMBER , int
100 #  define BOOST_PYTHON_NO_DATA_MEMBER , ...
101 # else
102 #  define BOOST_PYTHON_DATA_MEMBER_HELPER(D)
103 #  define BOOST_PYTHON_YES_DATA_MEMBER
104 #  define BOOST_PYTHON_NO_DATA_MEMBER
105 # endif
106 
107   namespace error
108   {
109     //
110     // A meta-assertion mechanism which prints nice error messages and
111     // backtraces on lots of compilers. Usage:
112     //
113     //      assertion<C>::failed
114     //
115     // where C is an MPL metafunction class
116     //
117 
118     template <class C> struct assertion_failed { };
119     template <class C> struct assertion_ok { typedef C failed; };
120 
121     template <class C>
122     struct assertion
123         : mpl::if_<C, assertion_ok<C>, assertion_failed<C> >::type
124     {};
125 
126     //
127     // Checks for validity of arguments used to define virtual
128     // functions with default implementations.
129     //
130 
131     template <class Default>
not_a_derived_class_member(Default)132     void not_a_derived_class_member(Default) {}
133 
134     template <class T, class Fn>
135     struct virtual_function_default
136     {
137         template <class Default>
138         static void
must_be_derived_class_memberboost::python::detail::error::virtual_function_default139         must_be_derived_class_member(Default const&)
140         {
141             typedef typename assertion<mpl::not_<is_same<Default,Fn> > >::failed test0;
142 # if !BOOST_WORKAROUND(__MWERKS__, <= 0x2407)
143             typedef typename assertion<is_polymorphic<T> >::failed test1;
144 # endif
145             typedef typename assertion<is_member_function_pointer<Fn> >::failed test2;
146             not_a_derived_class_member<Default>(Fn());
147         }
148     };
149   }
150 }
151 
152 // This is the primary mechanism through which users will expose
153 // C++ classes to Python.
154 template <
155     class W // class being wrapped
156     , class X1 // = detail::not_specified
157     , class X2 // = detail::not_specified
158     , class X3 // = detail::not_specified
159     >
160 class class_ : public objects::class_base
161 {
162  public: // types
163     typedef objects::class_base base;
164     typedef class_<W,X1,X2,X3> self;
165     typedef typename objects::class_metadata<W,X1,X2,X3> metadata;
166     typedef W wrapped_type;
167 
168  private: // types
169 
170     // A helper class which will contain an array of id objects to be
171     // passed to the base class constructor
172     struct id_vector
173     {
174         typedef typename metadata::bases bases;
175 
id_vectorboost::python::class_::id_vector176         id_vector()
177         {
178             // Stick the derived class id into the first element of the array
179             ids[0] = detail::unwrap_type_id((W*)0, (W*)0);
180 
181             // Write the rest of the elements into succeeding positions.
182             type_info* p = ids + 1;
183             mpl::for_each(detail::write_type_id(&p), (bases*)0, (add_pointer<mpl::_>*)0);
184         }
185 
186         BOOST_STATIC_CONSTANT(
187             std::size_t, size = mpl::size<bases>::value + 1);
188         type_info ids[size];
189     };
190     friend struct id_vector;
191 
192  public: // constructors
193 
194     // Construct with the class name, with or without docstring, and default __init__() function
195     class_(char const* name, char const* doc = 0);
196 
197     // Construct with class name, no docstring, and an uncallable __init__ function
198     class_(char const* name, no_init_t);
199 
200     // Construct with class name, docstring, and an uncallable __init__ function
201     class_(char const* name, char const* doc, no_init_t);
202 
203     // Construct with class name and init<> function
204     template <class DerivedT>
class_(char const * name,init_base<DerivedT> const & i)205     inline class_(char const* name, init_base<DerivedT> const& i)
206         : base(name, id_vector::size, id_vector().ids)
207     {
208         this->initialize(i);
209     }
210 
211     // Construct with class name, docstring and init<> function
212     template <class DerivedT>
class_(char const * name,char const * doc,init_base<DerivedT> const & i)213     inline class_(char const* name, char const* doc, init_base<DerivedT> const& i)
214         : base(name, id_vector::size, id_vector().ids, doc)
215     {
216         this->initialize(i);
217     }
218 
219  public: // member functions
220 
221     // Generic visitation
222     template <class Derived>
def(def_visitor<Derived> const & visitor)223     self& def(def_visitor<Derived> const& visitor)
224     {
225         visitor.visit(*this);
226         return *this;
227     }
228 
229     // Wrap a member function or a non-member function which can take
230     // a T, T cv&, or T cv* as its first parameter, a callable
231     // python object, or a generic visitor.
232     template <class F>
def(char const * name,F f)233     self& def(char const* name, F f)
234     {
235         this->def_impl(
236             detail::unwrap_wrapper((W*)0)
237           , name, f, detail::def_helper<char const*>(0), &f);
238         return *this;
239     }
240 
241     template <class A1, class A2>
def(char const * name,A1 a1,A2 const & a2)242     self& def(char const* name, A1 a1, A2 const& a2)
243     {
244         this->def_maybe_overloads(name, a1, a2, &a2);
245         return *this;
246     }
247 
248     template <class Fn, class A1, class A2>
def(char const * name,Fn fn,A1 const & a1,A2 const & a2)249     self& def(char const* name, Fn fn, A1 const& a1, A2 const& a2)
250     {
251         //  The arguments are definitely:
252         //      def(name, function, policy, doc_string)
253         //      def(name, function, doc_string, policy)
254 
255         this->def_impl(
256             detail::unwrap_wrapper((W*)0)
257           , name, fn
258           , detail::def_helper<A1,A2>(a1,a2)
259           , &fn);
260 
261         return *this;
262     }
263 
264     template <class Fn, class A1, class A2, class A3>
def(char const * name,Fn fn,A1 const & a1,A2 const & a2,A3 const & a3)265     self& def(char const* name, Fn fn, A1 const& a1, A2 const& a2, A3 const& a3)
266     {
267         this->def_impl(
268             detail::unwrap_wrapper((W*)0)
269           , name, fn
270           , detail::def_helper<A1,A2,A3>(a1,a2,a3)
271           , &fn);
272 
273         return *this;
274     }
275 
276     //
277     // Data member access
278     //
279     template <class D>
def_readonly(char const * name,D const & d,char const * doc=0)280     self& def_readonly(char const* name, D const& d, char const* doc=0)
281     {
282         return this->def_readonly_impl(name, d, doc BOOST_PYTHON_DATA_MEMBER_HELPER(D));
283     }
284 
285     template <class D>
def_readwrite(char const * name,D const & d,char const * doc=0)286     self& def_readwrite(char const* name, D const& d, char const* doc=0)
287     {
288         return this->def_readwrite_impl(name, d, doc BOOST_PYTHON_DATA_MEMBER_HELPER(D));
289     }
290 
291     template <class D>
def_readonly(char const * name,D & d,char const * doc=0)292     self& def_readonly(char const* name, D& d, char const* doc=0)
293     {
294         return this->def_readonly_impl(name, d, doc BOOST_PYTHON_DATA_MEMBER_HELPER(D));
295     }
296 
297     template <class D>
def_readwrite(char const * name,D & d,char const * doc=0)298     self& def_readwrite(char const* name, D& d, char const* doc=0)
299     {
300         return this->def_readwrite_impl(name, d, doc BOOST_PYTHON_DATA_MEMBER_HELPER(D));
301     }
302 
303     // Property creation
304 # if !BOOST_WORKAROUND(BOOST_MSVC, <= 1300)
305     template <class Get>
add_property(char const * name,Get fget,char const * docstr=0)306     self& add_property(char const* name, Get fget, char const* docstr = 0)
307     {
308         base::add_property(name, this->make_getter(fget), docstr);
309         return *this;
310     }
311 
312     template <class Get, class Set>
add_property(char const * name,Get fget,Set fset,char const * docstr=0)313     self& add_property(char const* name, Get fget, Set fset, char const* docstr = 0)
314     {
315         base::add_property(
316             name, this->make_getter(fget), this->make_setter(fset), docstr);
317         return *this;
318     }
319 # else
320  private:
321     template <class Get>
add_property_impl(char const * name,Get fget,char const * docstr,int)322     self& add_property_impl(char const* name, Get fget, char const* docstr, int)
323     {
324         base::add_property(name, this->make_getter(fget), docstr);
325         return *this;
326     }
327 
328     template <class Get, class Set>
add_property_impl(char const * name,Get fget,Set fset,...)329     self& add_property_impl(char const* name, Get fget, Set fset, ...)
330     {
331         base::add_property(
332             name, this->make_getter(fget), this->make_setter(fset), 0);
333         return *this;
334     }
335 
336  public:
337     template <class Get>
add_property(char const * name,Get fget)338     self& add_property(char const* name, Get fget)
339     {
340         base::add_property(name, this->make_getter(fget), 0);
341         return *this;
342     }
343 
344     template <class Get, class DocStrOrSet>
add_property(char const * name,Get fget,DocStrOrSet docstr_or_set)345     self& add_property(char const* name, Get fget, DocStrOrSet docstr_or_set)
346     {
347         this->add_property_impl(name, this->make_getter(fget), docstr_or_set, 0);
348         return *this;
349     }
350 
351     template <class Get, class Set>
352     self&
add_property(char const * name,Get fget,Set fset,char const * docstr)353     add_property(char const* name, Get fget, Set fset, char const* docstr)
354     {
355         base::add_property(
356             name, this->make_getter(fget), this->make_setter(fset), docstr);
357         return *this;
358     }
359 # endif
360 
361     template <class Get>
add_static_property(char const * name,Get fget)362     self& add_static_property(char const* name, Get fget)
363     {
364         base::add_static_property(name, object(fget));
365         return *this;
366     }
367 
368     template <class Get, class Set>
add_static_property(char const * name,Get fget,Set fset)369     self& add_static_property(char const* name, Get fget, Set fset)
370     {
371         base::add_static_property(name, object(fget), object(fset));
372         return *this;
373     }
374 
375     template <class U>
setattr(char const * name,U const & x)376     self& setattr(char const* name, U const& x)
377     {
378         this->base::setattr(name, object(x));
379         return *this;
380     }
381 
382     // Pickle support
383     template <typename PickleSuiteType>
def_pickle(PickleSuiteType const & x)384     self& def_pickle(PickleSuiteType const& x)
385     {
386       error_messages::must_be_derived_from_pickle_suite(x);
387       detail::pickle_suite_finalize<PickleSuiteType>::register_(
388         *this,
389         &PickleSuiteType::getinitargs,
390         &PickleSuiteType::getstate,
391         &PickleSuiteType::setstate,
392         PickleSuiteType::getstate_manages_dict());
393       return *this;
394     }
395 
enable_pickling()396     self& enable_pickling()
397     {
398         this->base::enable_pickling_(false);
399         return *this;
400     }
401 
staticmethod(char const * name)402     self& staticmethod(char const* name)
403     {
404         this->make_method_static(name);
405         return *this;
406     }
407  private: // helper functions
408 
409     // Builds a method for this class around the given [member]
410     // function pointer or object, appropriately adjusting the type of
411     // the first signature argument so that if f is a member of a
412     // (possibly not wrapped) base class of T, an lvalue argument of
413     // type T will be required.
414     //
415     // @group PropertyHelpers {
416     template <class F>
make_getter(F f)417     object make_getter(F f)
418     {
419         typedef typename api::is_object_operators<F>::type is_obj_or_proxy;
420 
421         return this->make_fn_impl(
422             detail::unwrap_wrapper((W*)0)
423           , f, is_obj_or_proxy(), (char*)0, detail::is_data_member_pointer<F>()
424         );
425     }
426 
427     template <class F>
make_setter(F f)428     object make_setter(F f)
429     {
430         typedef typename api::is_object_operators<F>::type is_obj_or_proxy;
431 
432         return this->make_fn_impl(
433             detail::unwrap_wrapper((W*)0)
434           , f, is_obj_or_proxy(), (int*)0, detail::is_data_member_pointer<F>()
435         );
436     }
437 
438     template <class T, class F>
make_fn_impl(T *,F const & f,mpl::false_,void *,mpl::false_)439     object make_fn_impl(T*, F const& f, mpl::false_, void*, mpl::false_)
440     {
441         return python::make_function(f, default_call_policies(), detail::get_signature(f, (T*)0));
442     }
443 
444     template <class T, class D, class B>
make_fn_impl(T *,D B::* pm_,mpl::false_,char *,mpl::true_)445     object make_fn_impl(T*, D B::*pm_, mpl::false_, char*, mpl::true_)
446     {
447         D T::*pm = pm_;
448         return python::make_getter(pm);
449     }
450 
451     template <class T, class D, class B>
make_fn_impl(T *,D B::* pm_,mpl::false_,int *,mpl::true_)452     object make_fn_impl(T*, D B::*pm_, mpl::false_, int*, mpl::true_)
453     {
454         D T::*pm = pm_;
455         return python::make_setter(pm);
456     }
457 
458     template <class T, class F>
make_fn_impl(T *,F const & x,mpl::true_,void *,mpl::false_)459     object make_fn_impl(T*, F const& x, mpl::true_, void*, mpl::false_)
460     {
461         return x;
462     }
463     // }
464 
465     template <class D, class B>
def_readonly_impl(char const * name,D B::* pm_,char const * doc BOOST_PYTHON_YES_DATA_MEMBER)466     self& def_readonly_impl(
467         char const* name, D B::*pm_, char const* doc BOOST_PYTHON_YES_DATA_MEMBER)
468     {
469         return this->add_property(name, pm_, doc);
470     }
471 
472     template <class D, class B>
def_readwrite_impl(char const * name,D B::* pm_,char const * doc BOOST_PYTHON_YES_DATA_MEMBER)473     self& def_readwrite_impl(
474         char const* name, D B::*pm_, char const* doc BOOST_PYTHON_YES_DATA_MEMBER)
475     {
476         return this->add_property(name, pm_, pm_, doc);
477     }
478 
479     template <class D>
def_readonly_impl(char const * name,D & d,char const * BOOST_PYTHON_NO_DATA_MEMBER)480     self& def_readonly_impl(
481         char const* name, D& d, char const* BOOST_PYTHON_NO_DATA_MEMBER)
482     {
483         return this->add_static_property(name, python::make_getter(d));
484     }
485 
486     template <class D>
def_readwrite_impl(char const * name,D & d,char const * BOOST_PYTHON_NO_DATA_MEMBER)487     self& def_readwrite_impl(
488         char const* name, D& d, char const* BOOST_PYTHON_NO_DATA_MEMBER)
489     {
490         return this->add_static_property(name, python::make_getter(d), python::make_setter(d));
491     }
492 
493     template <class DefVisitor>
initialize(DefVisitor const & i)494     inline void initialize(DefVisitor const& i)
495     {
496         metadata::register_(); // set up runtime metadata/conversions
497 
498         typedef typename metadata::holder holder;
499         this->set_instance_size( objects::additional_instance_size<holder>::value );
500 
501         this->def(i);
502     }
503 
initialize(no_init_t)504     inline void initialize(no_init_t)
505     {
506         metadata::register_(); // set up runtime metadata/conversions
507         this->def_no_init();
508     }
509 
510     //
511     // These two overloads discriminate between def() as applied to a
512     // generic visitor and everything else.
513     //
514     // @group def_impl {
515     template <class T, class Helper, class LeafVisitor, class Visitor>
def_impl(T *,char const * name,LeafVisitor,Helper const & helper,def_visitor<Visitor> const * v)516     inline void def_impl(
517         T*
518       , char const* name
519       , LeafVisitor
520       , Helper const& helper
521       , def_visitor<Visitor> const* v
522     )
523     {
524         v->visit(*this, name,  helper);
525     }
526 
527     template <class T, class Fn, class Helper>
def_impl(T *,char const * name,Fn fn,Helper const & helper,...)528     inline void def_impl(
529         T*
530       , char const* name
531       , Fn fn
532       , Helper const& helper
533       , ...
534     )
535     {
536         objects::add_to_namespace(
537             *this
538           , name
539           , make_function(
540                 fn
541               , helper.policies()
542               , helper.keywords()
543               , detail::get_signature(fn, (T*)0)
544             )
545           , helper.doc()
546         );
547 
548         this->def_default(name, fn, helper, mpl::bool_<Helper::has_default_implementation>());
549     }
550     // }
551 
552     //
553     // These two overloads handle the definition of default
554     // implementation overloads for virtual functions. The second one
555     // handles the case where no default implementation was specified.
556     //
557     // @group def_default {
558     template <class Fn, class Helper>
def_default(char const * name,Fn,Helper const & helper,mpl::bool_<true>)559     inline void def_default(
560         char const* name
561         , Fn
562         , Helper const& helper
563         , mpl::bool_<true>)
564     {
565         detail::error::virtual_function_default<W,Fn>::must_be_derived_class_member(
566             helper.default_implementation());
567 
568         objects::add_to_namespace(
569             *this, name,
570             make_function(
571                 helper.default_implementation(), helper.policies(), helper.keywords())
572             );
573     }
574 
575     template <class Fn, class Helper>
def_default(char const *,Fn,Helper const &,mpl::bool_<false>)576     inline void def_default(char const*, Fn, Helper const&, mpl::bool_<false>)
577     { }
578     // }
579 
580     //
581     // These two overloads discriminate between def() as applied to
582     // regular functions and def() as applied to the result of
583     // BOOST_PYTHON_FUNCTION_OVERLOADS(). The final argument is used to
584     // discriminate.
585     //
586     // @group def_maybe_overloads {
587     template <class OverloadsT, class SigT>
def_maybe_overloads(char const * name,SigT sig,OverloadsT const & overloads,detail::overloads_base const *)588     void def_maybe_overloads(
589         char const* name
590         , SigT sig
591         , OverloadsT const& overloads
592         , detail::overloads_base const*)
593 
594     {
595         //  convert sig to a type_list (see detail::get_signature in signature.hpp)
596         //  before calling detail::define_with_defaults.
597         detail::define_with_defaults(
598             name, overloads, *this, detail::get_signature(sig));
599     }
600 
601     template <class Fn, class A1>
def_maybe_overloads(char const * name,Fn fn,A1 const & a1,...)602     void def_maybe_overloads(
603         char const* name
604         , Fn fn
605         , A1 const& a1
606         , ...)
607     {
608         this->def_impl(
609             detail::unwrap_wrapper((W*)0)
610           , name
611           , fn
612           , detail::def_helper<A1>(a1)
613           , &fn
614         );
615 
616     }
617     // }
618 };
619 
620 
621 //
622 // implementations
623 //
624 
625 template <class W, class X1, class X2, class X3>
class_(char const * name,char const * doc)626 inline class_<W,X1,X2,X3>::class_(char const* name, char const* doc)
627     : base(name, id_vector::size, id_vector().ids, doc)
628 {
629     this->initialize(init<>());
630 //  select_holder::assert_default_constructible();
631 }
632 
633 template <class W, class X1, class X2, class X3>
class_(char const * name,no_init_t)634 inline class_<W,X1,X2,X3>::class_(char const* name, no_init_t)
635     : base(name, id_vector::size, id_vector().ids)
636 {
637     this->initialize(no_init);
638 }
639 
640 template <class W, class X1, class X2, class X3>
class_(char const * name,char const * doc,no_init_t)641 inline class_<W,X1,X2,X3>::class_(char const* name, char const* doc, no_init_t)
642     : base(name, id_vector::size, id_vector().ids, doc)
643 {
644     this->initialize(no_init);
645 }
646 
647 }} // namespace boost::python
648 
649 # undef BOOST_PYTHON_DATA_MEMBER_HELPER
650 # undef BOOST_PYTHON_YES_DATA_MEMBER
651 # undef BOOST_PYTHON_NO_DATA_MEMBER
652 # undef BOOST_PYTHON_NO_MEMBER_POINTER_ORDERING
653 
654 #endif // CLASS_DWA200216_HPP
655