1 
2 /*
3 A* -------------------------------------------------------------------
4 B* This file contains source code for the PyMOL computer program
5 C* copyright 1998-2000 by Warren Lyford Delano of DeLano Scientific.
6 D* -------------------------------------------------------------------
7 E* It is unlawful to modify or remove this copyright notice.
8 F* -------------------------------------------------------------------
9 G* Please see the accompanying LICENSE file for further information.
10 H* -------------------------------------------------------------------
11 I* Additional authors of this source file include:
12 -*
13 -*
14 -*
15 Z* -------------------------------------------------------------------
16 */
17 #ifndef _H_PConv
18 #define _H_PConv
19 
20 #include"os_python.h"
21 
22 #include"PyMOLGlobals.h"
23 #include"Base.h"
24 #include"OVLexicon.h"
25 
26 #include <array>
27 #include <map>
28 #include <set>
29 #include <string>
30 #include <type_traits>
31 #include <vector>
32 #include <algorithm>
33 
34 /* Convenient conversion routines for C<->Python data interchange
35 
36    Note that all of these routines assume that we have the global
37    interpreter lock - blocking all other threads.
38 
39    There are three ways to get it:
40 
41    - call PBlock() [followe by PUnblock() when done]
42 
43    - call PBlockAndUnlockAPI - [followed by PLockAPIAndUnblock() when
44    done]
45 
46    - or in response to a call to the PM API, you will have the main
47    Python thread by default.  [Note that within an
48    APIEntry(),APIExit() block the lock is released, so these
49    functions should be called outside of that block].
50 
51 */
52 
53 // CPythonVal macros
54 #define CPythonVal PyObject
55 #define CPythonVal_PyString_Check                       PyString_Check
56 #define CPythonVal_PyList_Check                         PyList_Check
57 #define CPythonVal_PyList_Size                          PyList_Size
58 #define CPythonVal_PyList_GetItem(G, list, i)           PyList_GetItem(list, i)
59 #define CPythonVal_PyDict_GetItemString(G, p, key)      PyDict_GetItemString(p, key)
60 #define CPythonVal_PConvPyIntToInt                                              PConvPyIntToInt
61 #define CPythonVal_PConvPyIntToInt_From_List(G, list, i, ptr)                   PConvPyIntToInt(PyList_GetItem(list, i), ptr)
62 #define CPythonVal_PConvPyFloatToFloat_From_List(G, list, i, ptr)               PConvPyFloatToFloat(PyList_GetItem(list, i), ptr)
63 #define CPythonVal_PConvPyListToIntArrayInPlace(G, obj, ff, ll)                 PConvPyListToIntArrayInPlace(obj, ff, ll)
64 #define CPythonVal_PConvPyListToIntArrayInPlace_From_List(G, list, i, ff, ll)   PConvPyListToIntArrayInPlace(PyList_GetItem(list, i), ff, ll)
65 #define CPythonVal_PConvPyListToFloatArrayInPlaceAutoZero_From_List(G, list, i, ...) \
66                    PConvPyListToFloatArrayInPlaceAutoZero(PyList_GetItem(list, i), __VA_ARGS__)
67 #define CPythonVal_PConvPyListToFloatVLANoneOkay_From_List(G, list, i, f)       PConvPyListToFloatVLANoneOkay(PyList_GetItem(list, i), f)
68 #define CPythonVal_PConvPyListToLabPosVLA(G, obj, vla_ptr)                      PConvPyListToLabPosVLA(obj, vla_ptr)
69 #define CPythonVal_PConvPyStrToStr_From_List(G, list, i, ptr, l)                PConvPyStrToStr(PyList_GetItem(list, i), ptr, l)
70 
71 #define CPythonVal_Free(obj)
72 #define CPythonVal_FreeAll(PYOBJECT)
73 
74 #define CPythonVal_New(G, PYOBJECT)                     PYOBJECT
75 #define CPythonVal_Append_List(LIST, ITEM)              PyList_Append(LIST, ITEM)
76 #define CPythonVal_New_List()                           PyList_New(0)
77 #define CPythonVal_New_Tuple(SIZE)                      PyTuple_New(SIZE)
78 #define CPythonVal_Tuple_SetItem(TUPLE, ITEM, VAL)      PyTuple_SetItem(TUPLE, ITEM, VAL)
79 #define CPythonVal_New_String(BUF, LEN)                 PyString_FromStringAndSize(BUF, LEN)
80 #define CPythonVal_New_Boolean(VAL)                     (VAL ? PyBool_FromLong(1) : PyBool_FromLong(0))
81 #define CPythonVal_New_Integer(VAL)                     PyInt_FromLong(VAL)
82 #define CPythonVal_New_Float(VAL)                       PyFloat_FromDouble(VAL)
83 
84 #define CPythonVal_IsNone(PYOBJECT)                     (PYOBJECT == Py_None)
85 
86 /* == error-checking routines: true = success, false = failure. */
87 
88 
89 /* NOTE: the string routines will write strings up to the specified
90  * length, PLUS a NULL...so watch out for array overruns */
91 
92 int PConvAttrToStrMaxLen(PyObject * obj, const char *attr, char *str, ov_size ll);
93 
94 int PConvPyListToBitmask(PyObject * obj, int *bitmask, ov_size ll);
95 int PConvPyListToExtent(PyObject * obj, float *mn, float *mx);
96 
97 int PConvAttrToFloatArrayInPlace(PyObject * obj, const char *attr, float *ff, ov_size ll);
98 int PConvAttrToIntArrayInPlace(PyObject * obj, const char *attr, int *ff, ov_size ll);
99 int PConvAttrToPtr(PyObject * obj, const char *name, void **cobj);
100 
101 int PConvCObjectToPtr(PyObject * obj, void **ptr);
102 int PConvPyListToStrVLAList(PyObject * obj, char **vla, int *n_str);
103 
104 int PConvPyListToStringVLA(PyObject * obj, char **vla_ptr);
105 #define PConvPyListToIntVLA(obj, f)     PConvPyListToIntArrayImpl(obj, f, true)
106 
107 int PConvPyStrToStr(PyObject * obj, char *ptr, int l);
108 #ifndef _PYMOL_NOPY
109 int PConvPyStrToStrPtr(PyObject * obj, const char **ptr);
110 #endif
111 int PConvPyStrToLexRef(PyObject * obj, OVLexicon * lex, int *lex_ref);
112 int PConvPyFloatToFloat(PyObject * obj, float *ptr);
113 int PConvPyIntToChar(PyObject * obj, char *ptr);
114 int PConvPyIntToInt(PyObject * obj, int *ptr);
115 int PConvPyBoolToInt(PyObject * obj, int *ptr);
116 int PConvPyListToLabPosVLA(PyObject * obj, LabPosType ** vla_ptr);
117 
118 
119 /* Jenarix conventions -- returns before args */
120 
121 ov_status PConvPyTupleToIntVLA(int **result, PyObject * tuple);
122 ov_status PConvPyTupleToFloatVLA(float **result, PyObject * tuple);
123 
124 
125 /* === end === */
126 
127 
128 /* categories below... */
129 
130 PyObject *PConvFloatVLAToPyList(const float *vla);
131 PyObject *PConvFloatVLAToPyTuple(float *vla);
132 PyObject *PConvIntVLAToPyList(const int *vla);
133 PyObject *PConvIntVLAToPyTuple(int *vla);
134 PyObject *PConvIntArrayToPyList(const int *f, int l, bool dump_binary=false);
135 PyObject *PConvSIntArrayToPyList(const short int *f, int l);
136 PyObject *PConvSCharArrayToPyList(const signed char *f, int l);
137 PyObject *PConvLabPosVLAToPyList(const LabPosType * vla, int l);
138 
139 void PConvFloat3ToPyObjAttr(PyObject * obj, const char *attr, const float *v);
140 void PConvFloatToPyObjAttr(PyObject * obj, const char *attr, float f);
141 void PConvIntToPyObjAttr(PyObject * obj, const char *attr, int i);
142 void PConvInt2ToPyObjAttr(PyObject * obj, const char *attr, const int *v);
143 void PConvStringToPyObjAttr(PyObject * obj, const char *attr, const char *f);
144 
145 int PConvPyObjectToFloat(PyObject * object, float *value);
146 int PConvPyObjectToInt(PyObject * object, int *value);
147 int PConvPyObjectToChar(PyObject * object, char *value);
148 
149 
150 /* NOTE: the string routines will write strings up to the specified
151  * length, PLUS a NULL...so watch out for array overruns */
152 
153 int PConvPyObjectToStrMaxLen(PyObject * object, char *value, int ln);
154 int PConvPyObjectToStrMaxClean(PyObject * object, char *value, int ln);
155 
156 PyObject *PConvStringListToPyList(int l, const char * const *str);
157 PyObject *PConvStringVLAToPyList(const char *str);
158 
159 void PConv44PyListTo44f(PyObject * src, float *dest);   /* note loss of precision */
160 
161 #define PConvPyListToFloatVLA(obj, f)   PConvPyListToFloatArrayImpl(obj, f, true)
162 int PConvPyListToFloatVLANoneOkay(PyObject * obj, float **f);
163 int PConvPyList3ToFloatVLA(PyObject * obj, float **f);
164 #define PConvPyListToFloatArray(obj, f) PConvPyListToFloatArrayImpl(obj, f, false)
165 int PConvPyListToFloatArrayImpl(PyObject * obj, float **f, bool as_vla);
166 int PConvPyListToDoubleArray(PyObject * obj, double **f);
167 int PConvPyListToFloatArrayInPlace(PyObject * obj, float *ff, ov_size ll);
168 int PConvPyListOrTupleToFloatArrayInPlace(PyObject * obj, float *ff, ov_size ll);
169 int PConvPyListToFloatArrayInPlaceAutoZero(PyObject * obj, float *ii, ov_size ll);
170 
171 int PConvPyListToDoubleArrayInPlace(PyObject * obj, double *ff, ov_size ll);
172 
173 PyObject *PConvFloatArrayToPyList(const float *f, int l, bool dump_binary=false);
174 PyObject *PConvFloatArrayToPyListNullOkay(const float *f, int l);
175 PyObject *PConvDoubleArrayToPyList(const double *f, int l);
176 
177 #define PConvPyListToIntArray(obj, f)   PConvPyListToIntArrayImpl(obj, f, false)
178 int PConvPyListToIntArrayImpl(PyObject * obj, int **f, bool as_vla);
179 int PConvPyListToIntArrayInPlace(PyObject * obj, int *ff, ov_size ll);
180 int PConvPyListToIntArrayInPlaceAutoZero(PyObject * obj, int *ii, ov_size ll);
181 
182 int PConvPyListToSIntArrayInPlaceAutoZero(PyObject * obj, short int *ii, ov_size ll);
183 int PConvPyListToSCharArrayInPlaceAutoZero(PyObject * obj, signed char *ii, ov_size ll);
184 
185 PyObject *PConv3DIntArrayTo3DPyList(int ***array, int *dim);
186 
187 PyObject *PConvPickleLoads(PyObject * str);
188 PyObject *PConvPickleDumps(PyObject * obj);
189 PyObject *PConvAutoNone(PyObject * result);     /* automatically own Py_None */
190 PyObject *PConvIntToPyDictItem(PyObject * dict, const char *key, int i);
191 
192 /* ============================================================ */
193 /*
194  * PConvToPyObject: Convert any standart type (primitives
195  * and c++ std library) to a python object.
196  *
197  * Return value: New reference.
198  */
PConvToPyObject(PyObject * v)199 inline PyObject * PConvToPyObject(PyObject * v) {
200   return v;
201 }
202 
PConvToPyObject(int v)203 inline PyObject * PConvToPyObject(int v) {
204   return PyInt_FromLong(v);
205 }
206 
PConvToPyObject(float v)207 inline PyObject * PConvToPyObject(float v) {
208   return PyFloat_FromDouble(v);
209 }
210 
PConvToPyObject(double v)211 inline PyObject * PConvToPyObject(double v) {
212   return PyFloat_FromDouble(v);
213 }
214 
PConvToPyObject(const std::string & v)215 inline PyObject * PConvToPyObject(const std::string &v) {
216   return PyString_FromString(v.c_str());
217 }
218 
PConvToPyObject(const char * v)219 inline PyObject * PConvToPyObject(const char * v) {
220 #ifndef _PYMOL_NOPY
221   if (!v) {
222     Py_RETURN_NONE;
223   }
224 #endif
225   return PyString_FromString(v);
226 }
227 
PConvToPyObject(const float * v,int n)228 inline PyObject * PConvToPyObject(const float * v, int n) {
229   return PConvFloatArrayToPyList((float*)v, n);
230 }
231 
232 template <class T>
PConvToPyObject(const std::vector<T> & v)233 PyObject * PConvToPyObject(const std::vector<T> &v) {
234   int n = v.size();
235   PyObject * o = PyList_New(n);
236 
237   for (int i = 0; i < n; ++i) {
238     PyList_SetItem(o, i, PConvToPyObject(v[i]));
239   }
240 
241   return o;
242 }
243 
244 template <class T, std::size_t N>
PConvToPyObject(const std::array<T,N> & arr)245 PyObject * PConvToPyObject(const std::array<T, N> &arr) {
246   PyObject * o = PyList_New(N);
247 
248   for (int i = 0; i < N; ++i) {
249     PyList_SetItem(o, i, PConvToPyObject(arr[i]));
250   }
251 
252   return o;
253 }
254 
255 /*
256  * Convert a set to a Python list
257  */
258 template <class T>
PConvToPyObject(const std::set<T> & v)259 PyObject * PConvToPyObject(const std::set<T> &v) {
260   size_t i = 0, n = v.size();
261   PyObject * o = PyList_New(n);
262 
263   for (auto it = v.begin(); it != v.end(); ++it) {
264     PyList_SET_ITEM(o, i++, PConvToPyObject(*it));
265   }
266 
267   return o;
268 }
269 
270 /*
271  * Convert a map to a flat Python list
272  *
273  * {k1: v1, k2: v2, ...} -> [k1, v1, k2, v2, ...]
274  */
275 template <class K, class V>
PConvToPyObject(const std::map<K,V> & v)276 PyObject * PConvToPyObject(const std::map<K, V> &v) {
277   size_t i = 0, n = v.size();
278   PyObject * o = PyList_New(n * 2);
279 
280   for (auto it = v.begin(); it != v.end(); ++it) {
281     PyList_SET_ITEM(o, i++, PConvToPyObject(it->first));
282     PyList_SET_ITEM(o, i++, PConvToPyObject(it->second));
283   }
284 
285   return o;
286 }
287 
288 /*
289  * Convert a pair to a Python tuple
290  */
291 template <class T1, class T2>
PConvToPyObject(const std::pair<T1,T2> & v)292 PyObject* PConvToPyObject(const std::pair<T1, T2> &v) {
293   PyObject* o = PyTuple_New(2);
294   PyTuple_SET_ITEM(o, 0, PConvToPyObject(v.first));
295   PyTuple_SET_ITEM(o, 1, PConvToPyObject(v.second));
296   return o;
297 }
298 
299 namespace pymol
300 {
301 struct Void;
302 }
303 
PConvToPyObject(const pymol::Void &)304 inline PyObject* PConvToPyObject(const pymol::Void&)
305 {
306 #ifndef _PYMOL_NOPY
307   Py_RETURN_NONE;
308 #else
309   return nullptr;
310 #endif
311 }
312 
313 /* ============================================================ */
314 /*
315  * PConvFromPyObject: Templated conversion of a python object to a
316  * standart type (primitives and c++ std library).
317  */
318 
319 template <typename Int,
320     typename std::enable_if<std::is_integral<Int>::value>::type* = nullptr>
PConvFromPyObject(PyMOLGlobals *,PyObject * obj,Int & out)321 inline bool PConvFromPyObject(PyMOLGlobals*, PyObject* obj, Int& out)
322 {
323   out = PyInt_AsLong(obj);
324   return true;
325 }
326 
327 template <typename Float,
328     typename std::enable_if<std::is_floating_point<Float>::value>::type* =
329         nullptr>
PConvFromPyObject(PyMOLGlobals *,PyObject * obj,Float & out)330 inline bool PConvFromPyObject(PyMOLGlobals*, PyObject* obj, Float& out)
331 {
332   out = PyFloat_AsDouble(obj);
333   return true;
334 }
335 
PConvFromPyObject(PyMOLGlobals *,PyObject * obj,std::string & out)336 inline bool PConvFromPyObject(PyMOLGlobals *, PyObject * obj, std::string &out) {
337   out = PyString_AsSomeString(obj);
338   return true;
339 }
340 
PConvFromPyObject(PyMOLGlobals *,PyObject * obj,float * out)341 inline bool PConvFromPyObject(PyMOLGlobals *, PyObject * obj, float * out) {
342   return PConvPyListToFloatArrayInPlace(obj, out, 0);
343 }
344 
345 template <class T>
PConvFromPyObject(PyMOLGlobals * G,PyObject * obj,std::vector<T> & out)346 bool PConvFromPyObject(PyMOLGlobals * G, PyObject * obj, std::vector<T> &out) {
347   if (PyBytes_Check(obj)) {
348     // binary_dump
349     size_t slen = PyBytes_Size(obj);
350 
351     if (slen % sizeof(T)) {
352       return false;
353     }
354 
355     out.resize(slen / sizeof(T));
356 
357     auto strval = PyBytes_AsSomeString(obj);
358     std::copy_n(strval.data(), slen, reinterpret_cast<char*>(out.data()));
359     return true;
360   }
361 
362   if (!PyList_Check(obj))
363     return false;
364 
365   int n = PyList_Size(obj);
366 
367   out.clear();
368   out.reserve(n);
369 
370   for (int i = 0; i < n; ++i) {
371     PyObject *item = PyList_GET_ITEM(obj, i);
372 
373     T t;
374     if (!PConvFromPyObject(G, item, t))
375       return false;
376 
377     out.push_back(t);
378   }
379 
380   return true;
381 }
382 
383 /*
384  * Convert a Python list to a set
385  */
386 template <class T>
PConvFromPyObject(PyMOLGlobals * G,PyObject * obj,std::set<T> & out)387 bool PConvFromPyObject(PyMOLGlobals * G, PyObject * obj, std::set<T> &out) {
388   if (!PyList_Check(obj))
389     return false;
390 
391   int n = PyList_Size(obj);
392 
393   out.clear();
394 
395   for (int i = 0; i < n; ++i) {
396     PyObject *item = PyList_GET_ITEM(obj, i);
397 
398     T t;
399     if (!PConvFromPyObject(G, item, t))
400       return false;
401 
402     out.insert(t);
403   }
404 
405   return true;
406 }
407 
408 /*
409  * Convert a flat Python list to a map, even indices are keys and odd
410  * indices are values.
411  *
412  * [a, b, c, d, ...] -> {a: b, c: d, ...}
413  */
414 template <class K, class V>
PConvFromPyObject(PyMOLGlobals * G,PyObject * obj,std::map<K,V> & out)415 bool PConvFromPyObject(PyMOLGlobals * G, PyObject * obj, std::map<K, V> &out) {
416   if (!PyList_Check(obj))
417     return false;
418 
419   int n = PyList_Size(obj);
420 
421   out.clear();
422 
423   for (int i = 0; i < n - 1;) {
424     PyObject *key   = PyList_GET_ITEM(obj, i++);
425     PyObject *value = PyList_GET_ITEM(obj, i++);
426 
427     K k;
428     if (!PConvFromPyObject(G, key, k))
429       return false;
430 
431     if (!PConvFromPyObject(G, value, out[k]))
432       return false;
433   }
434 
435   return true;
436 }
437 
438 /* ============================================================ */
439 
440 template <class T>
PConvFromPyListItem(PyMOLGlobals * G,PyObject * list,size_t i,T & out)441 bool PConvFromPyListItem(PyMOLGlobals* G, PyObject* list, size_t i, T& out)
442 {
443   auto item = PyList_GetItem(list, i);
444   auto ok = PConvFromPyObject(G, item, out);
445   CPythonVal_Free(item);
446   return ok;
447 }
448 
449 #endif
450