Nektar++
ShPtrFixes.hpp
Go to the documentation of this file.
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 // File: ShPtrFixes.hpp
4 //
5 // For more information, please see: http://www.nektar.info
6 //
7 // The MIT License
8 //
9 // Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
10 // Department of Aeronautics, Imperial College London (UK), and Scientific
11 // Computing and Imaging Institute, University of Utah (USA).
12 //
13 // Original code from Boost (c) David Abrahams 2002, Stefan Seefeld 2016.
14 //
15 // Permission is hereby granted, free of charge, to any person obtaining a
16 // copy of this software and associated documentation files (the "Software"),
17 // to deal in the Software without restriction, including without limitation
18 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
19 // and/or sell copies of the Software, and to permit persons to whom the
20 // Software is furnished to do so, subject to the following conditions:
21 //
22 // The above copyright notice and this permission notice shall be included
23 // in all copies or substantial portions of the Software.
24 //
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
26 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
28 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
30 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
31 // DEALINGS IN THE SOFTWARE.
32 //
33 // Description: Patches for boost.python to support std::shared_ptr for boost
34 // versions < 1.63.
35 //
36 ///////////////////////////////////////////////////////////////////////////////
37 
38 /*
39  * This file is an unpleasant series of includes from boost.python which is
40  * designed to support std::shared_ptr on versions of boost lower than 1.63
41  * (where support was first introduced). This file overrides or augments
42  * various headers from the release to enable this.
43  *
44  * Although one can mostly handle std::shared_ptr with the use of the
45  * py::implicitly_convertible, in some cases the allocation/deallocation process
46  * seems to lead to memory issues. This file therefore takes the patch made in
47  * boost python changeset 97e4b34a159 which enables this. This is a pretty ugly
48  * approach, but various other strategies did not seem to work!
49  */
50 
51 //
52 // From <boost/python/detail/is_shared_ptr.hpp>
53 //
54 
55 // clang-format off
56 #define IS_SHARED_PTR_DWA2003224_HPP
57 
58 #include <boost/python/detail/is_xxx.hpp>
59 #include <boost/shared_ptr.hpp>
60 // clang-format on
61 
62 namespace boost
63 {
64 namespace python
65 {
66 namespace detail
67 {
68 
69 BOOST_PYTHON_IS_XXX_DEF(shared_ptr, shared_ptr, 1)
70 template <typename T> struct is_shared_ptr<std::shared_ptr<T>> : std::true_type
71 {
72 };
73 
74 } // namespace detail
75 } // namespace python
76 } // namespace boost
77 
78 //
79 // From <boost/python/converter/registered.hpp>
80 //
81 
82 // clang-format off
83 #include <boost/python/type_id.hpp>
84 #include <boost/python/converter/registry.hpp>
85 #include <boost/python/converter/registrations.hpp>
86 #include <boost/type_traits/transform_traits.hpp>
87 
88 #include <boost/type_traits/cv_traits.hpp>
89 #include <boost/type_traits/is_void.hpp>
90 #include <boost/detail/workaround.hpp>
91 #include <boost/type.hpp>
92 #include <memory>
93 // clang-format on
94 
95 namespace boost
96 {
97 namespace python
98 {
99 namespace converter
100 {
101 namespace detail
102 {
103 
104 template <class T> inline void register_shared_ptr0(std::shared_ptr<T> *)
105 {
106  registry::lookup_shared_ptr(type_id<std::shared_ptr<T>>());
107 }
108 
109 } // namespace detail
110 } // namespace converter
111 } // namespace python
112 } // namespace boost
113 
114 // From <boost/python/detail/value_is_shared_ptr.hpp>
115 
116 // clang-format off
117 #define VALUE_IS_SHARED_PTR_DWA2003224_HPP
118 #include <boost/python/detail/value_is_xxx.hpp>
119 #include <boost/python/detail/is_shared_ptr.hpp>
120 // clang-format on
121 
122 namespace boost
123 {
124 namespace python
125 {
126 namespace detail
127 {
128 
129 template <class X_> struct value_is_shared_ptr
130 {
131  static bool const value = is_shared_ptr<
132  typename remove_cv<typename remove_reference<X_>::type>::type>::value;
133  typedef mpl::bool_<value> type;
134 };
135 
136 } // namespace detail
137 } // namespace python
138 } // namespace boost
139 
140 //
141 // From <boost/python/converter/shared_ptr_from_python.hpp>
142 //
143 
144 // clang-format off
145 #define SHARED_PTR_FROM_PYTHON_DWA20021130_HPP
146 
147 #include <boost/python/handle.hpp>
148 #include <boost/python/converter/shared_ptr_deleter.hpp>
149 #include <boost/python/converter/from_python.hpp>
150 #include <boost/python/converter/rvalue_from_python_data.hpp>
151 #include <boost/python/converter/registered.hpp>
152 #ifndef BOOST_PYTHON_NO_PY_SIGNATURES
153 #include <boost/python/converter/pytype_function.hpp>
154 #endif
155 #include <boost/shared_ptr.hpp>
156 // clang-format on
157 
158 namespace boost
159 {
160 namespace python
161 {
162 namespace converter
163 {
164 
165 template <class T, template <typename> class SP>
167 {
169  {
170  converter::registry::insert(
171  &convertible, &construct, type_id<SP<T>>()
172 #ifndef BOOST_PYTHON_NO_PY_SIGNATURES
173  ,
174  &converter::expected_from_python_type_direct<T>::get_pytype
175 #endif
176  );
177  }
178 
179 private:
180  static void *convertible(PyObject *p)
181  {
182  if (p == Py_None)
183  return p;
184 
185  return converter::get_lvalue_from_python(p, registered<T>::converters);
186  }
187 
188  static void construct(PyObject *source,
189  rvalue_from_python_stage1_data *data)
190  {
191  void *const storage =
192  ((converter::rvalue_from_python_storage<SP<T>> *)data)
193  ->storage.bytes;
194  // Deal with the "None" case.
195  if (data->convertible == source)
196  new (storage) SP<T>();
197  else
198  {
199  SP<void> hold_convertible_ref_count(
200  (void *)0, shared_ptr_deleter(handle<>(borrowed(source))));
201  // use aliasing constructor
202  new (storage) SP<T>(hold_convertible_ref_count,
203  static_cast<T *>(data->convertible));
204  }
205 
206  data->convertible = storage;
207  }
208 };
209 
210 // DM: Define original shared_ptr_from_python struct so that we can
211 // avoid changes to class_metadata.hpp.
212 template <class T> struct shared_ptr_from_python
213 {
215  {
218  }
219 };
220 
221 } // namespace converter
222 } // namespace python
223 } // namespace boost
224 
225 //
226 // From <boost/python/converter/shared_ptr_to_python.hpp>
227 //
228 
229 // clang-format off
230 #include <boost/python/refcount.hpp>
231 #include <boost/python/converter/shared_ptr_deleter.hpp>
232 #include <boost/python/detail/none.hpp>
233 #include <boost/get_pointer.hpp>
234 // clang-format on
235 
236 namespace boost
237 {
238 namespace python
239 {
240 namespace converter
241 {
242 
243 template <class T> PyObject *shared_ptr_to_python(std::shared_ptr<T> const &x)
244 {
245  if (!x)
246  return python::detail::none();
247  else if (shared_ptr_deleter *d = std::get_deleter<shared_ptr_deleter>(x))
248  return incref(get_pointer(d->owner));
249  else
250  return converter::registered<std::shared_ptr<T> const &>::converters
251  .to_python(&x);
252 }
253 
254 } // namespace converter
255 } // namespace python
256 } // namespace boost
257 
258 //
259 // From <boost/python/to_python_value.hpp>: this is a pretty big hack, but
260 // needs to be fully included due to the definition of new private member
261 // variables.
262 //
263 
264 // clang-format off
265 #define TO_PYTHON_VALUE_DWA200221_HPP
266 #include <boost/python/detail/prefix.hpp>
267 
268 #include <boost/python/refcount.hpp>
269 #include <boost/python/tag.hpp>
270 #include <boost/python/handle.hpp>
271 
272 #include <boost/python/converter/registry.hpp>
273 #include <boost/python/converter/registered.hpp>
274 #include <boost/python/converter/builtin_converters.hpp>
275 #include <boost/python/converter/object_manager.hpp>
276 #include <boost/python/converter/shared_ptr_to_python.hpp>
277 
278 #include <boost/python/detail/value_is_shared_ptr.hpp>
279 #include <boost/python/detail/value_arg.hpp>
280 
281 #include <boost/type_traits/transform_traits.hpp>
282 
283 #include <boost/mpl/if.hpp>
284 #include <boost/mpl/or.hpp>
285 #include <boost/type_traits/is_const.hpp>
286 // clang-format on
287 
288 namespace boost
289 {
290 namespace python
291 {
292 
293 namespace detail
294 {
295 #ifndef BOOST_PYTHON_NO_PY_SIGNATURES
296 
297 template <bool is_const_ref> struct object_manager_get_pytype
298 {
299  template <class U> static PyTypeObject const *get(U &(*)() = 0)
300  {
301  return converter::object_manager_traits<U>::get_pytype();
302  }
303 };
304 
305 template <> struct object_manager_get_pytype<true>
306 {
307  template <class U> static PyTypeObject const *get(U const &(*)() = 0)
308  {
309  return converter::object_manager_traits<U>::get_pytype();
310  }
311 };
312 
313 #endif
314 
315 template <class T> struct object_manager_to_python_value
316 {
317  typedef typename value_arg<T>::type argument_type;
318 
319  PyObject *operator()(argument_type) const;
320 #ifndef BOOST_PYTHON_NO_PY_SIGNATURES
321  typedef boost::mpl::bool_<is_handle<T>::value> is_t_handle;
322  typedef boost::detail::indirect_traits::is_reference_to_const<T> is_t_const;
323  PyTypeObject const *get_pytype() const
324  {
325  return get_pytype_aux((is_t_handle *)0);
326  }
327 
328  inline static PyTypeObject const *get_pytype_aux(mpl::true_ *)
329  {
330  return converter::object_manager_traits<T>::get_pytype();
331  }
332 
333  inline static PyTypeObject const *get_pytype_aux(mpl::false_ *)
334  {
336  }
337 
338 #endif
339 
340  // This information helps make_getter() decide whether to try to
341  // return an internal reference or not. I don't like it much,
342  // but it will have to serve for now.
343  BOOST_STATIC_CONSTANT(bool, uses_registry = false);
344 };
345 
346 template <class T> struct registry_to_python_value
347 {
348  typedef typename value_arg<T>::type argument_type;
349 
350  PyObject *operator()(argument_type) const;
351 #ifndef BOOST_PYTHON_NO_PY_SIGNATURES
352  PyTypeObject const *get_pytype() const
353  {
354  return converter::registered<T>::converters.to_python_target_type();
355  }
356 #endif
357 
358  // This information helps make_getter() decide whether to try to
359  // return an internal reference or not. I don't like it much,
360  // but it will have to serve for now.
361  BOOST_STATIC_CONSTANT(bool, uses_registry = true);
362 };
363 
364 template <class T> struct shared_ptr_to_python_value
365 {
366  typedef typename value_arg<T>::type argument_type;
367 
368  PyObject *operator()(argument_type) const;
369 #ifndef BOOST_PYTHON_NO_PY_SIGNATURES
370  PyTypeObject const *get_pytype() const
371  {
372  return get_pytype((boost::type<argument_type> *)0);
373  }
374 #endif
375  // This information helps make_getter() decide whether to try to
376  // return an internal reference or not. I don't like it much,
377  // but it will have to serve for now.
378  BOOST_STATIC_CONSTANT(bool, uses_registry = false);
379 
380 private:
381 #ifndef BOOST_PYTHON_NO_PY_SIGNATURES
382  template <class U>
383  PyTypeObject const *get_pytype(boost::type<shared_ptr<U> &> *) const
384  {
385  return converter::registered<U>::converters.to_python_target_type();
386  }
387  template <class U>
388  PyTypeObject const *get_pytype(boost::type<const shared_ptr<U> &> *) const
389  {
390  return converter::registered<U>::converters.to_python_target_type();
391  }
392 #if __cplusplus >= 201103L
393  template <class U>
394  PyTypeObject const *get_pytype(boost::type<std::shared_ptr<U> &> *) const
395  {
396  return converter::registered<U>::converters.to_python_target_type();
397  }
398  template <class U>
399  PyTypeObject const *get_pytype(
400  boost::type<const std::shared_ptr<U> &> *) const
401  {
402  return converter::registered<U>::converters.to_python_target_type();
403  }
404 #endif
405 #endif
406 };
407 } // namespace detail
408 
409 template <class T>
411  : mpl::if_<detail::value_is_shared_ptr<T>,
412  detail::shared_ptr_to_python_value<T>,
413  typename mpl::if_<
414  mpl::or_<converter::is_object_manager<T>,
415  converter::is_reference_to_object_manager<T>>,
416  detail::object_manager_to_python_value<T>,
417  detail::registry_to_python_value<T>>::type>::type
418 {
419 };
420 
421 //
422 // implementation
423 //
424 namespace detail
425 {
426 template <class T>
428 {
429  return converter::registered<argument_type>::converters.to_python(&x);
430 }
431 
432 template <class T>
434  argument_type x) const
435 {
436  return python::upcast<PyObject>(
437  python::xincref(get_managed_object(x, tag)));
438 }
439 
440 template <class T>
442  argument_type x) const
443 {
445 }
446 } // namespace detail
447 
448 } // namespace python
449 } // namespace boost
void register_shared_ptr0(std::shared_ptr< T > *)
Definition: ShPtrFixes.hpp:104
PyObject * shared_ptr_to_python(std::shared_ptr< T > const &x)
Definition: ShPtrFixes.hpp:243
static void construct(PyObject *source, rvalue_from_python_stage1_data *data)
Definition: ShPtrFixes.hpp:188
static PyTypeObject const * get(U const &(*)()=0)
Definition: ShPtrFixes.hpp:307
static PyTypeObject const * get(U &(*)()=0)
Definition: ShPtrFixes.hpp:299
static PyTypeObject const * get_pytype_aux(mpl::true_ *)
Definition: ShPtrFixes.hpp:328
boost::detail::indirect_traits::is_reference_to_const< T > is_t_const
Definition: ShPtrFixes.hpp:322
boost::mpl::bool_< is_handle< T >::value > is_t_handle
Definition: ShPtrFixes.hpp:321
static PyTypeObject const * get_pytype_aux(mpl::false_ *)
Definition: ShPtrFixes.hpp:333
BOOST_STATIC_CONSTANT(bool, uses_registry=true)
PyObject * operator()(argument_type) const
Definition: ShPtrFixes.hpp:427
PyTypeObject const * get_pytype(boost::type< shared_ptr< U > & > *) const
Definition: ShPtrFixes.hpp:383
PyTypeObject const * get_pytype(boost::type< const shared_ptr< U > & > *) const
Definition: ShPtrFixes.hpp:388
PyObject * operator()(argument_type) const
Definition: ShPtrFixes.hpp:441
BOOST_STATIC_CONSTANT(bool, uses_registry=false)