Classdesc 3.44
python_base.h
1/*
2 @copyright Russell Standish 2018
3 @author Russell Standish
4 This file is part of Classdesc
5
6 Open source licensed under the MIT license. See LICENSE for details.
7*/
8
9#ifndef CLASSDESC_PYTHON_BASE_H
10#define CLASSDESC_PYTHON_BASE_H
11#include <boost/python/detail/wrap_python.hpp>
12#include "classdesc.h"
13
14#include "function.h"
15#include <boost/mpl/vector.hpp>
16
17/*
18 For all types, maintain a vector of polymorphic class objects
19 use lazy instantiation
20
21 std::vector<shared_ptr<BaseObj>> classes;
22 class_<T>& getClass<T>()
23 {
24 static size_t id=classes.size();
25 if (id==classes.size())
26 classes.push_back(shared_ptr<BaseObj>(new class_<T>(typeName<T>())));
27 return dynamic_cast<class_<T>&>(*classes[id]);
28 }
29*/
30
31
32namespace classdesc
33{
34 class python_t;
35
36 template <class T>
38 public And<And<And<is_class<T>, Not<is_container<T> > >, Not<is_associative_container<T> > >, Not<is_enum<T> > > {};
39
41 template <class T>
43 public Or<is_fundamental<T>, is_string<T> > {};
44
45 // objectless calls
46 // classdesc generated
47 template <class T, class Base=T>
49 python(python_t& p, const string& d);
50
51
52 // anything that is neither a class nor enum
53 template <class T>
55 python(python_t&, const string&) {}
56
57 namespace pythonDetail
58 {
59 using namespace classdesc::functional;
60
61 template <class M> struct MemberType {typedef M T;};
62 template <class U, class V>
63 struct MemberType<U (V::*)>
64 {
65 typedef U T;
66 };
67 template <class U>
68 struct MemberType<U*>
69 {
70 typedef U T;
71 };
72
73 template <class R, int> struct SigArg;
74
75 template <class F> struct SigArg<F,0>
76 {
77 typedef boost::mpl::vector<> T;
78 };
79
80 template <class F> struct SigArg<F,1>
81 {
82 typedef boost::mpl::vector<typename Arg<F,Arity<F>::V>::T> T;
83 };
84
85 template <class F,int N> struct SigArg
86 {
87 typedef typename boost::mpl::push_front<
88 typename SigArg<F,N-1>::T,
89 typename Arg<F,Arity<F>::V-N+1>::T
90 >::type T;
91 };
92
93 template <class F> struct SigFun
94 {
95 typedef typename boost::mpl::push_front<
96 typename SigArg<F,Arity<F>::V>::T,
97 typename Return<F>::T
98 >::type T;
99 };
100
101 template <class F>
102 struct SigObj
103 {
104 typedef typename classdesc::pythonDetail::SigFun<decltype(&F::operator())>::T T;
105 };
106
107 template <class T> struct Sig: public std::conditional<is_class<T>::value, SigObj<T>, SigFun<T>>::type {};
108
109 template <class T>
110 size_t len(T& x) {return x.size();}
111
112 template <class T, class U>
114 assign(T& x, const U& y) {x=y;}
115
116 template <class T, class U>
117 typename enable_if<Not<is_assignable<T&,U> >, void>::T
118 assign(T& x, const U& y) {throw std::runtime_error("assignment not supported between "+typeName<U>()+" and "+typeName<T>());}
119
120 // registerClass is a MixIn because terminating rank differs from that of NewArrayGet
121 template <class T, int rank>
123 {static void registerClass(python_t& p);};
124
125 template <class T>
127 {static void registerClass(python_t& p) {python<T>(p,"");}};
128
129 template <class T, int rank> struct ArrayGetReturn;
130
131 template <class T, int rank>
132 struct ArrayGet: public ArrayGetRegisterClass<T,rank>
133 {
134 static_assert(rank==std::rank<T>::value,"rank==std::rank<T>::value");
135 T* x;
136 ArrayGet(): x(0) {}
137 ArrayGet(T& x): x(&x) {}
138 typedef typename ArrayGetReturn<T,rank>::T L;
139 L get(size_t i) const
140 {return L((*x)[i]);}
141 void set(size_t i, const L& v) {assign((*x)[i],v);}
142 };
143
144 template <class U, int rank> struct ArrayGetReturn
146 template <class U> struct ArrayGetReturn<U,1>
147 {typedef typename std::remove_extent<U>::type T;};
148
149
150 template <class T, class M>
151 struct ArrayMemRef
152 {
153 typedef typename MemberType<M>::T MT;
154 static constexpr size_t rank=std::rank<MT>::value;
155 static_assert(rank>0,"rank>0");
156 M m;
157 ArrayMemRef(M m): m(m) {}
158 typedef ArrayGet<MT,rank> L;
159
160 L operator()(T& o) const
161 {return L(o.*m);}
162 };
163
164 template<class T, class M>
165 struct ArrayMemRefSetItem
166 {
167 M m;
168 ArrayMemRefSetItem(M m): m(m) {}
169 typedef typename std::remove_all_extents<typename MemberType<M>::T>::type V;
170 void operator()(T& o, size_t i, V& v) const
171 {assign((o.*m)[i], v);}
172 };
173
174 template <class T, class M>
175 size_t arrayMemLen(const T&) {return std::extent<M>::value;}
176
177 template <class C, class M>
178 struct EnumGet
179 {
180 typedef typename MemberType<M>::T E;
181 M m;
182 EnumGet(M m): m(m) {}
183 string operator()(const C& o) const {return enum_keys<E>()(o.*m);}
184 };
185
186 template <class C,class M>
187 struct EnumSet
188 {
189 typedef typename MemberType<M>::T E;
190 M m;
191 EnumSet(M m): m(m) {}
192 void operator()(C& o, const string& v) const {o.*m=enum_keys<E>()(v);}
193 };
194
195 template <class C, class M>
196 EnumGet<C,M> enumGet(M m) {return EnumGet<C,M>(m);}
197 template <class C, class M>
198 EnumSet<C,M> enumSet(M m) {return EnumSet<C,M>(m);}
199
200 template <class T>
201 typename T::value_type& getItemRef(T& c, size_t n)
202 {
203 if (n>=size_t(c.size()))
204 throw std::out_of_range("index out of bounds");
205 auto i=c.begin();
206 std::advance(i,n);
207 return *i;
208 }
209
210 // for a structured type, return a PythonRef
211 template <class T>
212 typename enable_if<Not<PythonBasicType<typename T::value_type> >,
213 //PythonRef<typename T::value_type> >::T
214 typename T::value_type& >::T
215 getItem(T& c, size_t n) {return getItemRef(c,n);}
216
217
218 // for a basic python type, return by value
219 template <class T>
220 typename enable_if<PythonBasicType<typename T::value_type>,
221 typename T::value_type>::T
222 getItem(T& c, size_t n) {return getItemRef(c,n);}
223
224 template <class T>
225 typename enable_if<Not<PythonBasicType<typename T::value_type> >,
226 void>::T
227 setItem(T&, size_t,const typename T::value_type&) {}
228
229 template <class T>
230 typename enable_if<PythonBasicType<typename T::value_type>,
231 void>::T
232 setItem(T& c, size_t n,const typename T::value_type& v)
233 {getItemRef(c,n)=v;}
234
235 template <class T>
236 typename T::mapped_type basicGetMapItem(T& x, const typename T::key_type& k)
237 {
238 auto i=x.find(k);
239 if (i!=x.end())
240 return i->second;
241 else
242 throw std::runtime_error("key not found");
243 }
244
245 template <class T>
246 typename enable_if<PythonBasicType<typename T::mapped_type>,
247 typename T::mapped_type>::T
248 getMapItem(T& x, const typename T::key_type& k)
249 {return basicGetMapItem(x,k);}
250
251 template <class T>
252 typename enable_if<Not<PythonBasicType<typename T::mapped_type> >,
253 typename T::mapped_type& >::T
254 getMapItem(T& x, const typename T::key_type& k)
255 {return basicGetMapItem(x,k);}
256
257 template <class T>
258 void setMapItem
259 (T& x, const typename T::key_type& k, const typename T::mapped_type& v)
260 {x[k]=v;}
261
263 struct StopIteration {};
264
265 template <class T>
266 struct Iterator
267 {
268 typedef typename T::const_iterator I;
269 I i, end;
270 Iterator() {}
271 Iterator(I begin, I end): i(begin), end(end) {}
272 typename T::key_type next() {
273 if (i==end)
274 throw StopIteration();
275 else
276 {
277 auto j=i++;
278 return j->first;
279 }
280 }
281 static void registerClass(python_t&);
282 };
283
284 template <class T>
285 Iterator<T> iter(const T& m) {return Iterator<T>(m.begin(), m.end());}
286
287
288 // a one shot switch that determines if a give type has already been defined
289 template <class T>
290 inline bool classDefStarted()
291 {
292 static bool value=false;
293 if (value) return true;
294 value=true;
295 return false;
296 }
297
298 template <class T>
300 defaultEquality(const T& x, const T& y)
301 { return &x==&y || x==y;}
302
303 template <class T>
304 typename enable_if<And<is_container<T>, has_equality_operator<typename T::value_type>>, bool>::T
305 defaultEquality(const T& x, const T& y)
306 { return &x==&y || x==y;}
307
308 template <class T>
309 typename enable_if<Not<has_equality_operator<T>>, bool>::T
310 defaultEquality(const T& x, const T& y)
311 {return &x==&y;} // no equality, just return whether two objects are identical
312
313 template <class T>
314 typename enable_if<And<is_container<T>,
315 Not<has_equality_operator<typename T::value_type>>>, bool>::T
316 defaultEquality(const T& x, const T& y)
317 {return &x==&y;} // no equality, just return whether two objects are identical
318
319
320 }
321
322 template <class T, int rank> struct tn<pythonDetail::ArrayGet<T,rank>>
323 {
324 static std::string name()
325 {return "pythonDetail::ArrayGet<"+typeName<T>()+","+std::to_string(rank)+">";}
326 };
327
328 template <class T>
329 struct tn<pythonDetail::Iterator<T>>
330 {
331 static string name() {return "classdesc::pythonDetail::Iterator<"+typeName<T>()+">";}
332 };
333
334
335}
336
337
338// extend boost::python function signature processing on callable objects
339namespace boost {
340 namespace python {
341 namespace detail {
342 template <class F, class T>
343 typename classdesc::pythonDetail::Sig<F>::T get_signature(F)
344 {return typename classdesc::pythonDetail::Sig<F>::T();}
345 template <class F, class T>
346 typename classdesc::pythonDetail::Sig<F>::T get_signature(F,T*)
347 {return typename classdesc::pythonDetail::Sig<F>::T();}
348 }
349 }
350}
351
352#include <boost/python.hpp>
353#include <boost/python/raw_function.hpp>
354#include <boost/python/slice.hpp>
355#include <vector>
356
357namespace classdesc
358{
359 template <class T>
360 struct PythonExcludeType: public false_type {};
361
362 template <class T> struct PythonTypableMember;
363
364 template <class T>
365 typename enable_if<Not<PythonBasicType<T>>, boost::python::return_internal_reference<>>::T
366 return_policy() {return boost::python::return_internal_reference<>();}
367
368 template <class T>
369 typename enable_if<PythonBasicType<T>, boost::python::default_call_policies>::T
370 return_policy() {return boost::python::default_call_policies();}
371
372 namespace pythonDetail
373 {
374 template <class F, int arity=Arity<F>::value==2>
376
377 // used for detecting a raw function R f(tuple, dict) that can be
378 // used to implement variable and named argument functions,
379 // including implementing overload dispatching
380 template <class F> struct is_rawFunction<F,true>
381 {
382 // strips reference and const qualifiers for the ith argument
383 template <int i> struct Arg
384 {
385 typedef typename remove_const<typename remove_reference<typename functional::Arg<F,i>::T>::type>::type T;
386 };
387
388 static const bool value=
389 is_same<typename Arg<1>::T,boost::python::tuple>::value &&
390 is_same<typename Arg<2>::T,boost::python::dict>::value;
391 };
392
393 template <class F> struct is_rawFunction<F,false>
394 {
395 static const bool value=false;
396 };
397
398 template <class T>
399 boost::python::object rawInit(const boost::python::tuple& args, const boost::python::dict&) {
400 if (boost::python::len(args)>2)
401 {
402 auto& x=boost::python::extract<T&>(args[0])();
403 auto el=boost::python::extract<boost::python::list>(args[1]);
404 if (el.check())
405 assignList(x,el);
406 }
407 return boost::python::object(); //ie None
408 }
409
410 // *** enum conversion to/from python string ***
411#if PY_MAJOR_VERSION < 3
412 inline const char* to_string(PyObject* x) {return PyString_AsString(x);}
413#else
414 inline const char* to_string(PyObject* x) {return PyUnicode_AsUTF8(x);}
415#endif
416 template <class E>
418 {
419 static PyObject* convert(E e)
420 {
421 return boost::python::incref
422 (boost::python::object
423 (classdesc::enum_keys<E>()(e)).ptr());
424 }
425 };
426
427 template <class E>
428 struct EnumFromStr
429 {
430 EnumFromStr()
431 {
432 boost::python::converter::registry::push_back
433 (&convertible, &construct,
434 boost::python::type_id<E>());
435 }
436
437 static void* convertible(PyObject* obj_ptr)
438 {
439 // Extract the character data from the python string
440 const char* value = to_string(obj_ptr);
441 if (!value || !classdesc::enum_keys<E>().has(value)) return 0;
442 return obj_ptr;
443 }
444
445 static void construct(
446 PyObject* obj_ptr,
447 boost::python::converter::rvalue_from_python_stage1_data* data)
448 {
449 // Extract the character data from the python string
450 const char* value = to_string(obj_ptr);
451
452 // Verify that obj_ptr is a string (should be ensured by convertible())
453 assert(value);
454
455 // Grab pointer to memory into which to construct the new enum
456 void* storage = (
457 (boost::python::converter::rvalue_from_python_storage<E>*)
458 data)->storage.bytes;
459
460 // in-place construct the new enum using the character data
461 // extraced from the python object
462 new (storage) E(classdesc::enum_keys<E>()(value));
463
464 // Stash the memory chunk pointer for later use by boost.python
465 data->convertible = storage;
466 }
467
468 };
469
470 //*******
471
472 // generate an init expression with the same arguments as that of function pointer M
473 template <class M, int N=functional::Arity<M>::value> struct Init;
474
475 template <class... A> struct InitArgs;
476
477 template <class A, class... B> struct InitArgs<InitArgs<B...>, A>
478 : public InitArgs<B...,A> {};
479
480 template <class M, int N, class... A> struct InitArgs<Init<M,N>, A...>
481 : public InitArgs<Init<M,N-1>,typename functional::Arg<M,N>::T,A...> {};
482
483 template <class M, class... A> struct InitArgs<Init<M,0>, A...>
484 {typedef boost::python::init<A...> T;};
485
486
487
488 template <class M, int N> struct Init: public InitArgs<Init<M, N>>
489 {};
490
491
492 }
493
494
496 {
497 struct Scope
498 {
499 struct PythonDummy {};
500 string name;
501 boost::python::class_<PythonDummy> object;
502 shared_ptr<boost::python::scope> scope;
503 Scope(const string& name):
504 name(name), object(name.c_str()), scope(new boost::python::scope(object)) {}
505 // default object refers to current module
506 Scope(): name(PyModule_GetName(boost::python::scope().ptr())),
507 object(name.c_str()), scope(new boost::python::scope(object)) {}
508 };
509 std::vector<Scope> scopeStack; //push back current module onto stack
510 boost::python::scope topScope;
511 std::map<string,shared_ptr<boost::python::object>> namedScope;
512
513 struct ExtractClassNameAndSetScope
514 {
515 string className, modName;
516 boost::python::scope topScope;
517 std::vector<std::shared_ptr<boost::python::scope>> scopeStack;
518 ExtractClassNameAndSetScope(python_t& p, const string& qualifiedName)
519 {
520 const char* b=qualifiedName.c_str(), *e;
521 int nAngle=0; // template argument handling
522 for (; *b==':'; b++); //strip any leading global namespace qualifier
523 for (e=b; *e; ++e)
524 switch (*e)
525 {
526 case ':':
527 if (nAngle==0 && *(e+1)==':')
528 {
529 if (!modName.empty()) modName+=".";
530 modName+=string(b,e);
531 auto i=p.namedScope.find(modName);
532 if (i==p.namedScope.end())
533 i=p.namedScope.emplace
534 (modName, std::make_shared<Class<Scope::PythonDummy,true>>(modName)).first; // ensure exists
535 scopeStack.emplace_back(new boost::python::scope(*i->second));
536 e++;
537 b=e+1;
538 }
539 break;
540 case '<':
541 nAngle++;
542 break;
543 case '>':
544 nAngle--;
545 break;
546 }
547 className=b;
548 }
549 };
550 public:
551
555 {
556 virtual ~ClassBase() {}
557 bool completed=false, started=false;
558
559 template <class T, bool copiable> struct PyClass;
560 template <class T> struct PyClass<T,true>: public boost::python::class_<T>
561 {
562 PyClass(const char* n): boost::python::class_<T>(n,boost::python::no_init){}
563 };
564 template <class T> struct PyClass<T,false>: public boost::python::class_<T,boost::noncopyable>
565 {
566 PyClass(const char* n): boost::python::class_<T,boost::noncopyable>(n,boost::python::no_init){}
567 };
568
569 };
570
573 template <class T,bool copiable>
574 static typename enable_if<is_default_constructible<T>,void>::T
576 {c.def(boost::python::init<>());}
577
578 template <class T,bool copiable>
580 addDefaultConstructor(ClassBase::PyClass<T,copiable>&)
581 {}
582
583 template <class T, bool copiable> struct Class:
584 public ClassBase, public ClassBase::PyClass<T,copiable>
585 {
586 Class(const string& name): ClassBase::PyClass<T,copiable>(name.c_str())
587 {
589 // define a default equality operator
590 defFn("__eq__",pythonDetail::defaultEquality<T>);
591 }
592
593 // distinguish between assignable and unassignable properties, which may be const, or may have assignment deleted
594 template <class X>
595 typename enable_if<
596 And<
597 std::is_copy_assignable<typename pythonDetail::MemberType<X>::T>,
599 >,void>::T
600 addProperty(const string& d, X x) {this->def_readwrite(d.c_str(),x);}
601
602 template <class X>
603 typename enable_if<
604 Or<
606 is_const<typename pythonDetail::MemberType<X>::T>
607 >,void>::T
608 addProperty(const string& d, X x) {this->def_readonly(d.c_str(),x);}
609
610 using PyClass<T,copiable>::def;
611 // handle "raw" functions, enabling variable arguments and overload dispatch
612 template <class F>
614 defFn(const char* n, F f) {
616 "\nreference return of raw function not supported.\nUse boost::python::ptr instead");
617 PyClass<T,copiable>::def(n,boost::python::raw_function(f));
618 return *this;
619 }
620
621 template <class F>
622 typename enable_if<
623 And<
626 is_copy_constructible<functional::Return<F>>
627 >, Class&>::T
628 defFn(const char* n, F f) {PyClass<T,copiable>::def(n,f); return *this;}
629
630 template <class F>
631 typename enable_if<
632 And<
636 >, Class&>::T
637 defFn(const char* n, F f) {return *this;}
638
639
640
641 template <class R, class... Args>
642 typename enable_if<is_reference<R>, Class&>::T
643 overload(const char* n, R (T::*m)(Args...)) {
644 PyClass<T,copiable>::def(n,m,boost::python::return_internal_reference<>());
645 return *this;
646 }
647 template <class R, class... Args>
648 typename enable_if<Not<is_reference<R>>, Class&>::T
649 overload(const char* n, R (T::*m)(Args...)) {
651 return *this;
652 }
653 template <class R, class O,class... Args>
654 typename enable_if<is_reference<R>, Class&>::T
655 overload(const char* n, R (T::*m)(Args...),const O& o) {
656 PyClass<T,copiable>::def(n,m,o[boost::python::return_internal_reference<>()]);
657 return *this;
658 }
659 template <class R, class O, class... Args>
660 typename enable_if<Not<is_reference<R>>, Class&>::T
661 overload(const char* n, R (T::*m)(Args...), const O& o) {
663 return *this;
664 }
665
666 template <class R, class... Args>
667 typename enable_if<is_reference<R>, Class&>::T
668 overload(const char* n, R (T::*m)(Args...) const) {
669 PyClass<T,copiable>::def(n,m,boost::python::return_internal_reference<>());
670 return *this;
671 }
672 template <class R, class... Args>
673 typename enable_if<Not<is_reference<R>>, Class&>::T
674 overload(const char* n, R (T::*m)(Args...) const) {
676 return *this;
677 }
678 template <class R, class O,class... Args>
679 typename enable_if<is_reference<R>, Class&>::T
680 overload(const char* n, R (T::*m)(Args...) const,const O& o) {
681 PyClass<T,copiable>::def(n,m,o[boost::python::return_internal_reference<>()]);
682 return *this;
683 }
684 template <class R, class O, class... Args>
685 typename enable_if<Not<is_reference<R>>, Class&>::T
686 overload(const char* n, R (T::*m)(Args...) const, const O& o) {
688 return *this;
689 }
690
691 };
692
693 // lazy instantiation pattern to avoid needing an object file, and
694 // link time ordering dependencyy
695
696 //can be cleared after all python descriptor processing has
697 // finished to free memory, otherwise the descriptor will
698 // potentially throw an exception if this vector is cleared
699 static std::vector<shared_ptr<ClassBase> >& classes()
700 {
701 static std::vector<shared_ptr<ClassBase> > impl;
702 return impl;
703 }
704
705 // lazy instantiation pattern to register a unique class object
706 // per type.
707 template <class T>
708 Class<T,is_copy_constructible<T>::value>& getClass()
709 {
710 typedef Class<T,is_copy_constructible<T>::value> C;
711 static size_t id=classes().size();
712 if (id==classes().size())
713 {
714 ExtractClassNameAndSetScope scope(*this,typeName<T>());
715 classes().push_back(shared_ptr<ClassBase>(new C(scope.className)));
716 string pyQualName;
717 if (!scope.modName.empty()) pyQualName=scope.modName+".";
718 pyQualName+=scope.className;
719 // insert a reference to this class object for handling class scoped names
720 if (!namedScope.count(pyQualName))
721 namedScope.emplace
722 (pyQualName, std::dynamic_pointer_cast<boost::python::object>(classes().back()));
723 }
724 else if (id>classes().size())
725 throw exception("classes registry no longer valid");
726 return dynamic_cast<C&>(*classes()[id]);
727 }
729
730 string tail(const string& d) {
731 size_t p=d.rfind('.');
732 if (p==string::npos)
733 return d;
734 else
735 return d.substr(p+1);
736 }
737
738 void checkScope(string d) {
739 size_t level=0;
740 for (size_t p=d.find('.'); p!=string::npos; p=d.find('.'), level++)
741 {
742 string head=d.substr(0,p);
743 if (level<scopeStack.size() && head!=scopeStack[level].name)
744 scopeStack.erase(scopeStack.begin()+level,scopeStack.end());
745 if (level==scopeStack.size())
746 scopeStack.push_back(Scope(head));
747 d=d.substr(p+1);
748 }
749 scopeStack.erase(scopeStack.begin()+level,scopeStack.end());
750 // final component of d is not part of scope
751 }
752
753 // recursively define classes of arguments
754 template <class F, int N>
756 static void define(python_t& p) {
757 typedef typename remove_const<
758 typename remove_reference<
760 >::type
761 >::type T;
762 if (!pythonDetail::classDefStarted<T>())
763 p.defineClass<T>();
764 DefineArgClasses<F,N-1>::define(p);
765 }
766 };
767
768 template <class F>
769 struct DefineArgClasses<F,0> {
770 static void define(python_t& p) {
771 typedef typename remove_const<
772 typename remove_reference<
774 >::type
775 >::type T;
776 if (!pythonDetail::classDefStarted<T>())
777 // define return type
778 p.defineClass<T>();
779 }
780 };
781
782 template <class T>
784 addObject(const string& d, T& o) {
785 using namespace boost::python;
786 checkScope(d);
787
788 if (!scopeStack.empty())
789 scopeStack.back().object.def_readwrite(tail(d).c_str(),o);
790 else
791 extract<dict>(scope().attr("__dict__"))()[tail(d).c_str()]=ptr(&o);
792 }
793 template <class T>
795 addObject(const string& d, const T& o) {
796 using namespace boost::python;
797 checkScope(d);
798 if (!scopeStack.empty())
799 scopeStack.back().object.def_readonly(tail(d).c_str(),o);
800 else
801 extract<dict>(scope().attr("__dict__"))()[tail(d).c_str()]=ptr(&o);
802 }
803
804 template <class F>
806 addFunctional(const string& d, F f) {
807 checkScope(d);
808 boost::python::def(tail(d).c_str(),f);
809 if (!scopeStack.empty())
810 scopeStack.back().object.staticmethod(tail(d).c_str());
811 DefineArgClasses<F,functional::Arity<F>::value>::define(*this);
812 }
813
814 // ignore pointer returns, as we don't know anything about the object being pointed to.
815 template <class F>
816 typename enable_if<is_pointer<typename functional::Return<F>::T>, void>::T
817 addFunctional(const string&, F) {}
818
819 // no object present, update class definition
820 template <class C, class M>
821 typename enable_if<
822 And<
823 Not<is_reference<typename functional::Return<M>::T>>,
824 Not<is_pointer<typename functional::Return<M>::T>>
825 >,void>::T
826 addMemberFunction(const string& d, M m)
827 {
828 auto& c=getClass<C>();
829 if (!c.completed)
830 c.defFn(tail(d).c_str(),m);
832 }
833
834 // for methods returning a reference, create a wrapper object that
835 // can be pythonified
836 template <class C, class M>
837 typename enable_if<is_reference<typename functional::Return<M>::T>,void>::T
838 addMemberFunction(const string& d, M m)
839 {
840 auto& c=getClass<C>();
841 if (!c.completed)
842 c.def(tail(d).c_str(),m,boost::python::return_internal_reference<>());
844 }
845
846 // ignore pointer returns, as we don't know anything about the object being pointed to.
847 template <class C, class M>
848 typename enable_if<is_pointer<typename functional::Return<M>::T>,void>::T
849 addMemberFunction(const string&, M) {}
850
851 template <class C, class M>
852 typename enable_if<functional::is_nonmember_function_ptr<M>,void>::T
853 addMemberObject(const string& d, M m)
854 {
855 auto& c=getClass<C>();
856 if (!c.completed)
857 c.defFn(tail(d).c_str(),m);
858 }
859
860 template <class C, class M>
861 typename enable_if<And<Not<is_Carray<typename pythonDetail::MemberType<M>::T> >, Not<functional::is_nonmember_function_ptr<M> > >,void>::T
862 addMemberObject(const string& d, M m)
863 {
864 auto& c=getClass<C>();
865 if (!c.completed)
866 c.addProperty(tail(d),m);
867 // ensure member type is registered
868 DefineArgClasses<M,0>::define(*this);
869 }
870
871 template <class C, class M>
872 typename enable_if<is_Carray<typename pythonDetail::MemberType<M>::T>,void>::T
873 addMemberObject(const string& d, M m)
874 {
875 auto& c=getClass<C>();
876 if (!c.completed)
877 c.add_property(tail(d).c_str(), pythonDetail::ArrayMemRef<C,M>(m),
878 pythonDetail::ArrayMemRef<C,M>(m));
879 pythonDetail::ArrayMemRef<C,M>::L::registerClass(*this);
880 }
881
882
883 template <class C, class M>
884 typename enable_if<
885 And<is_member_function_pointer<M>,
886 functional::AllArgs<M,PythonTypableMember>,
887 Not<is_pointer<typename functional::Return<M>::T>>
888 >,void>::T
889 addMember(const string& d, M m) {addMemberFunction<C>(d,m);}
890
891// template <class C, class M>
892// typename enable_if<
893// And<is_member_function_pointer<M>,
894// Not<functional::AllArgs<M,PythonTypableMember>>,
895// Not<is_pointer<typename functional::Return<M>::T>>
896// >,void>::T
897// addMember(const string& d, M m) {}
898
899 template <class C, class M>
900 typename enable_if<And<is_member_object_pointer<M>,
901 PythonTypableMember<M>,
902 Not<functional::is_nonmember_function_ptr<M> >
903 >,void>::T
904 addMember(const string& d, M m) {addMemberObject<C>(d,m);}
905
906
907 template <class C, class M>
908 typename enable_if<And<is_member_object_pointer<M>,
909 Or<
910 Not<PythonTypableMember<M>>,
911 functional::is_nonmember_function_ptr<M>
912 >>,void>::T
913 addMember(const string& d, M m) {}
914
915
916 template <class C, class M>
917 typename enable_if<
918 And<
919 functional::is_nonmember_function_ptr<M>,
920 functional::AllArgs<M,PythonTypableMember>,
921 Not<is_pointer<typename functional::Return<M>::T>>
922 >,void>::T
923 addMember(const string& d, M m) {
924 auto& c=getClass<C>();
925 if (!c.completed)
926 c.defFn(tail(d).c_str(),m);
927 }
928
929 // ignore pointer returns, and unassignable arguments
930 template <class C, class M>
931 typename enable_if<
932 Or<
933 is_pointer<typename functional::Return<M>::T>,
934 Not<functional::AllArgs<M, PythonTypableMember>>
935 >, void>::T
936 addMember(const string&, M) {}
937
938 template <class C, class T>
939 void addStaticMember(const string& d, T* a) {
940 auto& c=getClass<C>();
941 if (!c.completed)
942 c.addProperty(tail(d).c_str(),a);
943 }
944
945 template <class C, class M>
946 void addConstructor(M) {
947 auto& c=getClass<C>();
948 if (!c.completed)
949 c.def(typename pythonDetail::Init<M>::T());
951 }
952
953 template <class C, class M>
954 void addEnum(const string& d, M m)
955 {
956 auto& c=getClass<C>();
957 if (!c.completed)
958 c.add_property(tail(d).c_str(),pythonDetail::enumGet<C>(m),pythonDetail::enumSet<C>(m));
959 }
960
962 template <class T>
963 typename enable_if<Not<is_abstract<T> >, void>::T
964 defineClass() {python<T>(*this,"");}
965
966 template <class T>
967 typename enable_if<is_abstract<T>, void>::T
968 defineClass() {}
969
970 template <class E>
971 void defineEnum();
972
973 };
974
976 template <class T>
977 T convertListTo(const boost::python::list& y)
978 {
979 T x;
980 for (int i=0; i<boost::python::len(y); ++i)
981 x.push_back(boost::python::extract<typename T::value_type>(y[i]));
982 return x;
983 }
984
985 template <class T>
986 void assignList(T& x, const boost::python::list& y)
987 {x=std::move(convertListTo<T>(y));}
988
989 template <class T>
990 boost::shared_ptr<T> constructFromList(const boost::python::list& y)
991 {
992 boost::shared_ptr<T> x(new T);
993 assignList(*x,y);
994 return x;
995 }
996
997 template <class C, class T=C>
998 typename enable_if<is_sequence<T>,void>::T
999 python(python_t& p, const string& ) {
1000 auto& c=p.getClass<C>();
1001 if (!c.completed)
1002 c.def("__len__", &pythonDetail::len<T>).
1003 def("__getitem__", &pythonDetail::getItem<T>, return_policy<typename T::value_type>()).
1004 def("__setitem__", &pythonDetail::setItem<T>).
1005 def("assign",assignList<T>).
1006 def("__init__",boost::python::make_constructor(constructFromList<T>)).
1007 def("constructor",boost::python::make_constructor(constructFromList<T>));
1008
1009 python<typename T::value_type>(p,"");
1010
1011 python<typename functional::Return<decltype(&pythonDetail::getItem<T>)>::T>(p,"");
1012 }
1013
1014 template <class C, class T=C>
1016 python(python_t& p, const string& ) {
1017 auto& c=p.getClass<C>();
1018 if (!c.completed)
1019 c.defFn("__len__", &pythonDetail::len<C>).
1020 defFn("__getitem__", &pythonDetail::getMapItem<C>).
1021 defFn("__setitem__", &pythonDetail::setMapItem<C>).
1022 defFn("__iter__", &pythonDetail::iter<C>);
1023 python<typename T::mapped_type>(p,"");
1024 python<typename T::key_type>(p,"");
1025 pythonDetail::Iterator<C>::registerClass(p);
1026 }
1027
1028 template <class T>
1029 T& sharedPtrTargetRefGetter(const shared_ptr<T>& self)
1030 {
1031 if (self)
1032 return *self;
1033 else
1034 throw std::runtime_error("null dereference");
1035 }
1036 template <class T>
1037 T sharedPtrTargetGetter(const shared_ptr<T>& self)
1038 {return sharedPtrTargetRefGetter(self);}
1039
1040 template <class T>
1041 typename enable_if<std::is_copy_assignable<T>, void>::T
1042 sharedPtrTargetSetter(const shared_ptr<T>& self,const T& v)
1043 {
1044 if (self)
1045 *self=v;
1046 else
1047 throw std::runtime_error("null dereference");
1048 }
1049 template <class T>
1051 sharedPtrTargetSetter(const shared_ptr<T>& self,const T&)
1052 {
1053 if (self)
1054 throw std::runtime_error(typeName<T>()+" not assignable");
1055 else
1056 throw std::runtime_error("null dereference");
1057 }
1058
1059 template <class T>
1061 pythonSharedPtr(python_t& p, const string& d)
1062 {
1063 auto& c=p.getClass<classdesc::shared_ptr<T> >();
1064 if (!c.completed)
1065 c.add_property("target",
1066 make_function(&sharedPtrTargetRefGetter<T>, boost::python::return_internal_reference<>()),
1067 &sharedPtrTargetSetter<T>);
1068 python<T>(p,d);
1069 }
1070 template <class T>
1071 typename enable_if<Or<PythonBasicType<T>,is_enum<T>>,void>::T
1072 pythonSharedPtr(python_t& p, const string& d)
1073 {
1074 auto& c=p.getClass<classdesc::shared_ptr<T> >();
1075 if (!c.completed)
1076 c.add_property("target",
1077 &sharedPtrTargetGetter<T>,
1078 &sharedPtrTargetSetter<T>);
1079 python<T>(p,d);
1080 }
1081
1082 template <class F>
1084 python(python_t& p, const string& d, F f) {
1085 p.addFunctional(d,f);
1086 }
1087
1088 template <class T>
1089 void python(python_t& p, const string& d, is_const_static, T* a)
1090 {
1091 p.addObject(tail(d),*a);
1092 }
1093
1094 template <class C, class T, class M>
1095 void python_type(python_t& p, const string& d, is_const_static, M m)
1096 {
1097 p.addStaticMember<C>(d,m);
1098 }
1099
1100 template <class C, class T, class M>
1101 typename enable_if<Not<is_function<M> >, void>::T
1102 python_type(python_t& p, const string& d, M* m)
1103 {
1104 p.addStaticMember<C>(d,m);
1105 }
1106
1107 template <class T>
1108 void python(python_t& p, const string& d, is_constructor, T* a)
1109 {}
1110
1111 template <class C, class T, class M>
1112 typename enable_if<Not<is_abstract<T> >, void>::T
1113 python_type(python_t& p, const string&, is_constructor, M m)
1114 {
1115 p.addConstructor<T>(m);
1116 }
1117
1118 template <class C, class T, class M>
1119 typename enable_if<is_abstract<T>, void>::T
1120 python_type(python_t&, const string&, is_constructor, M)
1121 { }
1122
1123 template <class C, class B, class M>
1124 void python_type(python_t& p, const string& d, M m)
1125 {
1126 p.addMember<C>(d,m);
1127 }
1128
1129 template <class C, class T>
1130 void python_type(python_t& p, const string& d, Exclude<T> (C::*m))
1131 {
1132 }
1133
1134 template <class T>
1135 void python_onbase(python_t& p, const string& d, T& a);
1136
1137 namespace pythonDetail
1138 {
1139
1140 inline void translate(StopIteration)
1141 {PyErr_SetString(PyExc_StopIteration,"");}
1142 static int dummy = (boost::python::register_exception_translator<StopIteration>(&translate),0);
1143
1144 template <class T>
1145 void Iterator<T>::registerClass(python_t& p)
1146 {
1147 auto& c=p.getClass<Iterator<T>>();
1148 if (!c.completed)
1149 {
1150 c.defFn("__next__",&Iterator<T>::next);
1151 c.completed=true;
1152 }
1153 }
1154 }
1155
1159
1164
1171 template <class T>
1172 void addPythonObject(const std::string& path, T& object)
1173 {
1174 using namespace boost::python;
1175 auto lastDot=path.rfind('.');
1176 string module, name;
1177 if (lastDot==std::string::npos)
1178 {
1179 module="__main__";
1180 name=path;
1181 }
1182 else
1183 {
1184 module=path.substr(0,lastDot);
1185 name=path.substr(lastDot+1);
1186 }
1187 dict the_dict=extract<dict>(import(module.c_str()).attr("__dict__"));
1188 the_dict[name]=ptr(&object);
1189 }
1190
1191 template <> inline void python<boost::python::object>(python_t&,const string&) {}
1192 template <> inline void python<boost::python::tuple>(python_t&,const string&) {}
1193 template <> inline void python<boost::python::list>(python_t&,const string&) {}
1194 template <> inline void python<boost::python::dict>(python_t&,const string&) {}
1195 template <> inline void python<boost::python::slice>(python_t&,const string&) {}
1196 template <> inline void python<boost::python::str>(python_t&,const string&) {}
1197
1198 template <class E>
1199 typename enable_if<is_enum<E>, void>::T
1200 python(python_t& p,const string&) {
1201 p.defineEnum<E>();
1202 }
1203}
1204
1205namespace classdesc_access
1206{
1207 namespace cd=classdesc;
1208 template <class T, class Enable=void> struct access_python;
1209
1210 template <class T> struct access_python<cd::Exclude<T> >
1211 {
1212 template <class U>
1213 void type(cd::python_t&,const cd::string&) {}
1214 };
1215
1216 template <class T> struct access_python<classdesc::shared_ptr<T> >
1217 {
1218 template <class U>
1219 void type(cd::python_t& p,const cd::string& d) {
1220 classdesc::pythonSharedPtr<T>(p,d);
1221 }
1222 };
1223
1224}
1225
1226using classdesc::python;
1227using classdesc::python_onbase;
1228
1229#endif
Definition pack_stl.h:51
Definition classdesc.h:923
Definition classdesc.h:926
Definition python_base.h:496
static enable_if< is_default_constructible< T >, void >::T addDefaultConstructor(ClassBase::PyClass< T, copiable > &c)
Definition python_base.h:575
enable_if< Not< is_abstract< T > >, void >::T defineClass()
utility method to add a Python wrapper class for T
Definition python_base.h:964
Metaprogramming support for processing functions of multiple arguments.
contains code generated by functiondb.sh that defines functional attributes.
Contains access_* structs, and nothing else. These structs are used to gain access to private members...
Definition classdesc_access.h:20
Contains definitions related to classdesc functionality.
void addPythonObject(const std::string &path, T &object)
Definition python_base.h:1172
T convertListTo(const boost::python::list &y)
convert a python list to a sequence type T
Definition python_base.h:977
Definition pythonCAPI.h:97
Definition classdesc.h:420
Definition RESTProcess_epilogue.h:159
Definition python_base.h:38
Definition classdesc.h:1012
Definition classdesc.h:405
Definition classdesc.h:423
types that have a primitive representation in Python
Definition python_base.h:43
Definition python_base.h:360
Definition python_epilogue.h:61
controlled template specialisation: stolen from boost::enable_if.
Definition classdesc.h:282
base class for exceptions thrown by classdesc
Definition classdesc.h:546
Definition function.h:80
Definition function.h:50
Return::T (or ::type) is the return type of F
Definition function.h:45
Definition object.h:29
Definition python_base.h:145
Definition python_base.h:133
Definition python_base.h:179
Definition python_base.h:418
Definition python_base.h:475
Definition python_base.h:489
Definition python_base.h:267
Definition python_base.h:61
Definition python_base.h:86
Definition python_base.h:94
Definition python_base.h:103
Definition python_base.h:107
exception to signal end of iteration
Definition python_base.h:263
Definition python_base.h:375
Definition python_base.h:559
Definition python_base.h:555
Definition python_base.h:755
Definition python_base.h:499
Definition classdesc.h:571
Definition python_base.h:1208