HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PyImathUtil.h
Go to the documentation of this file.
1 //
2 // SPDX-License-Identifier: BSD-3-Clause
3 // Copyright Contributors to the OpenEXR Project.
4 //
5 
6 // clang-format off
7 
8 #ifndef INCLUDED_PYIMATHUTIL_H
9 #define INCLUDED_PYIMATHUTIL_H
10 
11 //----------------------------------------------------------------------------
12 //
13 // PyImathUtil.h -- miscellaneous classes, functions
14 // and macros that are useful for Python wrapping
15 // of C++ objects.
16 //
17 //----------------------------------------------------------------------------
18 
19 #include <Python.h>
20 #include "PyImathExport.h"
21 #include <PyImathAPI.h>
22 
23 namespace PyImath {
24 
25 
26 /**
27  * PyAcquireLock ensures that python is prepared for multi-threaded use and
28  * ensures that this thread has the global lock.
29  *
30  * This object must be instantiated (and continue to be in scope) during all
31  * threaded api calls. It assumes the python interpretter is instantiated and
32  * multithreading is enabled.
33  *
34  * Note: this is not compatible with additional interpreters (calls to
35  * Py_NewInterpreter());
36  */
38 {
39  public:
42 
43  PyAcquireLock(const PyAcquireLock& other) = delete;
44  PyAcquireLock & operator = (PyAcquireLock& other) = delete;
45  PyAcquireLock(PyAcquireLock&& other) = delete;
46  PyAcquireLock & operator = (PyAcquireLock&& other) = delete;
47 
48  private:
49  PyGILState_STATE _gstate;
50 };
51 
52 
53 /**
54  * This object causes the python global lock to be released for the duration
55  * of it's existence.
56  *
57  * This object should be instantiated (and continue to be in scope) in thread-
58  * safe c++ functions called from python. This call is designed to be
59  * instantiated while an AcquireLock is in effect (nested).
60  *
61  */
63 {
64  public:
67  PyReleaseLock(const PyReleaseLock& other) = delete;
68  PyReleaseLock & operator = (PyReleaseLock& other) = delete;
69  PyReleaseLock(PyReleaseLock&& other) = delete;
70  PyReleaseLock & operator = (PyReleaseLock&& other) = delete;
71 
72  private:
73  PyThreadState *_save;
74 
75 };
76 
77 /**
78  * This object is safe object wrapper intended to use with hboost python objects.
79  *
80  * This object correctly acquires the python lock for creation, copying and
81  * desctruction of the given object.
82  *
83  */
84 template <class T>
86 {
87  public:
89  : _object(0)
90  {
91  PyAcquireLock pylock;
92  _object = new T();
93  }
94 
95  PySafeObject(const T &value)
96  : _object(0)
97  {
98  PyAcquireLock pylock;
99  _object = new T(value);
100  }
101 
103  {
104  PyAcquireLock pylock;
105  delete _object;
106  _object = 0;
107  }
108 
110  : _object(0)
111  {
112  PyAcquireLock pylock;
113  _object = new T(*other._object);
114  }
115 
116  const PySafeObject &
117  operator = (const PySafeObject &other)
118  {
119  if (&other == this) return *this;
120  PyAcquireLock pylock;
121  *_object = *other._object;
122  return *this;
123  }
124 
125  bool
126  operator == (const PySafeObject &other) const
127  {
128  if (&other == this) return true;
129  PyAcquireLock pylock;
130  return *_object == *other._object;
131  }
132 
133  bool
134  operator != (const PySafeObject &other) const
135  {
136  if (&other == this) return false;
137  PyAcquireLock pylock;
138  return *_object != *other._object;
139  }
140 
141  T & get() { return *_object; }
142  const T & get() const { return *_object; }
143 
144  private:
145 
146  T *_object;
147 };
148 
149 /**
150  * A special selectable postcall policy used in python wrappings.
151  *
152  * It expects the initial result to be a touple where the first
153  * object represents an integer value 0, 1, 2 which corresponds
154  * to which of the templated call polices should be applied.
155  *
156  * This postcall policy is modeled after a similar one defined
157  * in PyGeomParticleUtil.h of the PyGeomParticle project.
158  *
159  */
160 template <class policy0, class policy1, class policy2>
162 {
163  static PyObject *
164  postcall (PyObject* args, PyObject* result)
165  {
166  if (!PyTuple_Check (result))
167  {
168  PyErr_SetString (PyExc_TypeError,
169  "selectable_postcall: retval was not a tuple");
170  return 0;
171  }
172  if (PyTuple_Size(result) != 2)
173  {
174  PyErr_SetString (PyExc_IndexError,
175  "selectable_postcall: retval was not a tuple of length 2");
176  return 0;
177  }
178 
179  // borrowed references within the tuple
180  PyObject* object0 = PyTuple_GetItem (result, 0); // 'Choice' integer
181  PyObject* object1 = PyTuple_GetItem (result, 1); // The actual object
182 
183  if (!PyInt_Check (object0))
184  {
185  PyErr_SetString (PyExc_TypeError,
186  "selectable_postcall: tuple item 0 was not an integer choice");
187  return 0;
188  }
189 
190  const long usePolicy = PyInt_AsLong (object0);
191 
192  // ensure correct reference count for returned object and decref the tuple
193  Py_INCREF (object1);
194  Py_DECREF (result );
195 
196  if (usePolicy <= 0)
197  return policy0::postcall (args, object1);
198  else if (usePolicy == 1)
199  return policy1::postcall (args, object1);
200  else // usePolicy >= 2
201  return policy2::postcall (args, object1);
202  }
203 };
204 
205 } // namespace PyImath
206 
207 #endif
PYIMATH_EXPORT ~PyReleaseLock()
PYIMATH_EXPORT PyReleaseLock()
bool operator==(const PySafeObject &other) const
Definition: PyImathUtil.h:126
GLsizei const GLfloat * value
Definition: glcorearb.h:824
PySafeObject(const T &value)
Definition: PyImathUtil.h:95
**But if you need a result
Definition: thread.h:622
PYIMATH_EXPORT PyAcquireLock()
#define PYIMATH_EXPORT
Definition: PyImathExport.h:25
PyAcquireLock & operator=(PyAcquireLock &other)=delete
bool operator!=(const PySafeObject &other) const
Definition: PyImathUtil.h:134
PYIMATH_EXPORT ~PyAcquireLock()
const PySafeObject & operator=(const PySafeObject &other)
Definition: PyImathUtil.h:117
static PyObject * postcall(PyObject *args, PyObject *result)
Definition: PyImathUtil.h:164
PySafeObject(const PySafeObject &other)
Definition: PyImathUtil.h:109
**If you just want to fire and args
Definition: thread.h:618
PyReleaseLock & operator=(PyReleaseLock &other)=delete