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