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 #define IS_SHARED_PTR_DWA2003224_HPP
56 
57 #include <boost/python/detail/is_xxx.hpp>
58 #include <boost/shared_ptr.hpp>
59 
60 namespace boost { namespace python { namespace detail {
61 
62 BOOST_PYTHON_IS_XXX_DEF(shared_ptr, shared_ptr, 1)
63 template <typename T>
64 struct is_shared_ptr<std::shared_ptr<T> > : std::true_type {};
65 
66 }}} // namespace boost::python::detail
67 
68 //
69 // From <boost/python/converter/registered.hpp>
70 //
71 
72 #include <boost/python/type_id.hpp>
73 #include <boost/python/converter/registry.hpp>
74 #include <boost/python/converter/registrations.hpp>
75 #include <boost/type_traits/transform_traits.hpp>
76 #include <boost/type_traits/cv_traits.hpp>
77 #include <boost/type_traits/is_void.hpp>
78 #include <boost/detail/workaround.hpp>
79 #include <boost/type.hpp>
80 #include <memory>
81 
82 namespace boost { namespace python { namespace converter { namespace detail {
83 
84 template <class T>
85 inline void
86 register_shared_ptr0(std::shared_ptr<T>*)
87 {
88  registry::lookup_shared_ptr(type_id<std::shared_ptr<T> >());
89 }
90 
91 }}}}
92 
93 // From <boost/python/detail/value_is_shared_ptr.hpp>
94 
95 #define VALUE_IS_SHARED_PTR_DWA2003224_HPP
96 #include <boost/python/detail/value_is_xxx.hpp>
97 #include <boost/python/detail/is_shared_ptr.hpp>
98 
99 namespace boost { namespace python { namespace detail {
100 
101 template <class X_>
103 {
104  static bool const value = is_shared_ptr<typename remove_cv<
105  typename remove_reference<X_>
106  ::type>
107  ::type>
108  ::value;
109  typedef mpl::bool_<value> type;
110 };
111 
112 }}} // namespace boost::python::detail
113 
114 //
115 // From <boost/python/converter/shared_ptr_from_python.hpp>
116 //
117 
118 #define SHARED_PTR_FROM_PYTHON_DWA20021130_HPP
119 
120 #include <boost/python/handle.hpp>
121 #include <boost/python/converter/shared_ptr_deleter.hpp>
122 #include <boost/python/converter/from_python.hpp>
123 #include <boost/python/converter/rvalue_from_python_data.hpp>
124 #include <boost/python/converter/registered.hpp>
125 #ifndef BOOST_PYTHON_NO_PY_SIGNATURES
126 # include <boost/python/converter/pytype_function.hpp>
127 #endif
128 #include <boost/shared_ptr.hpp>
129 
130 namespace boost { namespace python { namespace converter {
131 
132 template <class T, template <typename> class SP>
134 {
136  {
137  converter::registry::insert(&convertible, &construct, type_id<SP<T> >()
138 #ifndef BOOST_PYTHON_NO_PY_SIGNATURES
139  , &converter::expected_from_python_type_direct<T>::get_pytype
140 #endif
141  );
142  }
143 
144  private:
145  static void* convertible(PyObject* p)
146  {
147  if (p == Py_None)
148  return p;
149 
150  return converter::get_lvalue_from_python(p, registered<T>::converters);
151  }
152 
153  static void construct(PyObject* source, rvalue_from_python_stage1_data* data)
154  {
155  void* const storage = ((converter::rvalue_from_python_storage<SP<T> >*)data)->storage.bytes;
156  // Deal with the "None" case.
157  if (data->convertible == source)
158  new (storage) SP<T>();
159  else
160  {
161  SP<void> hold_convertible_ref_count(
162  (void*)0, shared_ptr_deleter(handle<>(borrowed(source))) );
163  // use aliasing constructor
164  new (storage) SP<T>(hold_convertible_ref_count,
165  static_cast<T*>(data->convertible));
166  }
167 
168  data->convertible = storage;
169  }
170 };
171 
172 // DM: Define original shared_ptr_from_python struct so that we can
173 // avoid changes to class_metadata.hpp.
174 template <class T>
176 {
178  {
181  }
182 };
183 
184 
185 
186 }}} // namespace boost::python::converter
187 
188 
189 //
190 // From <boost/python/converter/shared_ptr_to_python.hpp>
191 //
192 
193 #include <boost/python/refcount.hpp>
194 #include <boost/python/converter/shared_ptr_deleter.hpp>
195 #include <boost/python/detail/none.hpp>
196 #include <boost/get_pointer.hpp>
197 
198 namespace boost { namespace python { namespace converter {
199 
200 template <class T>
201 PyObject* shared_ptr_to_python(std::shared_ptr<T> const& x)
202 {
203  if (!x)
204  return python::detail::none();
205  else if (shared_ptr_deleter* d = std::get_deleter<shared_ptr_deleter>(x))
206  return incref(get_pointer(d->owner));
207  else
208  return converter::registered<std::shared_ptr<T> const&>::converters.to_python(&x);
209 }
210 
211 }}} // namespace boost::python::converter
212 
213 //
214 // From <boost/python/to_python_value.hpp>: this is a pretty big hack, but
215 // needs to be fully included due to the definition of new private member
216 // variables.
217 //
218 
219 #define TO_PYTHON_VALUE_DWA200221_HPP
220 #include <boost/python/detail/prefix.hpp>
221 
222 #include <boost/python/refcount.hpp>
223 #include <boost/python/tag.hpp>
224 #include <boost/python/handle.hpp>
225 
226 #include <boost/python/converter/registry.hpp>
227 #include <boost/python/converter/registered.hpp>
228 #include <boost/python/converter/builtin_converters.hpp>
229 #include <boost/python/converter/object_manager.hpp>
230 #include <boost/python/converter/shared_ptr_to_python.hpp>
231 
232 #include <boost/python/detail/value_is_shared_ptr.hpp>
233 #include <boost/python/detail/value_arg.hpp>
234 
235 #include <boost/type_traits/transform_traits.hpp>
236 
237 #include <boost/mpl/if.hpp>
238 #include <boost/mpl/or.hpp>
239 #include <boost/type_traits/is_const.hpp>
240 
241 namespace boost { namespace python {
242 
243 namespace detail
244 {
245 #ifndef BOOST_PYTHON_NO_PY_SIGNATURES
246 
247 template <bool is_const_ref>
249 {
250  template <class U>
251  static PyTypeObject const* get( U& (*)() =0)
252  {
253  return converter::object_manager_traits<U>::get_pytype();
254  }
255 };
256 
257 template <>
259 {
260  template <class U>
261  static PyTypeObject const* get( U const& (*)() =0)
262  {
263  return converter::object_manager_traits<U>::get_pytype();
264  }
265 };
266 
267 #endif
268 
269  template <class T>
271  {
272  typedef typename value_arg<T>::type argument_type;
273 
274  PyObject* operator()(argument_type) const;
275 #ifndef BOOST_PYTHON_NO_PY_SIGNATURES
276  typedef boost::mpl::bool_<is_handle<T>::value> is_t_handle;
277  typedef boost::detail::indirect_traits::is_reference_to_const<T> is_t_const;
278  PyTypeObject const* get_pytype() const {
279  return get_pytype_aux((is_t_handle*)0);
280  }
281 
282  inline static PyTypeObject const* get_pytype_aux(mpl::true_*) {return converter::object_manager_traits<T>::get_pytype();}
283 
284  inline static PyTypeObject const* get_pytype_aux(mpl::false_* )
285  {
287  }
288 
289 #endif
290 
291  // This information helps make_getter() decide whether to try to
292  // return an internal reference or not. I don't like it much,
293  // but it will have to serve for now.
294  BOOST_STATIC_CONSTANT(bool, uses_registry = false);
295  };
296 
297 
298  template <class T>
300  {
301  typedef typename value_arg<T>::type argument_type;
302 
303  PyObject* operator()(argument_type) const;
304 #ifndef BOOST_PYTHON_NO_PY_SIGNATURES
305  PyTypeObject const* get_pytype() const {return converter::registered<T>::converters.to_python_target_type();}
306 #endif
307 
308  // This information helps make_getter() decide whether to try to
309  // return an internal reference or not. I don't like it much,
310  // but it will have to serve for now.
311  BOOST_STATIC_CONSTANT(bool, uses_registry = true);
312  };
313 
314  template <class T>
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  PyTypeObject const* get_pytype() const {return get_pytype((boost::type<argument_type>*)0);}
322 #endif
323  // This information helps make_getter() decide whether to try to
324  // return an internal reference or not. I don't like it much,
325  // but it will have to serve for now.
326  BOOST_STATIC_CONSTANT(bool, uses_registry = false);
327  private:
328 #ifndef BOOST_PYTHON_NO_PY_SIGNATURES
329  template <class U>
330  PyTypeObject const* get_pytype(boost::type<shared_ptr<U> &> *) const {return converter::registered<U>::converters.to_python_target_type();}
331  template <class U>
332  PyTypeObject const* get_pytype(boost::type<const shared_ptr<U> &> *) const {return converter::registered<U>::converters.to_python_target_type();}
333 # if __cplusplus >= 201103L
334  template <class U>
335  PyTypeObject const* get_pytype(boost::type<std::shared_ptr<U> &> *) const {return converter::registered<U>::converters.to_python_target_type();}
336  template <class U>
337  PyTypeObject const* get_pytype(boost::type<const std::shared_ptr<U> &> *) const {return converter::registered<U>::converters.to_python_target_type();}
338 # endif
339 #endif
340  };
341 }
342 
343 template <class T>
345  : mpl::if_<
346  detail::value_is_shared_ptr<T>
347  , detail::shared_ptr_to_python_value<T>
348  , typename mpl::if_<
349  mpl::or_<
350  converter::is_object_manager<T>
351  , converter::is_reference_to_object_manager<T>
352  >
353  , detail::object_manager_to_python_value<T>
354  , detail::registry_to_python_value<T>
355  >::type
356  >::type
357 {
358 };
359 
360 //
361 // implementation
362 //
363 namespace detail
364 {
365  template <class T>
367  {
368  return converter::registered<argument_type>::converters.to_python(&x);
369  }
370 
371  template <class T>
373  {
374  return python::upcast<PyObject>(
375  python::xincref(
376  get_managed_object(x, tag))
377  );
378  }
379 
380  template <class T>
382  {
384  }
385 }
386 
387 }} // namespace boost::python
388 
389 
void register_shared_ptr0(std::shared_ptr< T > *)
Definition: ShPtrFixes.hpp:86
PyObject * shared_ptr_to_python(std::shared_ptr< T > const &x)
Definition: ShPtrFixes.hpp:201
static void construct(PyObject *source, rvalue_from_python_stage1_data *data)
Definition: ShPtrFixes.hpp:153
static PyTypeObject const * get(U const &(*)()=0)
Definition: ShPtrFixes.hpp:261
static PyTypeObject const * get(U &(*)()=0)
Definition: ShPtrFixes.hpp:251
static PyTypeObject const * get_pytype_aux(mpl::true_ *)
Definition: ShPtrFixes.hpp:282
boost::detail::indirect_traits::is_reference_to_const< T > is_t_const
Definition: ShPtrFixes.hpp:277
boost::mpl::bool_< is_handle< T >::value > is_t_handle
Definition: ShPtrFixes.hpp:276
static PyTypeObject const * get_pytype_aux(mpl::false_ *)
Definition: ShPtrFixes.hpp:284
BOOST_STATIC_CONSTANT(bool, uses_registry=true)
PyObject * operator()(argument_type) const
Definition: ShPtrFixes.hpp:366
PyTypeObject const * get_pytype(boost::type< shared_ptr< U > & > *) const
Definition: ShPtrFixes.hpp:330
PyTypeObject const * get_pytype(boost::type< const shared_ptr< U > & > *) const
Definition: ShPtrFixes.hpp:332
PyObject * operator()(argument_type) const
Definition: ShPtrFixes.hpp:381
BOOST_STATIC_CONSTANT(bool, uses_registry=false)