with_custodian_and_ward.hpp 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. // Copyright David Abrahams 2002.
  2. // Distributed under the Boost Software License, Version 1.0. (See
  3. // accompanying file LICENSE_1_0.txt or copy at
  4. // http://www.boost.org/LICENSE_1_0.txt)
  5. #ifndef WITH_CUSTODIAN_AND_WARD_DWA2002131_HPP
  6. # define WITH_CUSTODIAN_AND_WARD_DWA2002131_HPP
  7. # include <boost/python/detail/prefix.hpp>
  8. # include <boost/python/default_call_policies.hpp>
  9. # include <boost/python/object/life_support.hpp>
  10. # include <algorithm>
  11. namespace boost { namespace python {
  12. namespace detail
  13. {
  14. template <std::size_t N>
  15. struct get_prev
  16. {
  17. template <class ArgumentPackage>
  18. static PyObject* execute(ArgumentPackage const& args, PyObject* = 0)
  19. {
  20. int const pre_n = static_cast<int>(N) - 1; // separate line is gcc-2.96 workaround
  21. return detail::get(mpl::int_<pre_n>(), args);
  22. }
  23. };
  24. template <>
  25. struct get_prev<0>
  26. {
  27. template <class ArgumentPackage>
  28. static PyObject* execute(ArgumentPackage const&, PyObject* zeroth)
  29. {
  30. return zeroth;
  31. }
  32. };
  33. }
  34. template <
  35. std::size_t custodian
  36. , std::size_t ward
  37. , class BasePolicy_ = default_call_policies
  38. >
  39. struct with_custodian_and_ward : BasePolicy_
  40. {
  41. BOOST_STATIC_ASSERT(custodian != ward);
  42. BOOST_STATIC_ASSERT(custodian > 0);
  43. BOOST_STATIC_ASSERT(ward > 0);
  44. template <class ArgumentPackage>
  45. static bool precall(ArgumentPackage const& args_)
  46. {
  47. unsigned arity_ = detail::arity(args_);
  48. if (custodian > arity_ || ward > arity_)
  49. {
  50. PyErr_SetString(
  51. PyExc_IndexError
  52. , "boost::python::with_custodian_and_ward: argument index out of range"
  53. );
  54. return false;
  55. }
  56. PyObject* patient = detail::get_prev<ward>::execute(args_);
  57. PyObject* nurse = detail::get_prev<custodian>::execute(args_);
  58. PyObject* life_support = python::objects::make_nurse_and_patient(nurse, patient);
  59. if (life_support == 0)
  60. return false;
  61. bool result = BasePolicy_::precall(args_);
  62. if (!result) {
  63. Py_DECREF(life_support);
  64. }
  65. return result;
  66. }
  67. };
  68. template <std::size_t custodian, std::size_t ward, class BasePolicy_ = default_call_policies>
  69. struct with_custodian_and_ward_postcall : BasePolicy_
  70. {
  71. BOOST_STATIC_ASSERT(custodian != ward);
  72. template <class ArgumentPackage>
  73. static PyObject* postcall(ArgumentPackage const& args_, PyObject* result)
  74. {
  75. std::size_t arity_ = detail::arity(args_);
  76. #if BOOST_WORKAROUND(BOOST_MSVC, < 1300)
  77. if ( custodian > arity_ || ward > arity_ )
  78. #else
  79. // check if either custodian or ward exceeds the arity
  80. // (this weird formulation avoids "always false" warnings
  81. // for arity_ = 0)
  82. if ( (std::max)(custodian, ward) > arity_ )
  83. #endif
  84. {
  85. PyErr_SetString(
  86. PyExc_IndexError
  87. , "boost::python::with_custodian_and_ward_postcall: argument index out of range"
  88. );
  89. return 0;
  90. }
  91. PyObject* patient = detail::get_prev<ward>::execute(args_, result);
  92. PyObject* nurse = detail::get_prev<custodian>::execute(args_, result);
  93. if (nurse == 0) return 0;
  94. result = BasePolicy_::postcall(args_, result);
  95. if (result == 0)
  96. return 0;
  97. if (python::objects::make_nurse_and_patient(nurse, patient) == 0)
  98. {
  99. Py_XDECREF(result);
  100. return 0;
  101. }
  102. return result;
  103. }
  104. };
  105. }} // namespace boost::python
  106. #endif // WITH_CUSTODIAN_AND_WARD_DWA2002131_HPP