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
62namespace boost
63{
64namespace python
65{
66namespace detail
67{
68
69BOOST_PYTHON_IS_XXX_DEF(shared_ptr, shared_ptr, 1)
70template <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
95namespace boost
96{
97namespace python
98{
99namespace converter
100{
101namespace detail
102{
103
104template <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
122namespace boost
123{
124namespace python
125{
126namespace detail
127{
128
129template <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
158namespace boost
159{
160namespace python
161{
162namespace converter
163{
164
165template <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
179private:
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.
212template <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
236namespace boost
237{
238namespace python
239{
240namespace converter
241{
242
243template <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
288namespace boost
289{
290namespace python
291{
292
293namespace detail
294{
295#ifndef BOOST_PYTHON_NO_PY_SIGNATURES
296
297template <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
305template <> 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
315template <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
346template <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
364template <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
380private:
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
409template <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//
424namespace detail
425{
426template <class T>
428{
429 return converter::registered<argument_type>::converters.to_python(&x);
430}
431
432template <class T>
434 argument_type x) const
435{
436 return python::upcast<PyObject>(
437 python::xincref(get_managed_object(x, tag)));
438}
439
440template <class T>
442 argument_type x) const
443{
445}
446} // namespace detail
447
448} // namespace python
449} // namespace boost
std::vector< double > d(NPUPPER *NPUPPER)
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
STL namespace.
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
boost::detail::indirect_traits::is_reference_to_const< T > is_t_const
Definition: ShPtrFixes.hpp:322
static PyTypeObject const * get_pytype_aux(mpl::false_ *)
Definition: ShPtrFixes.hpp:333
boost::mpl::bool_< is_handle< T >::value > is_t_handle
Definition: ShPtrFixes.hpp:321
static PyTypeObject const * get_pytype_aux(mpl::true_ *)
Definition: ShPtrFixes.hpp:328
BOOST_STATIC_CONSTANT(bool, uses_registry=true)
PyObject * operator()(argument_type) const
Definition: ShPtrFixes.hpp:427
PyTypeObject const * get_pytype(boost::type< const shared_ptr< U > & > *) const
Definition: ShPtrFixes.hpp:388
PyTypeObject const * get_pytype(boost::type< shared_ptr< U > & > *) const
Definition: ShPtrFixes.hpp:383
PyObject * operator()(argument_type) const
Definition: ShPtrFixes.hpp:441
BOOST_STATIC_CONSTANT(bool, uses_registry=false)
Template type to determine whether.