|
10 | 10 | #pragma once
|
11 | 11 |
|
12 | 12 | #include "detail/common.h"
|
| 13 | +#include "detail/typeid.h" |
13 | 14 | #include "buffer_info.h"
|
14 | 15 | #include <utility>
|
15 | 16 | #include <type_traits>
|
@@ -1091,23 +1092,36 @@ class bool_ : public object {
|
1091 | 1092 | };
|
1092 | 1093 |
|
1093 | 1094 | PYBIND11_NAMESPACE_BEGIN(detail)
|
| 1095 | +template <typename T> |
| 1096 | +using py_signed_int_type_for = conditional_t<sizeof(T) <= sizeof(long), long, long long>; |
| 1097 | + |
| 1098 | +template <typename T> |
| 1099 | +using py_unsigned_int_type_for = typename std::make_unsigned<py_signed_int_type_for<T>>::type; |
| 1100 | + |
| 1101 | +template <typename T> |
| 1102 | +using py_int_type_for = conditional_t<std::is_signed<T>::value, py_signed_int_type_for<T>, py_unsigned_int_type_for<T>>; |
| 1103 | + |
1094 | 1104 | // Converts a value to the given unsigned type. If an error occurs, you get back (Unsigned) -1;
|
1095 | 1105 | // otherwise you get back the unsigned long or unsigned long long value cast to (Unsigned).
|
1096 | 1106 | // (The distinction is critically important when casting a returned -1 error value to some other
|
1097 | 1107 | // unsigned type: (A)-1 != (B)-1 when A and B are unsigned types of different sizes).
|
1098 | 1108 | template <typename Unsigned>
|
1099 | 1109 | Unsigned as_unsigned(PyObject *o) {
|
1100 |
| - if (sizeof(Unsigned) <= sizeof(unsigned long) |
1101 |
| -#if PY_VERSION_HEX < 0x03000000 |
1102 |
| - || PyInt_Check(o) |
1103 |
| -#endif |
1104 |
| - ) { |
1105 |
| - unsigned long v = PyLong_AsUnsignedLong(o); |
1106 |
| - return v == (unsigned long) -1 && PyErr_Occurred() ? (Unsigned) -1 : (Unsigned) v; |
| 1110 | + py_unsigned_int_type_for<Unsigned> v = (sizeof(Unsigned) <= sizeof(unsigned long)) |
| 1111 | + ? PyLong_AsUnsignedLong(o) |
| 1112 | + : PYBIND11_LONG_AS_UNSIGNED_LONGLONG(o); |
| 1113 | + return v == (py_unsigned_int_type_for<Unsigned>) -1 && PyErr_Occurred() ? (Unsigned) -1 : (Unsigned) v; |
| 1114 | +} |
| 1115 | + |
| 1116 | +template <typename Int> |
| 1117 | +Int as_integer(PyObject *o) { |
| 1118 | + if (std::is_unsigned<Int>::value) { |
| 1119 | + return as_unsigned<Int>(o); |
1107 | 1120 | }
|
1108 | 1121 | else {
|
1109 |
| - unsigned long long v = PyLong_AsUnsignedLongLong(o); |
1110 |
| - return v == (unsigned long long) -1 && PyErr_Occurred() ? (Unsigned) -1 : (Unsigned) v; |
| 1122 | + return sizeof(Int) <= sizeof(long) |
| 1123 | + ? (Int) PyLong_AsLong(o) |
| 1124 | + : (Int) PYBIND11_LONG_AS_LONGLONG(o); |
1111 | 1125 | }
|
1112 | 1126 | }
|
1113 | 1127 | PYBIND11_NAMESPACE_END(detail)
|
@@ -1137,11 +1151,18 @@ class int_ : public object {
|
1137 | 1151 | template <typename T,
|
1138 | 1152 | detail::enable_if_t<std::is_integral<T>::value, int> = 0>
|
1139 | 1153 | operator T() const {
|
1140 |
| - return std::is_unsigned<T>::value |
1141 |
| - ? detail::as_unsigned<T>(m_ptr) |
1142 |
| - : sizeof(T) <= sizeof(long) |
1143 |
| - ? (T) PyLong_AsLong(m_ptr) |
1144 |
| - : (T) PYBIND11_LONG_AS_LONGLONG(m_ptr); |
| 1154 | + using py_type = detail::py_int_type_for<T>; |
| 1155 | + auto value = detail::as_integer<py_type>(m_ptr); |
| 1156 | + if (PyErr_Occurred()) |
| 1157 | + throw error_already_set(); |
| 1158 | + if (sizeof(py_type) != sizeof(T) && value != (py_type) (T) value) |
| 1159 | +#if defined(NDEBUG) |
| 1160 | + throw cast_error("Unable to cast Python instance to C++ type (compile in debug mode for details)"); |
| 1161 | +#else |
| 1162 | + throw cast_error("Unable to cast Python instance of type " + |
| 1163 | + (std::string) pybind11::str(type::handle_of(*this)) + " to C++ type '" + type_id<T>() + "'"); |
| 1164 | +#endif |
| 1165 | + return (T) value; |
1145 | 1166 | }
|
1146 | 1167 | };
|
1147 | 1168 |
|
|
0 commit comments