summaryrefslogtreecommitdiff
path: root/ext/pybind11/include
diff options
context:
space:
mode:
Diffstat (limited to 'ext/pybind11/include')
-rw-r--r--ext/pybind11/include/pybind11/attr.h132
-rw-r--r--ext/pybind11/include/pybind11/cast.h522
-rw-r--r--ext/pybind11/include/pybind11/chrono.h8
-rw-r--r--ext/pybind11/include/pybind11/class_support.h504
-rw-r--r--ext/pybind11/include/pybind11/common.h219
-rw-r--r--ext/pybind11/include/pybind11/complex.h13
-rw-r--r--ext/pybind11/include/pybind11/eigen.h564
-rw-r--r--ext/pybind11/include/pybind11/eval.h7
-rw-r--r--ext/pybind11/include/pybind11/functional.h22
-rw-r--r--ext/pybind11/include/pybind11/numpy.h462
-rw-r--r--ext/pybind11/include/pybind11/pybind11.h858
-rw-r--r--ext/pybind11/include/pybind11/pytypes.h458
-rw-r--r--ext/pybind11/include/pybind11/stl.h4
-rw-r--r--ext/pybind11/include/pybind11/stl_bind.h108
14 files changed, 2835 insertions, 1046 deletions
diff --git a/ext/pybind11/include/pybind11/attr.h b/ext/pybind11/include/pybind11/attr.h
index 448612c52..e38a1a32d 100644
--- a/ext/pybind11/include/pybind11/attr.h
+++ b/ext/pybind11/include/pybind11/attr.h
@@ -14,6 +14,9 @@
NAMESPACE_BEGIN(pybind11)
+/// \addtogroup annotations
+/// @{
+
/// Annotation for methods
struct is_method { handle class_; is_method(const handle &c) : class_(c) { } };
@@ -39,7 +42,7 @@ template <typename T> struct base {
};
/// Keep patient alive while nurse lives
-template <int Nurse, int Patient> struct keep_alive { };
+template <size_t Nurse, size_t Patient> struct keep_alive { };
/// Annotation indicating that a class is involved in a multiple inheritance relationship
struct multiple_inheritance { };
@@ -47,9 +50,25 @@ struct multiple_inheritance { };
/// Annotation which enables dynamic attributes, i.e. adds `__dict__` to a class
struct dynamic_attr { };
+/// Annotation which enables the buffer protocol for a type
+struct buffer_protocol { };
+
+/// Annotation which requests that a special metaclass is created for a type
+struct metaclass {
+ handle value;
+
+ PYBIND11_DEPRECATED("py::metaclass() is no longer required. It's turned on by default now.")
+ metaclass() = default;
+
+ /// Override pybind11's default metaclass
+ explicit metaclass(handle value) : value(value) { }
+};
+
/// Annotation to mark enums as an arithmetic type
struct arithmetic { };
+/// @} annotations
+
NAMESPACE_BEGIN(detail)
/* Forward declarations */
enum op_id : int;
@@ -58,16 +77,17 @@ struct undefined_t;
template <op_id id, op_type ot, typename L = undefined_t, typename R = undefined_t> struct op_;
template <typename... Args> struct init;
template <typename... Args> struct init_alias;
-inline void keep_alive_impl(int Nurse, int Patient, handle args, handle ret);
+inline void keep_alive_impl(size_t Nurse, size_t Patient, function_call &call, handle ret);
/// Internal data structure which holds metadata about a keyword argument
struct argument_record {
const char *name; ///< Argument name
const char *descr; ///< Human-readable version of the argument value
handle value; ///< Associated Python object
+ bool convert : 1; ///< True if the argument is allowed to convert when loading
- argument_record(const char *name, const char *descr, handle value)
- : name(name), descr(descr), value(value) { }
+ argument_record(const char *name, const char *descr, handle value, bool convert)
+ : name(name), descr(descr), value(value), convert(convert) { }
};
/// Internal data structure which holds metadata about a bound function (signature, overloads, etc.)
@@ -89,7 +109,7 @@ struct function_record {
std::vector<argument_record> args;
/// Pointer to lambda function which converts arguments and performs the actual call
- handle (*impl) (function_record *, handle, handle, handle) = nullptr;
+ handle (*impl) (function_call &) = nullptr;
/// Storage for the wrapped function pointer and captured data, if any
void *data[3] = { };
@@ -118,8 +138,8 @@ struct function_record {
/// True if this is a method
bool is_method : 1;
- /// Number of arguments
- uint16_t nargs;
+ /// Number of arguments (including py::args and/or py::kwargs, if present)
+ std::uint16_t nargs;
/// Python method object
PyMethodDef *def = nullptr;
@@ -136,7 +156,8 @@ struct function_record {
/// Special data structure which (temporarily) holds metadata about a bound class
struct type_record {
- PYBIND11_NOINLINE type_record() { }
+ PYBIND11_NOINLINE type_record()
+ : multiple_inheritance(false), dynamic_attr(false), buffer_protocol(false) { }
/// Handle to the parent scope
handle scope;
@@ -153,6 +174,9 @@ struct type_record {
/// How large is pybind11::instance<type>?
size_t instance_size = 0;
+ /// The global operator new can be overridden with a class-specific variant
+ void *(*operator_new)(size_t) = ::operator new;
+
/// Function pointer to class_<..>::init_holder
void (*init_holder)(PyObject *, const void *) = nullptr;
@@ -165,11 +189,20 @@ struct type_record {
/// Optional docstring
const char *doc = nullptr;
+ /// Custom metaclass (optional)
+ handle metaclass;
+
/// Multiple inheritance marker
- bool multiple_inheritance = false;
+ bool multiple_inheritance : 1;
/// Does the class manage a __dict__?
- bool dynamic_attr = false;
+ bool dynamic_attr : 1;
+
+ /// Does the class implement the buffer protocol?
+ bool buffer_protocol : 1;
+
+ /// Is the default (unique_ptr) holder type used?
+ bool default_holder : 1;
PYBIND11_NOINLINE void add_base(const std::type_info *base, void *(*caster)(void *)) {
auto base_info = detail::get_type_info(*base, false);
@@ -180,6 +213,15 @@ struct type_record {
"\" referenced unknown base type \"" + tname + "\"");
}
+ if (default_holder != base_info->default_holder) {
+ std::string tname(base->name());
+ detail::clean_type_id(tname);
+ pybind11_fail("generic_type: type \"" + std::string(name) + "\" " +
+ (default_holder ? "does not have" : "has") +
+ " a non-default holder type while its base \"" + tname + "\" " +
+ (base_info->default_holder ? "does not" : "does"));
+ }
+
bases.append((PyObject *) base_info->type);
if (base_info->type->tp_dictoffset != 0)
@@ -190,6 +232,12 @@ struct type_record {
}
};
+inline function_call::function_call(function_record &f, handle p) :
+ func(f), parent(p) {
+ args.reserve(f.nargs);
+ args_convert.reserve(f.nargs);
+}
+
/**
* Partial template specializations to process custom attributes provided to
* cpp_function_ and class_. These are either used to initialize the respective
@@ -202,8 +250,8 @@ template <typename T> struct process_attribute_default {
/// Default implementation: do nothing
static void init(const T &, function_record *) { }
static void init(const T &, type_record *) { }
- static void precall(handle) { }
- static void postcall(handle, handle) { }
+ static void precall(function_call &) { }
+ static void postcall(function_call &, handle) { }
};
/// Process an attribute specifying the function's name
@@ -252,8 +300,8 @@ template <> struct process_attribute<is_operator> : process_attribute_default<is
template <> struct process_attribute<arg> : process_attribute_default<arg> {
static void init(const arg &a, function_record *r) {
if (r->is_method && r->args.empty())
- r->args.emplace_back("self", nullptr, handle());
- r->args.emplace_back(a.name, nullptr, handle());
+ r->args.emplace_back("self", nullptr, handle(), true /*convert*/);
+ r->args.emplace_back(a.name, nullptr, handle(), !a.flag_noconvert);
}
};
@@ -261,32 +309,34 @@ template <> struct process_attribute<arg> : process_attribute_default<arg> {
template <> struct process_attribute<arg_v> : process_attribute_default<arg_v> {
static void init(const arg_v &a, function_record *r) {
if (r->is_method && r->args.empty())
- r->args.emplace_back("self", nullptr, handle());
+ r->args.emplace_back("self", nullptr /*descr*/, handle() /*parent*/, true /*convert*/);
if (!a.value) {
#if !defined(NDEBUG)
- auto descr = "'" + std::string(a.name) + ": " + a.type + "'";
+ std::string descr("'");
+ if (a.name) descr += std::string(a.name) + ": ";
+ descr += a.type + "'";
if (r->is_method) {
if (r->name)
descr += " in method '" + (std::string) str(r->scope) + "." + (std::string) r->name + "'";
else
descr += " in method of '" + (std::string) str(r->scope) + "'";
} else if (r->name) {
- descr += " in function named '" + (std::string) r->name + "'";
+ descr += " in function '" + (std::string) r->name + "'";
}
- pybind11_fail("arg(): could not convert default keyword argument "
+ pybind11_fail("arg(): could not convert default argument "
+ descr + " into a Python object (type not registered yet?)");
#else
- pybind11_fail("arg(): could not convert default keyword argument "
+ pybind11_fail("arg(): could not convert default argument "
"into a Python object (type not registered yet?). "
"Compile in debug mode for more information.");
#endif
}
- r->args.emplace_back(a.name, a.descr, a.value.inc_ref());
+ r->args.emplace_back(a.name, a.descr, a.value.inc_ref(), !a.flag_noconvert);
}
};
-/// Process a parent class attribute
+/// Process a parent class attribute. Single inheritance only (class_ itself already guarantees that)
template <typename T>
struct process_attribute<T, enable_if_t<is_pyobject<T>::value>> : process_attribute_default<handle> {
static void init(const handle &h, type_record *r) { r->bases.append(h); }
@@ -309,6 +359,16 @@ struct process_attribute<dynamic_attr> : process_attribute_default<dynamic_attr>
static void init(const dynamic_attr &, type_record *r) { r->dynamic_attr = true; }
};
+template <>
+struct process_attribute<buffer_protocol> : process_attribute_default<buffer_protocol> {
+ static void init(const buffer_protocol &, type_record *r) { r->buffer_protocol = true; }
+};
+
+template <>
+struct process_attribute<metaclass> : process_attribute_default<metaclass> {
+ static void init(const metaclass &m, type_record *r) { r->metaclass = m.value; }
+};
+
/// Process an 'arithmetic' attribute for enums (does nothing here)
template <>
@@ -319,15 +379,15 @@ struct process_attribute<arithmetic> : process_attribute_default<arithmetic> {};
* pre-call handler if both Nurse, Patient != 0 and use the post-call handler
* otherwise
*/
-template <int Nurse, int Patient> struct process_attribute<keep_alive<Nurse, Patient>> : public process_attribute_default<keep_alive<Nurse, Patient>> {
- template <int N = Nurse, int P = Patient, enable_if_t<N != 0 && P != 0, int> = 0>
- static void precall(handle args) { keep_alive_impl(Nurse, Patient, args, handle()); }
- template <int N = Nurse, int P = Patient, enable_if_t<N != 0 && P != 0, int> = 0>
- static void postcall(handle, handle) { }
- template <int N = Nurse, int P = Patient, enable_if_t<N == 0 || P == 0, int> = 0>
- static void precall(handle) { }
- template <int N = Nurse, int P = Patient, enable_if_t<N == 0 || P == 0, int> = 0>
- static void postcall(handle args, handle ret) { keep_alive_impl(Nurse, Patient, args, ret); }
+template <size_t Nurse, size_t Patient> struct process_attribute<keep_alive<Nurse, Patient>> : public process_attribute_default<keep_alive<Nurse, Patient>> {
+ template <size_t N = Nurse, size_t P = Patient, enable_if_t<N != 0 && P != 0, int> = 0>
+ static void precall(function_call &call) { keep_alive_impl(Nurse, Patient, call, handle()); }
+ template <size_t N = Nurse, size_t P = Patient, enable_if_t<N != 0 && P != 0, int> = 0>
+ static void postcall(function_call &, handle) { }
+ template <size_t N = Nurse, size_t P = Patient, enable_if_t<N == 0 || P == 0, int> = 0>
+ static void precall(function_call &) { }
+ template <size_t N = Nurse, size_t P = Patient, enable_if_t<N == 0 || P == 0, int> = 0>
+ static void postcall(function_call &call, handle ret) { keep_alive_impl(Nurse, Patient, call, ret); }
};
/// Recursively iterate over variadic template arguments
@@ -340,12 +400,12 @@ template <typename... Args> struct process_attributes {
int unused[] = { 0, (process_attribute<typename std::decay<Args>::type>::init(args, r), 0) ... };
ignore_unused(unused);
}
- static void precall(handle fn_args) {
- int unused[] = { 0, (process_attribute<typename std::decay<Args>::type>::precall(fn_args), 0) ... };
+ static void precall(function_call &call) {
+ int unused[] = { 0, (process_attribute<typename std::decay<Args>::type>::precall(call), 0) ... };
ignore_unused(unused);
}
- static void postcall(handle fn_args, handle fn_ret) {
- int unused[] = { 0, (process_attribute<typename std::decay<Args>::type>::postcall(fn_args, fn_ret), 0) ... };
+ static void postcall(function_call &call, handle fn_ret) {
+ int unused[] = { 0, (process_attribute<typename std::decay<Args>::type>::postcall(call, fn_ret), 0) ... };
ignore_unused(unused);
}
};
@@ -354,8 +414,8 @@ template <typename... Args> struct process_attributes {
template <typename... Extra,
size_t named = constexpr_sum(std::is_base_of<arg, Extra>::value...),
size_t self = constexpr_sum(std::is_same<is_method, Extra>::value...)>
-constexpr bool expected_num_args(size_t nargs) {
- return named == 0 || (self + named) == nargs;
+constexpr bool expected_num_args(size_t nargs, bool has_args, bool has_kwargs) {
+ return named == 0 || (self + named + has_args + has_kwargs) == nargs;
}
NAMESPACE_END(detail)
diff --git a/ext/pybind11/include/pybind11/cast.h b/ext/pybind11/include/pybind11/cast.h
index 535516b37..fe19075e4 100644
--- a/ext/pybind11/include/pybind11/cast.h
+++ b/ext/pybind11/include/pybind11/cast.h
@@ -18,12 +18,16 @@
NAMESPACE_BEGIN(pybind11)
NAMESPACE_BEGIN(detail)
+inline PyTypeObject *make_static_property_type();
+inline PyTypeObject *make_default_metaclass();
/// Additional type information which does not fit into the PyTypeObject
struct type_info {
PyTypeObject *type;
size_t type_size;
+ void *(*operator_new)(size_t);
void (*init_holder)(PyObject *, const void *);
+ void (*dealloc)(PyObject *);
std::vector<PyObject *(*)(PyObject *, PyTypeObject *)> implicit_conversions;
std::vector<std::pair<const std::type_info *, void *(*)(void *)>> implicit_casts;
std::vector<bool (*)(PyObject *, void *&)> *direct_conversions;
@@ -32,6 +36,8 @@ struct type_info {
/** A simple type never occurs as a (direct or indirect) parent
* of a class that makes use of multiple inheritance */
bool simple_type = true;
+ /* for base vs derived holder_type checks */
+ bool default_holder = true;
};
PYBIND11_NOINLINE inline internals &get_internals() {
@@ -71,6 +77,8 @@ PYBIND11_NOINLINE inline internals &get_internals() {
}
}
);
+ internals_ptr->static_property_type = make_static_property_type();
+ internals_ptr->default_metaclass = make_default_metaclass();
}
return *internals_ptr;
}
@@ -108,14 +116,10 @@ PYBIND11_NOINLINE inline handle get_type_handle(const std::type_info &tp, bool t
}
PYBIND11_NOINLINE inline bool isinstance_generic(handle obj, const std::type_info &tp) {
- const auto type = detail::get_type_handle(tp, false);
+ handle type = detail::get_type_handle(tp, false);
if (!type)
return false;
-
- const auto result = PyObject_IsInstance(obj.ptr(), type.ptr());
- if (result == -1)
- throw error_already_set();
- return result != 0;
+ return isinstance(obj, type);
}
PYBIND11_NOINLINE inline std::string error_string() {
@@ -141,6 +145,7 @@ PYBIND11_NOINLINE inline std::string error_string() {
PyException_SetTraceback(scope.value, scope.trace);
#endif
+#if !defined(PYPY_VERSION)
if (scope.trace) {
PyTracebackObject *trace = (PyTracebackObject *) scope.trace;
@@ -160,6 +165,7 @@ PYBIND11_NOINLINE inline std::string error_string() {
}
trace = trace->tb_next;
}
+#endif
return errorString;
}
@@ -176,7 +182,9 @@ PYBIND11_NOINLINE inline handle get_object_handle(const void *ptr, const detail:
}
inline PyThreadState *get_thread_state_unchecked() {
-#if PY_VERSION_HEX < 0x03000000
+#if defined(PYPY_VERSION)
+ return PyThreadState_GET();
+#elif PY_VERSION_HEX < 0x03000000
return _PyThreadState_Current;
#elif PY_VERSION_HEX < 0x03050000
return (PyThreadState*) _Py_atomic_load_relaxed(&_PyThreadState_Current);
@@ -224,7 +232,7 @@ public:
/* If this is a python class, also check the parents recursively */
auto const &type_dict = get_internals().registered_types_py;
- bool new_style_class = PyType_Check(tobj);
+ bool new_style_class = PyType_Check((PyObject *) tobj);
if (type_dict.find(tobj) == type_dict.end() && new_style_class && tobj->tp_bases) {
auto parents = reinterpret_borrow<tuple>(tobj->tp_bases);
for (handle parent : parents) {
@@ -400,6 +408,13 @@ public:
make_copy_constructor(src), make_move_constructor(src));
}
+ static handle cast_holder(const itype *src, const void *holder) {
+ return type_caster_generic::cast(
+ src, return_value_policy::take_ownership, {},
+ src ? &typeid(*src) : nullptr, &typeid(type),
+ nullptr, nullptr, holder);
+ }
+
template <typename T> using cast_op_type = pybind11::detail::cast_op_type<T>;
operator itype*() { return (type *) value; }
@@ -413,7 +428,7 @@ protected:
template <typename T = type, typename = enable_if_t<is_copy_constructible<T>::value>> static auto make_copy_constructor(const T *value) -> decltype(new T(*value), Constructor(nullptr)) {
return [](const void *arg) -> void * { return new T(*((const T *) arg)); }; }
template <typename T = type> static auto make_move_constructor(const T *value) -> decltype(new T(std::move(*((T *) value))), Constructor(nullptr)) {
- return [](const void *arg) -> void * { return (void *) new T(std::move(*((T *) arg))); }; }
+ return [](const void *arg) -> void * { return (void *) new T(std::move(*const_cast<T *>(reinterpret_cast<const T *>(arg)))); }; }
#else
/* Visual Studio 2015's SFINAE implementation doesn't yet handle the above robustly in all situations.
Use a workaround that only tests for constructibility for now. */
@@ -455,6 +470,7 @@ public:
public: \
static PYBIND11_DESCR name() { return type_descr(py_name); } \
static handle cast(const type *src, return_value_policy policy, handle parent) { \
+ if (!src) return none().release(); \
return cast(*src, policy, parent); \
} \
operator type*() { return &value; } \
@@ -462,20 +478,31 @@ public:
template <typename _T> using cast_op_type = pybind11::detail::cast_op_type<_T>
+template <typename CharT> using is_std_char_type = any_of<
+ std::is_same<CharT, char>, /* std::string */
+ std::is_same<CharT, char16_t>, /* std::u16string */
+ std::is_same<CharT, char32_t>, /* std::u32string */
+ std::is_same<CharT, wchar_t> /* std::wstring */
+>;
+
template <typename T>
-struct type_caster<T, enable_if_t<std::is_arithmetic<T>::value>> {
- typedef typename std::conditional<sizeof(T) <= sizeof(long), long, long long>::type _py_type_0;
- typedef typename std::conditional<std::is_signed<T>::value, _py_type_0, typename std::make_unsigned<_py_type_0>::type>::type _py_type_1;
- typedef typename std::conditional<std::is_floating_point<T>::value, double, _py_type_1>::type py_type;
+struct type_caster<T, enable_if_t<std::is_arithmetic<T>::value && !is_std_char_type<T>::value>> {
+ using _py_type_0 = conditional_t<sizeof(T) <= sizeof(long), long, long long>;
+ using _py_type_1 = conditional_t<std::is_signed<T>::value, _py_type_0, typename std::make_unsigned<_py_type_0>::type>;
+ using py_type = conditional_t<std::is_floating_point<T>::value, double, _py_type_1>;
public:
- bool load(handle src, bool) {
+ bool load(handle src, bool convert) {
py_type py_value;
- if (!src) {
+ if (!src)
return false;
- } if (std::is_floating_point<T>::value) {
- py_value = (py_type) PyFloat_AsDouble(src.ptr());
+
+ if (std::is_floating_point<T>::value) {
+ if (convert || PyFloat_Check(src.ptr()))
+ py_value = (py_type) PyFloat_AsDouble(src.ptr());
+ else
+ return false;
} else if (sizeof(T) <= sizeof(long)) {
if (PyFloat_Check(src.ptr()))
return false;
@@ -502,7 +529,7 @@ public:
bool type_error = PyErr_ExceptionMatches(PyExc_TypeError);
#endif
PyErr_Clear();
- if (type_error && PyNumber_Check(src.ptr())) {
+ if (type_error && convert && PyNumber_Check(src.ptr())) {
auto tmp = reinterpret_borrow<object>(std::is_floating_point<T>::value
? PyNumber_Float(src.ptr())
: PyNumber_Long(src.ptr()));
@@ -604,133 +631,161 @@ public:
PYBIND11_TYPE_CASTER(bool, _("bool"));
};
-template <> class type_caster<std::string> {
-public:
- bool load(handle src, bool) {
- object temp;
- handle load_src = src;
- if (!src) {
- return false;
- } else if (PyUnicode_Check(load_src.ptr())) {
- temp = reinterpret_steal<object>(PyUnicode_AsUTF8String(load_src.ptr()));
- if (!temp) { PyErr_Clear(); return false; } // UnicodeEncodeError
- load_src = temp;
- }
- char *buffer;
- ssize_t length;
- int err = PYBIND11_BYTES_AS_STRING_AND_SIZE(load_src.ptr(), &buffer, &length);
- if (err == -1) { PyErr_Clear(); return false; } // TypeError
- value = std::string(buffer, (size_t) length);
- success = true;
- return true;
- }
+// Helper class for UTF-{8,16,32} C++ stl strings:
+template <typename CharT, class Traits, class Allocator>
+struct type_caster<std::basic_string<CharT, Traits, Allocator>, enable_if_t<is_std_char_type<CharT>::value>> {
+ // Simplify life by being able to assume standard char sizes (the standard only guarantees
+ // minimums), but Python requires exact sizes
+ static_assert(!std::is_same<CharT, char>::value || sizeof(CharT) == 1, "Unsupported char size != 1");
+ static_assert(!std::is_same<CharT, char16_t>::value || sizeof(CharT) == 2, "Unsupported char16_t size != 2");
+ static_assert(!std::is_same<CharT, char32_t>::value || sizeof(CharT) == 4, "Unsupported char32_t size != 4");
+ // wchar_t can be either 16 bits (Windows) or 32 (everywhere else)
+ static_assert(!std::is_same<CharT, wchar_t>::value || sizeof(CharT) == 2 || sizeof(CharT) == 4,
+ "Unsupported wchar_t size != 2/4");
+ static constexpr size_t UTF_N = 8 * sizeof(CharT);
+
+ using StringType = std::basic_string<CharT, Traits, Allocator>;
- static handle cast(const std::string &src, return_value_policy /* policy */, handle /* parent */) {
- return PyUnicode_FromStringAndSize(src.c_str(), (ssize_t) src.length());
- }
-
- PYBIND11_TYPE_CASTER(std::string, _(PYBIND11_STRING_NAME));
-protected:
- bool success = false;
-};
-
-template <typename type, typename deleter> class type_caster<std::unique_ptr<type, deleter>> {
-public:
- static handle cast(std::unique_ptr<type, deleter> &&src, return_value_policy policy, handle parent) {
- handle result = type_caster_base<type>::cast(src.get(), policy, parent);
- if (result)
- src.release();
- return result;
- }
- static PYBIND11_DESCR name() { return type_caster_base<type>::name(); }
-};
-
-template <> class type_caster<std::wstring> {
-public:
bool load(handle src, bool) {
+#if PY_MAJOR_VERSION < 3
object temp;
+#endif
handle load_src = src;
if (!src) {
return false;
} else if (!PyUnicode_Check(load_src.ptr())) {
+#if PY_MAJOR_VERSION >= 3
+ return false;
+ // The below is a guaranteed failure in Python 3 when PyUnicode_Check returns false
+#else
+ if (!PYBIND11_BYTES_CHECK(load_src.ptr()))
+ return false;
temp = reinterpret_steal<object>(PyUnicode_FromObject(load_src.ptr()));
if (!temp) { PyErr_Clear(); return false; }
load_src = temp;
- }
- wchar_t *buffer = nullptr;
- ssize_t length = -1;
-#if PY_MAJOR_VERSION >= 3
- buffer = PyUnicode_AsWideCharString(load_src.ptr(), &length);
-#else
- temp = reinterpret_steal<object>(
- sizeof(wchar_t) == sizeof(short)
- ? PyUnicode_AsUTF16String(load_src.ptr())
- : PyUnicode_AsUTF32String(load_src.ptr()));
- if (temp) {
- int err = PYBIND11_BYTES_AS_STRING_AND_SIZE(temp.ptr(), (char **) &buffer, &length);
- if (err == -1) { buffer = nullptr; } // TypeError
- length = length / (ssize_t) sizeof(wchar_t) - 1; ++buffer; // Skip BOM
- }
#endif
- if (!buffer) { PyErr_Clear(); return false; }
- value = std::wstring(buffer, (size_t) length);
- success = true;
+ }
+
+ object utfNbytes = reinterpret_steal<object>(PyUnicode_AsEncodedString(
+ load_src.ptr(), UTF_N == 8 ? "utf-8" : UTF_N == 16 ? "utf-16" : "utf-32", nullptr));
+ if (!utfNbytes) { PyErr_Clear(); return false; }
+
+ const CharT *buffer = reinterpret_cast<const CharT *>(PYBIND11_BYTES_AS_STRING(utfNbytes.ptr()));
+ size_t length = (size_t) PYBIND11_BYTES_SIZE(utfNbytes.ptr()) / sizeof(CharT);
+ if (UTF_N > 8) { buffer++; length--; } // Skip BOM for UTF-16/32
+ value = StringType(buffer, length);
return true;
}
- static handle cast(const std::wstring &src, return_value_policy /* policy */, handle /* parent */) {
- return PyUnicode_FromWideChar(src.c_str(), (ssize_t) src.length());
+ static handle cast(const StringType &src, return_value_policy /* policy */, handle /* parent */) {
+ const char *buffer = reinterpret_cast<const char *>(src.c_str());
+ ssize_t nbytes = ssize_t(src.size() * sizeof(CharT));
+ handle s = decode_utfN(buffer, nbytes);
+ if (!s) throw error_already_set();
+ return s;
}
- PYBIND11_TYPE_CASTER(std::wstring, _(PYBIND11_STRING_NAME));
-protected:
- bool success = false;
+ PYBIND11_TYPE_CASTER(StringType, _(PYBIND11_STRING_NAME));
+
+private:
+ static handle decode_utfN(const char *buffer, ssize_t nbytes) {
+#if !defined(PYPY_VERSION)
+ return
+ UTF_N == 8 ? PyUnicode_DecodeUTF8(buffer, nbytes, nullptr) :
+ UTF_N == 16 ? PyUnicode_DecodeUTF16(buffer, nbytes, nullptr, nullptr) :
+ PyUnicode_DecodeUTF32(buffer, nbytes, nullptr, nullptr);
+#else
+ // PyPy seems to have multiple problems related to PyUnicode_UTF*: the UTF8 version
+ // sometimes segfaults for unknown reasons, while the UTF16 and 32 versions require a
+ // non-const char * arguments, which is also a nuissance, so bypass the whole thing by just
+ // passing the encoding as a string value, which works properly:
+ return PyUnicode_Decode(buffer, nbytes, UTF_N == 8 ? "utf-8" : UTF_N == 16 ? "utf-16" : "utf-32", nullptr);
+#endif
+ }
};
-template <> class type_caster<char> : public type_caster<std::string> {
+// Type caster for C-style strings. We basically use a std::string type caster, but also add the
+// ability to use None as a nullptr char* (which the string caster doesn't allow).
+template <typename CharT> struct type_caster<CharT, enable_if_t<is_std_char_type<CharT>::value>> {
+ using StringType = std::basic_string<CharT>;
+ using StringCaster = type_caster<StringType>;
+ StringCaster str_caster;
+ bool none = false;
public:
bool load(handle src, bool convert) {
- if (src.is_none()) return true;
- return type_caster<std::string>::load(src, convert);
- }
-
- static handle cast(const char *src, return_value_policy /* policy */, handle /* parent */) {
- if (src == nullptr) return none().inc_ref();
- return PyUnicode_FromString(src);
+ if (!src) return false;
+ if (src.is_none()) {
+ // Defer accepting None to other overloads (if we aren't in convert mode):
+ if (!convert) return false;
+ none = true;
+ return true;
+ }
+ return str_caster.load(src, convert);
}
- static handle cast(char src, return_value_policy /* policy */, handle /* parent */) {
- char str[2] = { src, '\0' };
- return PyUnicode_DecodeLatin1(str, 1, nullptr);
+ static handle cast(const CharT *src, return_value_policy policy, handle parent) {
+ if (src == nullptr) return pybind11::none().inc_ref();
+ return StringCaster::cast(StringType(src), policy, parent);
}
- operator char*() { return success ? (char *) value.c_str() : nullptr; }
- operator char&() { return value[0]; }
-
- static PYBIND11_DESCR name() { return type_descr(_(PYBIND11_STRING_NAME)); }
-};
+ static handle cast(CharT src, return_value_policy policy, handle parent) {
+ if (std::is_same<char, CharT>::value) {
+ handle s = PyUnicode_DecodeLatin1((const char *) &src, 1, nullptr);
+ if (!s) throw error_already_set();
+ return s;
+ }
+ return StringCaster::cast(StringType(1, src), policy, parent);
+ }
+
+ operator CharT*() { return none ? nullptr : const_cast<CharT *>(static_cast<StringType &>(str_caster).c_str()); }
+ operator CharT() {
+ if (none)
+ throw value_error("Cannot convert None to a character");
+
+ auto &value = static_cast<StringType &>(str_caster);
+ size_t str_len = value.size();
+ if (str_len == 0)
+ throw value_error("Cannot convert empty string to a character");
+
+ // If we're in UTF-8 mode, we have two possible failures: one for a unicode character that
+ // is too high, and one for multiple unicode characters (caught later), so we need to figure
+ // out how long the first encoded character is in bytes to distinguish between these two
+ // errors. We also allow want to allow unicode characters U+0080 through U+00FF, as those
+ // can fit into a single char value.
+ if (StringCaster::UTF_N == 8 && str_len > 1 && str_len <= 4) {
+ unsigned char v0 = static_cast<unsigned char>(value[0]);
+ size_t char0_bytes = !(v0 & 0x80) ? 1 : // low bits only: 0-127
+ (v0 & 0xE0) == 0xC0 ? 2 : // 0b110xxxxx - start of 2-byte sequence
+ (v0 & 0xF0) == 0xE0 ? 3 : // 0b1110xxxx - start of 3-byte sequence
+ 4; // 0b11110xxx - start of 4-byte sequence
+
+ if (char0_bytes == str_len) {
+ // If we have a 128-255 value, we can decode it into a single char:
+ if (char0_bytes == 2 && (v0 & 0xFC) == 0xC0) { // 0x110000xx 0x10xxxxxx
+ return static_cast<CharT>(((v0 & 3) << 6) + (static_cast<unsigned char>(value[1]) & 0x3F));
+ }
+ // Otherwise we have a single character, but it's > U+00FF
+ throw value_error("Character code point not in range(0x100)");
+ }
+ }
-template <> class type_caster<wchar_t> : public type_caster<std::wstring> {
-public:
- bool load(handle src, bool convert) {
- if (src.is_none()) return true;
- return type_caster<std::wstring>::load(src, convert);
- }
+ // UTF-16 is much easier: we can only have a surrogate pair for values above U+FFFF, thus a
+ // surrogate pair with total length 2 instantly indicates a range error (but not a "your
+ // string was too long" error).
+ else if (StringCaster::UTF_N == 16 && str_len == 2) {
+ char16_t v0 = static_cast<char16_t>(value[0]);
+ if (v0 >= 0xD800 && v0 < 0xE000)
+ throw value_error("Character code point not in range(0x10000)");
+ }
- static handle cast(const wchar_t *src, return_value_policy /* policy */, handle /* parent */) {
- if (src == nullptr) return none().inc_ref();
- return PyUnicode_FromWideChar(src, (ssize_t) wcslen(src));
- }
+ if (str_len != 1)
+ throw value_error("Expected a character, but multi-character string found");
- static handle cast(wchar_t src, return_value_policy /* policy */, handle /* parent */) {
- wchar_t wstr[2] = { src, L'\0' };
- return PyUnicode_FromWideChar(wstr, 1);
+ return value[0];
}
- operator wchar_t*() { return success ? (wchar_t *) value.c_str() : nullptr; }
- operator wchar_t&() { return value[0]; }
-
static PYBIND11_DESCR name() { return type_descr(_(PYBIND11_STRING_NAME)); }
+ template <typename _T> using cast_op_type = typename std::remove_reference<pybind11::detail::cast_op_type<_T>>::type;
};
template <typename T1, typename T2> class type_caster<std::pair<T1, T2>> {
@@ -832,12 +887,19 @@ protected:
return result.release();
}
-protected:
std::tuple<make_caster<Tuple>...> value;
};
+/// Helper class which abstracts away certain actions. Users can provide specializations for
+/// custom holders, but it's only necessary if the type has a non-standard interface.
+template <typename T>
+struct holder_helper {
+ static auto get(const T &p) -> decltype(p.get()) { return p.get(); }
+};
+
/// Type caster for holder types like std::shared_ptr, etc.
-template <typename type, typename holder_type> class type_caster_holder : public type_caster_base<type> {
+template <typename type, typename holder_type>
+struct copyable_holder_caster : public type_caster_base<type> {
public:
using base = type_caster_base<type>;
using base::base;
@@ -858,6 +920,9 @@ public:
return true;
}
+ if (typeinfo->default_holder)
+ throw cast_error("Unable to load a custom holder type from a default-holder instance");
+
if (typeinfo->simple_type) { /* Case 1: no multiple inheritance etc. involved */
/* Check if we can safely perform a reinterpret-style cast */
if (PyType_IsSubtype(tobj, typeinfo->type))
@@ -869,7 +934,7 @@ public:
/* If this is a python class, also check the parents recursively */
auto const &type_dict = get_internals().registered_types_py;
- bool new_style_class = PyType_Check(tobj);
+ bool new_style_class = PyType_Check((PyObject *) tobj);
if (type_dict.find(tobj) == type_dict.end() && new_style_class && tobj->tp_bases) {
auto parents = reinterpret_borrow<tuple>(tobj->tp_bases);
for (handle parent : parents) {
@@ -916,7 +981,7 @@ public:
template <typename T = holder_type, detail::enable_if_t<std::is_constructible<T, const T &, type*>::value, int> = 0>
bool try_implicit_casts(handle src, bool convert) {
for (auto &cast : typeinfo->implicit_casts) {
- type_caster_holder sub_caster(*cast.first);
+ copyable_holder_caster sub_caster(*cast.first);
if (sub_caster.load(src, convert)) {
value = cast.second(sub_caster.value);
holder = holder_type(sub_caster.holder, (type *) value);
@@ -939,10 +1004,8 @@ public:
#endif
static handle cast(const holder_type &src, return_value_policy, handle) {
- return type_caster_generic::cast(
- src.get(), return_value_policy::take_ownership, handle(),
- src.get() ? &typeid(*src.get()) : nullptr, &typeid(type),
- nullptr, nullptr, &src);
+ const auto *ptr = holder_helper<holder_type>::get(src);
+ return type_caster_base<type>::cast_holder(ptr, &src);
}
protected:
@@ -951,12 +1014,34 @@ protected:
/// Specialize for the common std::shared_ptr, so users don't need to
template <typename T>
-class type_caster<std::shared_ptr<T>> : public type_caster_holder<T, std::shared_ptr<T>> { };
+class type_caster<std::shared_ptr<T>> : public copyable_holder_caster<T, std::shared_ptr<T>> { };
+
+template <typename type, typename holder_type>
+struct move_only_holder_caster {
+ static handle cast(holder_type &&src, return_value_policy, handle) {
+ auto *ptr = holder_helper<holder_type>::get(src);
+ return type_caster_base<type>::cast_holder(ptr, &src);
+ }
+ static PYBIND11_DESCR name() { return type_caster_base<type>::name(); }
+};
+
+template <typename type, typename deleter>
+class type_caster<std::unique_ptr<type, deleter>>
+ : public move_only_holder_caster<type, std::unique_ptr<type, deleter>> { };
+
+template <typename type, typename holder_type>
+using type_caster_holder = conditional_t<std::is_copy_constructible<holder_type>::value,
+ copyable_holder_caster<type, holder_type>,
+ move_only_holder_caster<type, holder_type>>;
+
+template <typename T, bool Value = false> struct always_construct_holder { static constexpr bool value = Value; };
/// Create a specialization for custom holder types (silently ignores std::shared_ptr)
-#define PYBIND11_DECLARE_HOLDER_TYPE(type, holder_type) \
+#define PYBIND11_DECLARE_HOLDER_TYPE(type, holder_type, ...) \
namespace pybind11 { namespace detail { \
template <typename type> \
+ struct always_construct_holder<holder_type> : always_construct_holder<void, ##__VA_ARGS__> { }; \
+ template <typename type> \
class type_caster<holder_type, enable_if_t<!is_shared_ptr<holder_type>::value>> \
: public type_caster_holder<type, holder_type> { }; \
}}
@@ -1004,23 +1089,24 @@ class type_caster<T, enable_if_t<is_pyobject<T>::value>> : public pyobject_caste
// - if the type is non-copy-constructible, the object must be the sole owner of the type (i.e. it
// must have ref_count() == 1)h
// If any of the above are not satisfied, we fall back to copying.
-template <typename T, typename SFINAE = void> struct move_is_plain_type : std::false_type {};
-template <typename T> struct move_is_plain_type<T, enable_if_t<
- !std::is_void<T>::value && !std::is_pointer<T>::value && !std::is_reference<T>::value && !std::is_const<T>::value
- >> : std::true_type { };
+template <typename T> using move_is_plain_type = satisfies_none_of<T,
+ std::is_void, std::is_pointer, std::is_reference, std::is_const
+>;
template <typename T, typename SFINAE = void> struct move_always : std::false_type {};
-template <typename T> struct move_always<T, enable_if_t<
- move_is_plain_type<T>::value &&
- !std::is_copy_constructible<T>::value && std::is_move_constructible<T>::value &&
- std::is_same<decltype(std::declval<type_caster<T>>().operator T&()), T&>::value
- >> : std::true_type { };
+template <typename T> struct move_always<T, enable_if_t<all_of<
+ move_is_plain_type<T>,
+ negation<std::is_copy_constructible<T>>,
+ std::is_move_constructible<T>,
+ std::is_same<decltype(std::declval<make_caster<T>>().operator T&()), T&>
+>::value>> : std::true_type {};
template <typename T, typename SFINAE = void> struct move_if_unreferenced : std::false_type {};
-template <typename T> struct move_if_unreferenced<T, enable_if_t<
- move_is_plain_type<T>::value &&
- !move_always<T>::value && std::is_move_constructible<T>::value &&
- std::is_same<decltype(std::declval<type_caster<T>>().operator T&()), T&>::value
- >> : std::true_type { };
-template <typename T> using move_never = std::integral_constant<bool, !move_always<T>::value && !move_if_unreferenced<T>::value>;
+template <typename T> struct move_if_unreferenced<T, enable_if_t<all_of<
+ move_is_plain_type<T>,
+ negation<move_always<T>>,
+ std::is_move_constructible<T>,
+ std::is_same<decltype(std::declval<make_caster<T>>().operator T&()), T&>
+>::value>> : std::true_type {};
+template <typename T> using move_never = none_of<move_always<T>, move_if_unreferenced<T>>;
// Detect whether returning a `type` from a cast on type's type_caster is going to result in a
// reference or pointer to a local variable of the type_caster. Basically, only
@@ -1031,6 +1117,17 @@ template <typename type> using cast_is_temporary_value_reference = bool_constant
!std::is_base_of<type_caster_generic, make_caster<type>>::value
>;
+// When a value returned from a C++ function is being cast back to Python, we almost always want to
+// force `policy = move`, regardless of the return value policy the function/method was declared
+// with. Some classes (most notably Eigen::Ref and related) need to avoid this, and so can do so by
+// specializing this struct.
+template <typename Return, typename SFINAE = void> struct return_value_policy_override {
+ static return_value_policy policy(return_value_policy p) {
+ return !std::is_lvalue_reference<Return>::value && !std::is_pointer<Return>::value
+ ? return_value_policy::move : p;
+ }
+};
+
// Basic python -> C++ casting; throws if casting fails
template <typename T, typename SFINAE> type_caster<T, SFINAE> &load_type(type_caster<T, SFINAE> &conv, const handle &handle) {
if (!conv.load(handle, true)) {
@@ -1080,7 +1177,7 @@ template <typename T> T handle::cast() const { return pybind11::cast<T>(*this);
template <> inline void handle::cast() const { return; }
template <typename T>
-detail::enable_if_t<detail::move_always<T>::value || detail::move_if_unreferenced<T>::value, T> move(object &&obj) {
+detail::enable_if_t<!detail::move_never<T>::value, T> move(object &&obj) {
if (obj.ref_count() > 1)
#if defined(NDEBUG)
throw cast_error("Unable to cast Python instance to C++ rvalue: instance has multiple references"
@@ -1171,19 +1268,27 @@ template <return_value_policy policy = return_value_policy::automatic_reference,
return result;
}
-/// Annotation for keyword arguments
+/// \ingroup annotations
+/// Annotation for arguments
struct arg {
- constexpr explicit arg(const char *name) : name(name) { }
+ /// Constructs an argument with the name of the argument; if null or omitted, this is a positional argument.
+ constexpr explicit arg(const char *name = nullptr) : name(name), flag_noconvert(false) { }
+ /// Assign a value to this argument
template <typename T> arg_v operator=(T &&value) const;
+ /// Indicate that the type should not be converted in the type caster
+ arg &noconvert(bool flag = true) { flag_noconvert = flag; return *this; }
- const char *name;
+ const char *name; ///< If non-null, this is a named kwargs argument
+ bool flag_noconvert : 1; ///< If set, do not allow conversion (requires a supporting type caster!)
};
-/// Annotation for keyword arguments with values
+/// \ingroup annotations
+/// Annotation for arguments with values
struct arg_v : arg {
+private:
template <typename T>
- arg_v(const char *name, T &&x, const char *descr = nullptr)
- : arg(name),
+ arg_v(arg &&base, T &&x, const char *descr = nullptr)
+ : arg(base),
value(reinterpret_steal<object>(
detail::make_caster<T>::cast(x, return_value_policy::automatic, {})
)),
@@ -1193,40 +1298,89 @@ struct arg_v : arg {
#endif
{ }
+public:
+ /// Direct construction with name, default, and description
+ template <typename T>
+ arg_v(const char *name, T &&x, const char *descr = nullptr)
+ : arg_v(arg(name), std::forward<T>(x), descr) { }
+
+ /// Called internally when invoking `py::arg("a") = value`
+ template <typename T>
+ arg_v(const arg &base, T &&x, const char *descr = nullptr)
+ : arg_v(arg(base), std::forward<T>(x), descr) { }
+
+ /// Same as `arg::noconvert()`, but returns *this as arg_v&, not arg&
+ arg_v &noconvert(bool flag = true) { arg::noconvert(flag); return *this; }
+
+ /// The default value
object value;
+ /// The (optional) description of the default value
const char *descr;
#if !defined(NDEBUG)
+ /// The C++ type name of the default value (only available when compiled in debug mode)
std::string type;
#endif
};
template <typename T>
-arg_v arg::operator=(T &&value) const { return {name, std::forward<T>(value)}; }
+arg_v arg::operator=(T &&value) const { return {std::move(*this), std::forward<T>(value)}; }
/// Alias for backward compatibility -- to be removed in version 2.0
template <typename /*unused*/> using arg_t = arg_v;
inline namespace literals {
-/// String literal version of arg
+/** \rst
+ String literal version of `arg`
+ \endrst */
constexpr arg operator"" _a(const char *name, size_t) { return arg(name); }
}
NAMESPACE_BEGIN(detail)
+// forward declaration
+struct function_record;
+
+/// Internal data associated with a single function call
+struct function_call {
+ function_call(function_record &f, handle p); // Implementation in attr.h
+
+ /// The function data:
+ const function_record &func;
+
+ /// Arguments passed to the function:
+ std::vector<handle> args;
+
+ /// The `convert` value the arguments should be loaded with
+ std::vector<bool> args_convert;
+
+ /// The parent, if any
+ handle parent;
+};
+
+
/// Helper class which loads arguments for C++ functions called from Python
template <typename... Args>
class argument_loader {
- using itypes = type_list<intrinsic_t<Args>...>;
using indices = make_index_sequence<sizeof...(Args)>;
+ template <typename Arg> using argument_is_args = std::is_same<intrinsic_t<Arg>, args>;
+ template <typename Arg> using argument_is_kwargs = std::is_same<intrinsic_t<Arg>, kwargs>;
+ // Get args/kwargs argument positions relative to the end of the argument list:
+ static constexpr auto args_pos = constexpr_first<argument_is_args, Args...>() - (int) sizeof...(Args),
+ kwargs_pos = constexpr_first<argument_is_kwargs, Args...>() - (int) sizeof...(Args);
+
+ static constexpr bool args_kwargs_are_last = kwargs_pos >= - 1 && args_pos >= kwargs_pos - 1;
+
+ static_assert(args_kwargs_are_last, "py::args/py::kwargs are only permitted as the last argument(s) of a function");
+
public:
- static constexpr auto has_kwargs = std::is_same<itypes, type_list<args, kwargs>>::value;
- static constexpr auto has_args = has_kwargs || std::is_same<itypes, type_list<args>>::value;
+ static constexpr bool has_kwargs = kwargs_pos < 0;
+ static constexpr bool has_args = args_pos < 0;
static PYBIND11_DESCR arg_names() { return detail::concat(make_caster<Args>::name()...); }
- bool load_args(handle args, handle kwargs, bool convert) {
- return load_impl(args, kwargs, convert, itypes{});
+ bool load_args(function_call &call) {
+ return load_impl_sequence(call, indices{});
}
template <typename Return, typename Func>
@@ -1241,26 +1395,12 @@ public:
}
private:
- bool load_impl(handle args_, handle, bool convert, type_list<args>) {
- std::get<0>(value).load(args_, convert);
- return true;
- }
-
- bool load_impl(handle args_, handle kwargs_, bool convert, type_list<args, kwargs>) {
- std::get<0>(value).load(args_, convert);
- std::get<1>(value).load(kwargs_, convert);
- return true;
- }
-
- bool load_impl(handle args, handle, bool convert, ... /* anything else */) {
- return load_impl_sequence(args, convert, indices{});
- }
- static constexpr bool load_impl_sequence(handle, bool, index_sequence<>) { return true; }
+ static bool load_impl_sequence(function_call &, index_sequence<>) { return true; }
template <size_t... Is>
- bool load_impl_sequence(handle src, bool convert, index_sequence<Is...>) {
- for (bool r : {std::get<Is>(value).load(PyTuple_GET_ITEM(src.ptr(), Is), convert)...})
+ bool load_impl_sequence(function_call &call, index_sequence<Is...>) {
+ for (bool r : {std::get<Is>(value).load(call.args[Is], call.args_convert[Is])...})
if (!r)
return false;
return true;
@@ -1271,29 +1411,9 @@ private:
return std::forward<Func>(f)(cast_op<Args>(std::get<Is>(value))...);
}
-private:
std::tuple<make_caster<Args>...> value;
};
-NAMESPACE_BEGIN(constexpr_impl)
-/// Implementation details for constexpr functions
-constexpr int first(int i) { return i; }
-template <typename T, typename... Ts>
-constexpr int first(int i, T v, Ts... vs) { return v ? i : first(i + 1, vs...); }
-
-constexpr int last(int /*i*/, int result) { return result; }
-template <typename T, typename... Ts>
-constexpr int last(int i, int result, T v, Ts... vs) { return last(i + 1, v ? i : result, vs...); }
-NAMESPACE_END(constexpr_impl)
-
-/// Return the index of the first type in Ts which satisfies Predicate<T>
-template <template<typename> class Predicate, typename... Ts>
-constexpr int constexpr_first() { return constexpr_impl::first(0, Predicate<Ts>::value...); }
-
-/// Return the index of the last type in Ts which satisfies Predicate<T>
-template <template<typename> class Predicate, typename... Ts>
-constexpr int constexpr_last() { return constexpr_impl::last(0, -1, Predicate<Ts>::value...); }
-
/// Helper class which collects only positional arguments for a Python function call.
/// A fancier version below can collect any argument, but this one is optimal for simple calls.
template <return_value_policy policy>
@@ -1369,6 +1489,13 @@ private:
}
void process(list &/*args_list*/, arg_v a) {
+ if (!a.name)
+#if defined(NDEBUG)
+ nameless_argument_error();
+#else
+ nameless_argument_error(a.type);
+#endif
+
if (m_kwargs.contains(a.name)) {
#if defined(NDEBUG)
multiple_values_error();
@@ -1401,6 +1528,15 @@ private:
}
}
+ [[noreturn]] static void nameless_argument_error() {
+ throw type_error("Got kwargs without a name; only named arguments "
+ "may be passed via py::arg() to a python function call. "
+ "(compile in debug mode for details)");
+ }
+ [[noreturn]] static void nameless_argument_error(std::string type) {
+ throw type_error("Got kwargs without a name of type '" + type + "'; only named "
+ "arguments may be passed via py::arg() to a python function call. ");
+ }
[[noreturn]] static void multiple_values_error() {
throw type_error("Got multiple values for keyword argument "
"(compile in debug mode for details)");
@@ -1427,14 +1563,14 @@ private:
/// Collect only positional arguments for a Python function call
template <return_value_policy policy, typename... Args,
- typename = enable_if_t<all_of_t<is_positional, Args...>::value>>
+ typename = enable_if_t<all_of<is_positional<Args>...>::value>>
simple_collector<policy> collect_arguments(Args &&...args) {
return simple_collector<policy>(std::forward<Args>(args)...);
}
/// Collect all arguments, including keywords and unpacking (only instantiated when needed)
template <return_value_policy policy, typename... Args,
- typename = enable_if_t<!all_of_t<is_positional, Args...>::value>>
+ typename = enable_if_t<!all_of<is_positional<Args>...>::value>>
unpacking_collector<policy> collect_arguments(Args &&...args) {
// Following argument order rules for generalized unpacking according to PEP 448
static_assert(
diff --git a/ext/pybind11/include/pybind11/chrono.h b/ext/pybind11/include/pybind11/chrono.h
index 2b37f56f1..8a41d08b0 100644
--- a/ext/pybind11/include/pybind11/chrono.h
+++ b/ext/pybind11/include/pybind11/chrono.h
@@ -85,9 +85,11 @@ public:
using ss_t = duration<int, std::ratio<1>>;
using us_t = duration<int, std::micro>;
- return PyDelta_FromDSU(duration_cast<dd_t>(d).count(),
- duration_cast<ss_t>(d % days(1)).count(),
- duration_cast<us_t>(d % seconds(1)).count());
+ auto dd = duration_cast<dd_t>(d);
+ auto subd = d - dd;
+ auto ss = duration_cast<ss_t>(subd);
+ auto us = duration_cast<us_t>(subd - ss);
+ return PyDelta_FromDSU(dd.count(), ss.count(), us.count());
}
PYBIND11_TYPE_CASTER(type, _("datetime.timedelta"));
diff --git a/ext/pybind11/include/pybind11/class_support.h b/ext/pybind11/include/pybind11/class_support.h
new file mode 100644
index 000000000..992703ff3
--- /dev/null
+++ b/ext/pybind11/include/pybind11/class_support.h
@@ -0,0 +1,504 @@
+/*
+ pybind11/class_support.h: Python C API implementation details for py::class_
+
+ Copyright (c) 2017 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+ All rights reserved. Use of this source code is governed by a
+ BSD-style license that can be found in the LICENSE file.
+*/
+
+#pragma once
+
+#include "attr.h"
+
+NAMESPACE_BEGIN(pybind11)
+NAMESPACE_BEGIN(detail)
+
+#if !defined(PYPY_VERSION)
+
+/// `pybind11_static_property.__get__()`: Always pass the class instead of the instance.
+extern "C" inline PyObject *pybind11_static_get(PyObject *self, PyObject * /*ob*/, PyObject *cls) {
+ return PyProperty_Type.tp_descr_get(self, cls, cls);
+}
+
+/// `pybind11_static_property.__set__()`: Just like the above `__get__()`.
+extern "C" inline int pybind11_static_set(PyObject *self, PyObject *obj, PyObject *value) {
+ PyObject *cls = PyType_Check(obj) ? obj : (PyObject *) Py_TYPE(obj);
+ return PyProperty_Type.tp_descr_set(self, cls, value);
+}
+
+/** A `static_property` is the same as a `property` but the `__get__()` and `__set__()`
+ methods are modified to always use the object type instead of a concrete instance.
+ Return value: New reference. */
+inline PyTypeObject *make_static_property_type() {
+ constexpr auto *name = "pybind11_static_property";
+ auto name_obj = reinterpret_steal<object>(PYBIND11_FROM_STRING(name));
+
+ /* Danger zone: from now (and until PyType_Ready), make sure to
+ issue no Python C API calls which could potentially invoke the
+ garbage collector (the GC will call type_traverse(), which will in
+ turn find the newly constructed type in an invalid state) */
+ auto heap_type = (PyHeapTypeObject *) PyType_Type.tp_alloc(&PyType_Type, 0);
+ if (!heap_type)
+ pybind11_fail("make_static_property_type(): error allocating type!");
+
+ heap_type->ht_name = name_obj.inc_ref().ptr();
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 3
+ heap_type->ht_qualname = name_obj.inc_ref().ptr();
+#endif
+
+ auto type = &heap_type->ht_type;
+ type->tp_name = name;
+ type->tp_base = &PyProperty_Type;
+ type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE;
+ type->tp_descr_get = pybind11_static_get;
+ type->tp_descr_set = pybind11_static_set;
+
+ if (PyType_Ready(type) < 0)
+ pybind11_fail("make_static_property_type(): failure in PyType_Ready()!");
+
+ setattr((PyObject *) type, "__module__", str("pybind11_builtins"));
+
+ return type;
+}
+
+#else // PYPY
+
+/** PyPy has some issues with the above C API, so we evaluate Python code instead.
+ This function will only be called once so performance isn't really a concern.
+ Return value: New reference. */
+inline PyTypeObject *make_static_property_type() {
+ auto d = dict();
+ PyObject *result = PyRun_String(R"(\
+ class pybind11_static_property(property):
+ def __get__(self, obj, cls):
+ return property.__get__(self, cls, cls)
+
+ def __set__(self, obj, value):
+ cls = obj if isinstance(obj, type) else type(obj)
+ property.__set__(self, cls, value)
+ )", Py_file_input, d.ptr(), d.ptr()
+ );
+ if (result == nullptr)
+ throw error_already_set();
+ Py_DECREF(result);
+ return (PyTypeObject *) d["pybind11_static_property"].cast<object>().release().ptr();
+}
+
+#endif // PYPY
+
+/** Inheriting from multiple C++ types in Python is not supported -- set an error instead.
+ A Python definition (`class C(A, B): pass`) will call `tp_new` so we check for multiple
+ C++ bases here. On the other hand, C++ type definitions (`py::class_<C, A, B>(m, "C")`)
+ don't not use `tp_new` and will not trigger this error. */
+extern "C" inline PyObject *pybind11_meta_new(PyTypeObject *metaclass, PyObject *args,
+ PyObject *kwargs) {
+ PyObject *bases = PyTuple_GetItem(args, 1); // arguments: (name, bases, dict)
+ if (!bases)
+ return nullptr;
+
+ auto &internals = get_internals();
+ auto num_cpp_bases = 0;
+ for (auto base : reinterpret_borrow<tuple>(bases)) {
+ auto base_type = (PyTypeObject *) base.ptr();
+ auto instance_size = static_cast<size_t>(base_type->tp_basicsize);
+ if (PyObject_IsSubclass(base.ptr(), internals.get_base(instance_size)))
+ ++num_cpp_bases;
+ }
+
+ if (num_cpp_bases > 1) {
+ PyErr_SetString(PyExc_TypeError, "Can't inherit from multiple C++ classes in Python."
+ "Use py::class_ to define the class in C++ instead.");
+ return nullptr;
+ } else {
+ return PyType_Type.tp_new(metaclass, args, kwargs);
+ }
+}
+
+/** Types with static properties need to handle `Type.static_prop = x` in a specific way.
+ By default, Python replaces the `static_property` itself, but for wrapped C++ types
+ we need to call `static_property.__set__()` in order to propagate the new value to
+ the underlying C++ data structure. */
+extern "C" inline int pybind11_meta_setattro(PyObject* obj, PyObject* name, PyObject* value) {
+ // Use `_PyType_Lookup()` instead of `PyObject_GetAttr()` in order to get the raw
+ // descriptor (`property`) instead of calling `tp_descr_get` (`property.__get__()`).
+ PyObject *descr = _PyType_Lookup((PyTypeObject *) obj, name);
+
+ // Call `static_property.__set__()` instead of replacing the `static_property`.
+ if (descr && PyObject_IsInstance(descr, (PyObject *) get_internals().static_property_type)) {
+#if !defined(PYPY_VERSION)
+ return Py_TYPE(descr)->tp_descr_set(descr, obj, value);
+#else
+ if (PyObject *result = PyObject_CallMethod(descr, "__set__", "OO", obj, value)) {
+ Py_DECREF(result);
+ return 0;
+ } else {
+ return -1;
+ }
+#endif
+ } else {
+ return PyType_Type.tp_setattro(obj, name, value);
+ }
+}
+
+/** This metaclass is assigned by default to all pybind11 types and is required in order
+ for static properties to function correctly. Users may override this using `py::metaclass`.
+ Return value: New reference. */
+inline PyTypeObject* make_default_metaclass() {
+ constexpr auto *name = "pybind11_type";
+ auto name_obj = reinterpret_steal<object>(PYBIND11_FROM_STRING(name));
+
+ /* Danger zone: from now (and until PyType_Ready), make sure to
+ issue no Python C API calls which could potentially invoke the
+ garbage collector (the GC will call type_traverse(), which will in
+ turn find the newly constructed type in an invalid state) */
+ auto heap_type = (PyHeapTypeObject *) PyType_Type.tp_alloc(&PyType_Type, 0);
+ if (!heap_type)
+ pybind11_fail("make_default_metaclass(): error allocating metaclass!");
+
+ heap_type->ht_name = name_obj.inc_ref().ptr();
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 3
+ heap_type->ht_qualname = name_obj.inc_ref().ptr();
+#endif
+
+ auto type = &heap_type->ht_type;
+ type->tp_name = name;
+ type->tp_base = &PyType_Type;
+ type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE;
+
+ type->tp_new = pybind11_meta_new;
+ type->tp_setattro = pybind11_meta_setattro;
+
+ if (PyType_Ready(type) < 0)
+ pybind11_fail("make_default_metaclass(): failure in PyType_Ready()!");
+
+ setattr((PyObject *) type, "__module__", str("pybind11_builtins"));
+
+ return type;
+}
+
+/// Instance creation function for all pybind11 types. It only allocates space for the
+/// C++ object, but doesn't call the constructor -- an `__init__` function must do that.
+extern "C" inline PyObject *pybind11_object_new(PyTypeObject *type, PyObject *, PyObject *) {
+ PyObject *self = type->tp_alloc(type, 0);
+ auto instance = (instance_essentials<void> *) self;
+ auto tinfo = get_type_info(type);
+ instance->value = tinfo->operator_new(tinfo->type_size);
+ instance->owned = true;
+ instance->holder_constructed = false;
+ get_internals().registered_instances.emplace(instance->value, self);
+ return self;
+}
+
+/// An `__init__` function constructs the C++ object. Users should provide at least one
+/// of these using `py::init` or directly with `.def(__init__, ...)`. Otherwise, the
+/// following default function will be used which simply throws an exception.
+extern "C" inline int pybind11_object_init(PyObject *self, PyObject *, PyObject *) {
+ PyTypeObject *type = Py_TYPE(self);
+ std::string msg;
+#if defined(PYPY_VERSION)
+ msg += handle((PyObject *) type).attr("__module__").cast<std::string>() + ".";
+#endif
+ msg += type->tp_name;
+ msg += ": No constructor defined!";
+ PyErr_SetString(PyExc_TypeError, msg.c_str());
+ return -1;
+}
+
+/// Instance destructor function for all pybind11 types. It calls `type_info.dealloc`
+/// to destroy the C++ object itself, while the rest is Python bookkeeping.
+extern "C" inline void pybind11_object_dealloc(PyObject *self) {
+ auto instance = (instance_essentials<void> *) self;
+ if (instance->value) {
+ auto type = Py_TYPE(self);
+ get_type_info(type)->dealloc(self);
+
+ auto &registered_instances = get_internals().registered_instances;
+ auto range = registered_instances.equal_range(instance->value);
+ bool found = false;
+ for (auto it = range.first; it != range.second; ++it) {
+ if (type == Py_TYPE(it->second)) {
+ registered_instances.erase(it);
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ pybind11_fail("pybind11_object_dealloc(): Tried to deallocate unregistered instance!");
+
+ if (instance->weakrefs)
+ PyObject_ClearWeakRefs(self);
+
+ PyObject **dict_ptr = _PyObject_GetDictPtr(self);
+ if (dict_ptr)
+ Py_CLEAR(*dict_ptr);
+ }
+ Py_TYPE(self)->tp_free(self);
+}
+
+/** Create a type which can be used as a common base for all classes with the same
+ instance size, i.e. all classes with the same `sizeof(holder_type)`. This is
+ needed in order to satisfy Python's requirements for multiple inheritance.
+ Return value: New reference. */
+inline PyObject *make_object_base_type(size_t instance_size) {
+ auto name = "pybind11_object_" + std::to_string(instance_size);
+ auto name_obj = reinterpret_steal<object>(PYBIND11_FROM_STRING(name.c_str()));
+
+ /* Danger zone: from now (and until PyType_Ready), make sure to
+ issue no Python C API calls which could potentially invoke the
+ garbage collector (the GC will call type_traverse(), which will in
+ turn find the newly constructed type in an invalid state) */
+ auto metaclass = get_internals().default_metaclass;
+ auto heap_type = (PyHeapTypeObject *) metaclass->tp_alloc(metaclass, 0);
+ if (!heap_type)
+ pybind11_fail("make_object_base_type(): error allocating type!");
+
+ heap_type->ht_name = name_obj.inc_ref().ptr();
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 3
+ heap_type->ht_qualname = name_obj.inc_ref().ptr();
+#endif
+
+ auto type = &heap_type->ht_type;
+ type->tp_name = strdup(name.c_str());
+ type->tp_base = &PyBaseObject_Type;
+ type->tp_basicsize = static_cast<ssize_t>(instance_size);
+ type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE;
+
+ type->tp_new = pybind11_object_new;
+ type->tp_init = pybind11_object_init;
+ type->tp_dealloc = pybind11_object_dealloc;
+
+ /* Support weak references (needed for the keep_alive feature) */
+ type->tp_weaklistoffset = offsetof(instance_essentials<void>, weakrefs);
+
+ if (PyType_Ready(type) < 0)
+ pybind11_fail("PyType_Ready failed in make_object_base_type():" + error_string());
+
+ setattr((PyObject *) type, "__module__", str("pybind11_builtins"));
+
+ assert(!PyType_HasFeature(type, Py_TPFLAGS_HAVE_GC));
+ return (PyObject *) heap_type;
+}
+
+/** Return the appropriate base type for the given instance size. The results are cached
+ in `internals.bases` so that only a single base is ever created for any size value.
+ Return value: Borrowed reference. */
+inline PyObject *internals::get_base(size_t instance_size) {
+ auto it = bases.find(instance_size);
+ if (it != bases.end()) {
+ return it->second;
+ } else {
+ auto base = make_object_base_type(instance_size);
+ bases[instance_size] = base;
+ return base;
+ }
+}
+
+/// dynamic_attr: Support for `d = instance.__dict__`.
+extern "C" inline PyObject *pybind11_get_dict(PyObject *self, void *) {
+ PyObject *&dict = *_PyObject_GetDictPtr(self);
+ if (!dict)
+ dict = PyDict_New();
+ Py_XINCREF(dict);
+ return dict;
+}
+
+/// dynamic_attr: Support for `instance.__dict__ = dict()`.
+extern "C" inline int pybind11_set_dict(PyObject *self, PyObject *new_dict, void *) {
+ if (!PyDict_Check(new_dict)) {
+ PyErr_Format(PyExc_TypeError, "__dict__ must be set to a dictionary, not a '%.200s'",
+ Py_TYPE(new_dict)->tp_name);
+ return -1;
+ }
+ PyObject *&dict = *_PyObject_GetDictPtr(self);
+ Py_INCREF(new_dict);
+ Py_CLEAR(dict);
+ dict = new_dict;
+ return 0;
+}
+
+/// dynamic_attr: Allow the garbage collector to traverse the internal instance `__dict__`.
+extern "C" inline int pybind11_traverse(PyObject *self, visitproc visit, void *arg) {
+ PyObject *&dict = *_PyObject_GetDictPtr(self);
+ Py_VISIT(dict);
+ return 0;
+}
+
+/// dynamic_attr: Allow the GC to clear the dictionary.
+extern "C" inline int pybind11_clear(PyObject *self) {
+ PyObject *&dict = *_PyObject_GetDictPtr(self);
+ Py_CLEAR(dict);
+ return 0;
+}
+
+/// Give instances of this type a `__dict__` and opt into garbage collection.
+inline void enable_dynamic_attributes(PyHeapTypeObject *heap_type) {
+ auto type = &heap_type->ht_type;
+#if defined(PYPY_VERSION)
+ pybind11_fail(std::string(type->tp_name) + ": dynamic attributes are "
+ "currently not supported in "
+ "conjunction with PyPy!");
+#endif
+ type->tp_flags |= Py_TPFLAGS_HAVE_GC;
+ type->tp_dictoffset = type->tp_basicsize; // place dict at the end
+ type->tp_basicsize += sizeof(PyObject *); // and allocate enough space for it
+ type->tp_traverse = pybind11_traverse;
+ type->tp_clear = pybind11_clear;
+
+ static PyGetSetDef getset[] = {
+ {const_cast<char*>("__dict__"), pybind11_get_dict, pybind11_set_dict, nullptr, nullptr},
+ {nullptr, nullptr, nullptr, nullptr, nullptr}
+ };
+ type->tp_getset = getset;
+}
+
+/// buffer_protocol: Fill in the view as specified by flags.
+extern "C" inline int pybind11_getbuffer(PyObject *obj, Py_buffer *view, int flags) {
+ auto tinfo = get_type_info(Py_TYPE(obj));
+ if (view == nullptr || obj == nullptr || !tinfo || !tinfo->get_buffer) {
+ if (view)
+ view->obj = nullptr;
+ PyErr_SetString(PyExc_BufferError, "generic_type::getbuffer(): Internal error");
+ return -1;
+ }
+ memset(view, 0, sizeof(Py_buffer));
+ buffer_info *info = tinfo->get_buffer(obj, tinfo->get_buffer_data);
+ view->obj = obj;
+ view->ndim = 1;
+ view->internal = info;
+ view->buf = info->ptr;
+ view->itemsize = (ssize_t) info->itemsize;
+ view->len = view->itemsize;
+ for (auto s : info->shape)
+ view->len *= s;
+ if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT)
+ view->format = const_cast<char *>(info->format.c_str());
+ if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES) {
+ view->ndim = (int) info->ndim;
+ view->strides = (ssize_t *) &info->strides[0];
+ view->shape = (ssize_t *) &info->shape[0];
+ }
+ Py_INCREF(view->obj);
+ return 0;
+}
+
+/// buffer_protocol: Release the resources of the buffer.
+extern "C" inline void pybind11_releasebuffer(PyObject *, Py_buffer *view) {
+ delete (buffer_info *) view->internal;
+}
+
+/// Give this type a buffer interface.
+inline void enable_buffer_protocol(PyHeapTypeObject *heap_type) {
+ heap_type->ht_type.tp_as_buffer = &heap_type->as_buffer;
+#if PY_MAJOR_VERSION < 3
+ heap_type->ht_type.tp_flags |= Py_TPFLAGS_HAVE_NEWBUFFER;
+#endif
+
+ heap_type->as_buffer.bf_getbuffer = pybind11_getbuffer;
+ heap_type->as_buffer.bf_releasebuffer = pybind11_releasebuffer;
+}
+
+/** Create a brand new Python type according to the `type_record` specification.
+ Return value: New reference. */
+inline PyObject* make_new_python_type(const type_record &rec) {
+ auto name = reinterpret_steal<object>(PYBIND11_FROM_STRING(rec.name));
+
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 3
+ auto ht_qualname = name;
+ if (rec.scope && hasattr(rec.scope, "__qualname__")) {
+ ht_qualname = reinterpret_steal<object>(
+ PyUnicode_FromFormat("%U.%U", rec.scope.attr("__qualname__").ptr(), name.ptr()));
+ }
+#endif
+
+ object module;
+ if (rec.scope) {
+ if (hasattr(rec.scope, "__module__"))
+ module = rec.scope.attr("__module__");
+ else if (hasattr(rec.scope, "__name__"))
+ module = rec.scope.attr("__name__");
+ }
+
+#if !defined(PYPY_VERSION)
+ const auto full_name = module ? str(module).cast<std::string>() + "." + rec.name
+ : std::string(rec.name);
+#else
+ const auto full_name = std::string(rec.name);
+#endif
+
+ char *tp_doc = nullptr;
+ if (rec.doc && options::show_user_defined_docstrings()) {
+ /* Allocate memory for docstring (using PyObject_MALLOC, since
+ Python will free this later on) */
+ size_t size = strlen(rec.doc) + 1;
+ tp_doc = (char *) PyObject_MALLOC(size);
+ memcpy((void *) tp_doc, rec.doc, size);
+ }
+
+ auto &internals = get_internals();
+ auto bases = tuple(rec.bases);
+ auto base = (bases.size() == 0) ? internals.get_base(rec.instance_size)
+ : bases[0].ptr();
+
+ /* Danger zone: from now (and until PyType_Ready), make sure to
+ issue no Python C API calls which could potentially invoke the
+ garbage collector (the GC will call type_traverse(), which will in
+ turn find the newly constructed type in an invalid state) */
+ auto metaclass = rec.metaclass.ptr() ? (PyTypeObject *) rec.metaclass.ptr()
+ : internals.default_metaclass;
+
+ auto heap_type = (PyHeapTypeObject *) metaclass->tp_alloc(metaclass, 0);
+ if (!heap_type)
+ pybind11_fail(std::string(rec.name) + ": Unable to create type object!");
+
+ heap_type->ht_name = name.release().ptr();
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 3
+ heap_type->ht_qualname = ht_qualname.release().ptr();
+#endif
+
+ auto type = &heap_type->ht_type;
+ type->tp_name = strdup(full_name.c_str());
+ type->tp_doc = tp_doc;
+ type->tp_base = (PyTypeObject *) handle(base).inc_ref().ptr();
+ type->tp_basicsize = static_cast<ssize_t>(rec.instance_size);
+ if (bases.size() > 0)
+ type->tp_bases = bases.release().ptr();
+
+ /* Don't inherit base __init__ */
+ type->tp_init = pybind11_object_init;
+
+ /* Supported protocols */
+ type->tp_as_number = &heap_type->as_number;
+ type->tp_as_sequence = &heap_type->as_sequence;
+ type->tp_as_mapping = &heap_type->as_mapping;
+
+ /* Flags */
+ type->tp_flags |= Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE;
+#if PY_MAJOR_VERSION < 3
+ type->tp_flags |= Py_TPFLAGS_CHECKTYPES;
+#endif
+
+ if (rec.dynamic_attr)
+ enable_dynamic_attributes(heap_type);
+
+ if (rec.buffer_protocol)
+ enable_buffer_protocol(heap_type);
+
+ if (PyType_Ready(type) < 0)
+ pybind11_fail(std::string(rec.name) + ": PyType_Ready failed (" + error_string() + ")!");
+
+ assert(rec.dynamic_attr ? PyType_HasFeature(type, Py_TPFLAGS_HAVE_GC)
+ : !PyType_HasFeature(type, Py_TPFLAGS_HAVE_GC));
+
+ /* Register type with the parent scope */
+ if (rec.scope)
+ setattr(rec.scope, rec.name, (PyObject *) type);
+
+ if (module) // Needed by pydoc
+ setattr((PyObject *) type, "__module__", module);
+
+ return (PyObject *) type;
+}
+
+NAMESPACE_END(detail)
+NAMESPACE_END(pybind11)
diff --git a/ext/pybind11/include/pybind11/common.h b/ext/pybind11/include/pybind11/common.h
index f7a383007..ac2be7aef 100644
--- a/ext/pybind11/include/pybind11/common.h
+++ b/ext/pybind11/include/pybind11/common.h
@@ -28,6 +28,33 @@
# endif
#endif
+// Compiler version assertions
+#if defined(__INTEL_COMPILER)
+# if __INTEL_COMPILER < 1500
+# error pybind11 requires Intel C++ compiler v15 or newer
+# endif
+#elif defined(__clang__) && !defined(__apple_build_version__)
+# if __clang_major__ < 3 || (__clang_major__ == 3 && __clang_minor__ < 3)
+# error pybind11 requires clang 3.3 or newer
+# endif
+#elif defined(__clang__)
+// Apple changes clang version macros to its Xcode version; the first Xcode release based on
+// (upstream) clang 3.3 was Xcode 5:
+# if __clang_major__ < 5
+# error pybind11 requires Xcode/clang 5.0 or newer
+# endif
+#elif defined(__GNUG__)
+# if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 8)
+# error pybind11 requires gcc 4.8 or newer
+# endif
+#elif defined(_MSC_VER)
+// Pybind hits various compiler bugs in 2015u2 and earlier, and also makes use of some stl features
+// (e.g. std::negation) added in 2015u3:
+# if _MSC_FULL_VER < 190024210
+# error pybind11 requires MSVC 2015 update 3 or newer
+# endif
+#endif
+
#if !defined(PYBIND11_EXPORT)
# if defined(WIN32) || defined(_WIN32)
# define PYBIND11_EXPORT __declspec(dllexport)
@@ -52,16 +79,18 @@
# define PYBIND11_DEPRECATED(reason) __declspec(deprecated)
#endif
-#define PYBIND11_VERSION_MAJOR 1
-#define PYBIND11_VERSION_MINOR 9
-#define PYBIND11_VERSION_PATCH dev0
+#define PYBIND11_VERSION_MAJOR 2
+#define PYBIND11_VERSION_MINOR 1
+#define PYBIND11_VERSION_PATCH 1
/// Include Python header, disable linking to pythonX_d.lib on Windows in debug mode
#if defined(_MSC_VER)
-# define HAVE_ROUND
+# if (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 4)
+# define HAVE_ROUND 1
+# endif
# pragma warning(push)
# pragma warning(disable: 4510 4610 4512 4005)
-# if _DEBUG
+# if defined(_DEBUG)
# define PYBIND11_DEBUG_MARKER
# undef _DEBUG
# endif
@@ -111,6 +140,7 @@
#define PYBIND11_BYTES_FROM_STRING_AND_SIZE PyBytes_FromStringAndSize
#define PYBIND11_BYTES_AS_STRING_AND_SIZE PyBytes_AsStringAndSize
#define PYBIND11_BYTES_AS_STRING PyBytes_AsString
+#define PYBIND11_BYTES_SIZE PyBytes_Size
#define PYBIND11_LONG_CHECK(o) PyLong_Check(o)
#define PYBIND11_LONG_AS_LONGLONG(o) PyLong_AsLongLong(o)
#define PYBIND11_LONG_AS_UNSIGNED_LONGLONG(o) PyLong_AsUnsignedLongLong(o)
@@ -119,7 +149,6 @@
#define PYBIND11_SLICE_OBJECT PyObject
#define PYBIND11_FROM_STRING PyUnicode_FromString
#define PYBIND11_STR_TYPE ::pybind11::str
-#define PYBIND11_OB_TYPE(ht_type) (ht_type).ob_base.ob_base.ob_type
#define PYBIND11_PLUGIN_IMPL(name) \
extern "C" PYBIND11_EXPORT PyObject *PyInit_##name()
#else
@@ -129,6 +158,7 @@
#define PYBIND11_BYTES_FROM_STRING_AND_SIZE PyString_FromStringAndSize
#define PYBIND11_BYTES_AS_STRING_AND_SIZE PyString_AsStringAndSize
#define PYBIND11_BYTES_AS_STRING PyString_AsString
+#define PYBIND11_BYTES_SIZE PyString_Size
#define PYBIND11_LONG_CHECK(o) (PyInt_Check(o) || PyLong_Check(o))
#define PYBIND11_LONG_AS_LONGLONG(o) (PyInt_Check(o) ? (long long) PyLong_AsLong(o) : PyLong_AsLongLong(o))
#define PYBIND11_LONG_AS_UNSIGNED_LONGLONG(o) (PyInt_Check(o) ? (unsigned long long) PyLong_AsUnsignedLong(o) : PyLong_AsUnsignedLongLong(o))
@@ -137,9 +167,12 @@
#define PYBIND11_SLICE_OBJECT PySliceObject
#define PYBIND11_FROM_STRING PyString_FromString
#define PYBIND11_STR_TYPE ::pybind11::bytes
-#define PYBIND11_OB_TYPE(ht_type) (ht_type).ob_type
#define PYBIND11_PLUGIN_IMPL(name) \
- extern "C" PYBIND11_EXPORT PyObject *init##name()
+ static PyObject *pybind11_init_wrapper(); \
+ extern "C" PYBIND11_EXPORT void init##name() { \
+ (void)pybind11_init_wrapper(); \
+ } \
+ PyObject *pybind11_init_wrapper()
#endif
#if PY_VERSION_HEX >= 0x03050000 && PY_VERSION_HEX < 0x03050200
@@ -155,6 +188,19 @@ extern "C" {
#define PYBIND11_INTERNALS_ID "__pybind11_" \
PYBIND11_TOSTRING(PYBIND11_VERSION_MAJOR) "_" PYBIND11_TOSTRING(PYBIND11_VERSION_MINOR) "__"
+/** \rst
+ This macro creates the entry point that will be invoked when the Python interpreter
+ imports a plugin library. Please create a `module` in the function body and return
+ the pointer to its underlying Python object at the end.
+
+ .. code-block:: cpp
+
+ PYBIND11_PLUGIN(example) {
+ pybind11::module m("example", "pybind11 example plugin");
+ /// Set up bindings here
+ return m.ptr();
+ }
+\endrst */
#define PYBIND11_PLUGIN(name) \
static PyObject *pybind11_init(); \
PYBIND11_PLUGIN_IMPL(name) { \
@@ -172,6 +218,10 @@ extern "C" {
} \
try { \
return pybind11_init(); \
+ } catch (pybind11::error_already_set &e) { \
+ e.clear(); \
+ PyErr_SetString(PyExc_ImportError, e.what()); \
+ return nullptr; \
} catch (const std::exception &e) { \
PyErr_SetString(PyExc_ImportError, e.what()); \
return nullptr; \
@@ -327,7 +377,7 @@ struct overload_hash {
}
};
-/// Internal data struture used to track registered instances and types
+/// Internal data structure used to track registered instances and types
struct internals {
std::unordered_map<std::type_index, void*> registered_types_cpp; // std::type_index -> type_info
std::unordered_map<const void *, void*> registered_types_py; // PyTypeObject* -> type_info
@@ -336,17 +386,34 @@ struct internals {
std::unordered_map<std::type_index, std::vector<bool (*)(PyObject *, void *&)>> direct_conversions;
std::forward_list<void (*) (std::exception_ptr)> registered_exception_translators;
std::unordered_map<std::string, void *> shared_data; // Custom data to be shared across extensions
+ PyTypeObject *static_property_type;
+ PyTypeObject *default_metaclass;
+ std::unordered_map<size_t, PyObject *> bases; // one base type per `instance_size` (very few)
#if defined(WITH_THREAD)
decltype(PyThread_create_key()) tstate = 0; // Usually an int but a long on Cygwin64 with Python 3.x
PyInterpreterState *istate = nullptr;
#endif
+
+ /// Return the appropriate base type for the given instance size
+ PyObject *get_base(size_t instance_size);
};
/// Return a reference to the current 'internals' information
inline internals &get_internals();
-/// Index sequence for convenient template metaprogramming involving tuples
+/// from __cpp_future__ import (convenient aliases from C++14/17)
#ifdef PYBIND11_CPP14
+using std::enable_if_t;
+using std::conditional_t;
+using std::remove_cv_t;
+#else
+template <bool B, typename T = void> using enable_if_t = typename std::enable_if<B, T>::type;
+template <bool B, typename T, typename F> using conditional_t = typename std::conditional<B, T, F>::type;
+template <typename T> using remove_cv_t = typename std::remove_cv<T>::type;
+#endif
+
+/// Index sequences
+#if defined(PYBIND11_CPP14) || defined(_MSC_VER)
using std::index_sequence;
using std::make_index_sequence;
#else
@@ -356,6 +423,35 @@ template<size_t ...S> struct make_index_sequence_impl <0, S...> { typedef index_
template<size_t N> using make_index_sequence = typename make_index_sequence_impl<N>::type;
#endif
+/// Backports of std::bool_constant and std::negation to accomodate older compilers
+template <bool B> using bool_constant = std::integral_constant<bool, B>;
+template <typename T> struct negation : bool_constant<!T::value> { };
+
+template <typename...> struct void_t_impl { using type = void; };
+template <typename... Ts> using void_t = typename void_t_impl<Ts...>::type;
+
+/// Compile-time all/any/none of that check the boolean value of all template types
+#ifdef __cpp_fold_expressions
+template <class... Ts> using all_of = bool_constant<(Ts::value && ...)>;
+template <class... Ts> using any_of = bool_constant<(Ts::value || ...)>;
+#elif !defined(_MSC_VER)
+template <bool...> struct bools {};
+template <class... Ts> using all_of = std::is_same<
+ bools<Ts::value..., true>,
+ bools<true, Ts::value...>>;
+template <class... Ts> using any_of = negation<all_of<negation<Ts>...>>;
+#else
+// MSVC has trouble with the above, but supports std::conjunction, which we can use instead (albeit
+// at a slight loss of compilation efficiency).
+template <class... Ts> using all_of = std::conjunction<Ts...>;
+template <class... Ts> using any_of = std::disjunction<Ts...>;
+#endif
+template <class... Ts> using none_of = negation<any_of<Ts...>>;
+
+template <class T, template<class> class... Predicates> using satisfies_all_of = all_of<Predicates<T>...>;
+template <class T, template<class> class... Predicates> using satisfies_any_of = any_of<Predicates<T>...>;
+template <class T, template<class> class... Predicates> using satisfies_none_of = none_of<Predicates<T>...>;
+
/// Strip the class from a method type
template <typename T> struct remove_class { };
template <typename C, typename R, typename... A> struct remove_class<R (C::*)(A...)> { typedef R type(A...); };
@@ -377,34 +473,34 @@ struct void_type { };
/// Helper template which holds a list of types
template <typename...> struct type_list { };
-/// from __cpp_future__ import (convenient aliases from C++14/17)
-template <bool B> using bool_constant = std::integral_constant<bool, B>;
-template <class T> using negation = bool_constant<!T::value>;
-template <bool B, typename T = void> using enable_if_t = typename std::enable_if<B, T>::type;
-template <bool B, typename T, typename F> using conditional_t = typename std::conditional<B, T, F>::type;
-
/// Compile-time integer sum
+#ifdef __cpp_fold_expressions
+template <typename... Ts> constexpr size_t constexpr_sum(Ts... ns) { return (0 + ... + size_t{ns}); }
+#else
constexpr size_t constexpr_sum() { return 0; }
template <typename T, typename... Ts>
constexpr size_t constexpr_sum(T n, Ts... ns) { return size_t{n} + constexpr_sum(ns...); }
-
-// Counts the number of types in the template parameter pack matching the predicate
-#if !defined(_MSC_VER)
-template <template<typename> class Predicate, typename... Ts>
-using count_t = std::integral_constant<size_t, constexpr_sum(Predicate<Ts>::value...)>;
-#else
-// MSVC workaround (2015 Update 3 has issues with some member type aliases and constexpr)
-template <template<typename> class Predicate, typename... Ts> struct count_t;
-template <template<typename> class Predicate> struct count_t<Predicate> : std::integral_constant<size_t, 0> {};
-template <template<typename> class Predicate, class T, class... Ts>
-struct count_t<Predicate, T, Ts...> : std::integral_constant<size_t, Predicate<T>::value + count_t<Predicate, Ts...>::value> {};
#endif
-/// Return true if all/any Ts satify Predicate<T>
+NAMESPACE_BEGIN(constexpr_impl)
+/// Implementation details for constexpr functions
+constexpr int first(int i) { return i; }
+template <typename T, typename... Ts>
+constexpr int first(int i, T v, Ts... vs) { return v ? i : first(i + 1, vs...); }
+
+constexpr int last(int /*i*/, int result) { return result; }
+template <typename T, typename... Ts>
+constexpr int last(int i, int result, T v, Ts... vs) { return last(i + 1, v ? i : result, vs...); }
+NAMESPACE_END(constexpr_impl)
+
+/// Return the index of the first type in Ts which satisfies Predicate<T>. Returns sizeof...(Ts) if
+/// none match.
template <template<typename> class Predicate, typename... Ts>
-using all_of_t = bool_constant<(count_t<Predicate, Ts...>::value == sizeof...(Ts))>;
+constexpr int constexpr_first() { return constexpr_impl::first(0, Predicate<Ts>::value...); }
+
+/// Return the index of the last type in Ts which satisfies Predicate<T>, or -1 if none match.
template <template<typename> class Predicate, typename... Ts>
-using any_of_t = bool_constant<(count_t<Predicate, Ts...>::value > 0)>;
+constexpr int constexpr_last() { return constexpr_impl::last(0, -1, Predicate<Ts>::value...); }
// Extracts the first type from the template parameter pack matching the predicate, or Default if none match.
template <template<class> class Predicate, class Default, class... Ts> struct first_of;
@@ -435,9 +531,9 @@ struct is_template_base_of_impl {
/// `is_template_base_of<Base, T>` is true if `struct T : Base<U> {}` where U can be anything
template <template<typename...> class Base, typename T>
#if !defined(_MSC_VER)
-using is_template_base_of = decltype(is_template_base_of_impl<Base>::check((T*)nullptr));
+using is_template_base_of = decltype(is_template_base_of_impl<Base>::check((remove_cv_t<T>*)nullptr));
#else // MSVC2015 has trouble with decltype in template aliases
-struct is_template_base_of : decltype(is_template_base_of_impl<Base>::check((T*)nullptr)) { };
+struct is_template_base_of : decltype(is_template_base_of_impl<Base>::check((remove_cv_t<T>*)nullptr)) { };
#endif
/// Check if T is std::shared_ptr<U> where U can be anything
@@ -498,6 +594,9 @@ public:
/// Give the error back to Python
void restore() { PyErr_Restore(type, value, trace); type = value = trace = nullptr; }
+ /// Clear the held Python error state (the C++ `what()` message remains intact)
+ void clear() { restore(); PyErr_Clear(); }
+
private:
PyObject *type, *value, *trace;
};
@@ -506,7 +605,8 @@ private:
class builtin_exception : public std::runtime_error {
public:
using std::runtime_error::runtime_error;
- virtual void set_error() const = 0; /// Set the error using the Python C API
+ /// Set the error using the Python C API
+ virtual void set_error() const = 0;
};
#define PYBIND11_RUNTIME_EXCEPTION(name, type) \
@@ -527,21 +627,49 @@ PYBIND11_RUNTIME_EXCEPTION(reference_cast_error, PyExc_RuntimeError) /// Used in
[[noreturn]] PYBIND11_NOINLINE inline void pybind11_fail(const char *reason) { throw std::runtime_error(reason); }
[[noreturn]] PYBIND11_NOINLINE inline void pybind11_fail(const std::string &reason) { throw std::runtime_error(reason); }
-/// Format strings for basic number types
-#define PYBIND11_DECL_FMT(t, v) template<> struct format_descriptor<t> \
- { static constexpr const char* value = v; /* for backwards compatibility */ \
- static std::string format() { return value; } }
-
template <typename T, typename SFINAE = void> struct format_descriptor { };
-template <typename T> struct format_descriptor<T, detail::enable_if_t<std::is_integral<T>::value>> {
- static constexpr const char c = "bBhHiIqQ"[detail::log2(sizeof(T))*2 + std::is_unsigned<T>::value];
+NAMESPACE_BEGIN(detail)
+// Returns the index of the given type in the type char array below, and in the list in numpy.h
+// The order here is: bool; 8 ints ((signed,unsigned)x(8,16,32,64)bits); float,double,long double;
+// complex float,double,long double. Note that the long double types only participate when long
+// double is actually longer than double (it isn't under MSVC).
+// NB: not only the string below but also complex.h and numpy.h rely on this order.
+template <typename T, typename SFINAE = void> struct is_fmt_numeric { static constexpr bool value = false; };
+template <typename T> struct is_fmt_numeric<T, enable_if_t<std::is_arithmetic<T>::value>> {
+ static constexpr bool value = true;
+ static constexpr int index = std::is_same<T, bool>::value ? 0 : 1 + (
+ std::is_integral<T>::value ? detail::log2(sizeof(T))*2 + std::is_unsigned<T>::value : 8 + (
+ std::is_same<T, double>::value ? 1 : std::is_same<T, long double>::value ? 2 : 0));
+};
+NAMESPACE_END(detail)
+
+template <typename T> struct format_descriptor<T, detail::enable_if_t<detail::is_fmt_numeric<T>::value>> {
+ static constexpr const char c = "?bBhHiIqQfdgFDG"[detail::is_fmt_numeric<T>::index];
static constexpr const char value[2] = { c, '\0' };
static std::string format() { return std::string(1, c); }
};
template <typename T> constexpr const char format_descriptor<
- T, detail::enable_if_t<std::is_integral<T>::value>>::value[2];
+ T, detail::enable_if_t<detail::is_fmt_numeric<T>::value>>::value[2];
+
+NAMESPACE_BEGIN(detail)
+
+template <typename T, typename SFINAE = void> struct compare_buffer_info {
+ static bool compare(const buffer_info& b) {
+ return b.format == format_descriptor<T>::format() && b.itemsize == sizeof(T);
+ }
+};
+
+template <typename T> struct compare_buffer_info<T, detail::enable_if_t<std::is_integral<T>::value>> {
+ static bool compare(const buffer_info& b) {
+ return b.itemsize == sizeof(T) && (b.format == format_descriptor<T>::value ||
+ ((sizeof(T) == sizeof(long)) && b.format == (std::is_unsigned<T>::value ? "L" : "l")) ||
+ ((sizeof(T) == sizeof(size_t)) && b.format == (std::is_unsigned<T>::value ? "N" : "n")));
+ }
+};
+
+NAMESPACE_END(detail)
/// RAII wrapper that temporarily clears any Python error state
struct error_scope {
@@ -550,16 +678,11 @@ struct error_scope {
~error_scope() { PyErr_Restore(type, value, trace); }
};
-PYBIND11_DECL_FMT(float, "f");
-PYBIND11_DECL_FMT(double, "d");
-PYBIND11_DECL_FMT(bool, "?");
-
/// Dummy destructor wrapper that can be used to expose classes with a private destructor
struct nodelete { template <typename T> void operator()(T*) { } };
-// overload_cast requires variable templates: C++14 or MSVC 2015 Update 2
-#if defined(PYBIND11_CPP14) || ( \
- defined(_MSC_FULL_VER) &&_MSC_FULL_VER >= 190023918)
+// overload_cast requires variable templates: C++14 or MSVC
+#if defined(PYBIND11_CPP14) || defined(_MSC_VER)
#define PYBIND11_OVERLOAD_CAST 1
NAMESPACE_BEGIN(detail)
diff --git a/ext/pybind11/include/pybind11/complex.h b/ext/pybind11/include/pybind11/complex.h
index f767f354c..945ca0710 100644
--- a/ext/pybind11/include/pybind11/complex.h
+++ b/ext/pybind11/include/pybind11/complex.h
@@ -18,16 +18,21 @@
#endif
NAMESPACE_BEGIN(pybind11)
+NAMESPACE_BEGIN(detail)
-PYBIND11_DECL_FMT(std::complex<float>, "Zf");
-PYBIND11_DECL_FMT(std::complex<double>, "Zd");
+// The format codes are already in the string in common.h, we just need to provide a specialization
+template <typename T> struct is_fmt_numeric<std::complex<T>> {
+ static constexpr bool value = true;
+ static constexpr int index = is_fmt_numeric<T>::index + 3;
+};
-NAMESPACE_BEGIN(detail)
template <typename T> class type_caster<std::complex<T>> {
public:
- bool load(handle src, bool) {
+ bool load(handle src, bool convert) {
if (!src)
return false;
+ if (!convert && !PyComplex_Check(src.ptr()))
+ return false;
Py_complex result = PyComplex_AsCComplex(src.ptr());
if (result.real == -1.0 && PyErr_Occurred()) {
PyErr_Clear();
diff --git a/ext/pybind11/include/pybind11/eigen.h b/ext/pybind11/include/pybind11/eigen.h
index 0a1208e16..6abe8c48f 100644
--- a/ext/pybind11/include/pybind11/eigen.h
+++ b/ext/pybind11/include/pybind11/eigen.h
@@ -17,158 +17,506 @@
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wconversion"
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+# if __GNUC__ >= 7
+# pragma GCC diagnostic ignored "-Wint-in-bool-context"
+# endif
#endif
#include <Eigen/Core>
#include <Eigen/SparseCore>
-#if defined(__GNUG__) || defined(__clang__)
-# pragma GCC diagnostic pop
-#endif
-
#if defined(_MSC_VER)
-#pragma warning(push)
-#pragma warning(disable: 4127) // warning C4127: Conditional expression is constant
+# pragma warning(push)
+# pragma warning(disable: 4127) // warning C4127: Conditional expression is constant
#endif
+// Eigen prior to 3.2.7 doesn't have proper move constructors--but worse, some classes get implicit
+// move constructors that break things. We could detect this an explicitly copy, but an extra copy
+// of matrices seems highly undesirable.
+static_assert(EIGEN_VERSION_AT_LEAST(3,2,7), "Eigen support in pybind11 requires Eigen >= 3.2.7");
+
NAMESPACE_BEGIN(pybind11)
+
+// Provide a convenience alias for easier pass-by-ref usage with fully dynamic strides:
+using EigenDStride = Eigen::Stride<Eigen::Dynamic, Eigen::Dynamic>;
+template <typename MatrixType> using EigenDRef = Eigen::Ref<MatrixType, 0, EigenDStride>;
+template <typename MatrixType> using EigenDMap = Eigen::Map<MatrixType, 0, EigenDStride>;
+
NAMESPACE_BEGIN(detail)
-template <typename T> using is_eigen_dense = is_template_base_of<Eigen::DenseBase, T>;
-template <typename T> using is_eigen_sparse = is_template_base_of<Eigen::SparseMatrixBase, T>;
-template <typename T> using is_eigen_ref = is_template_base_of<Eigen::RefBase, T>;
+#if EIGEN_VERSION_AT_LEAST(3,3,0)
+using EigenIndex = Eigen::Index;
+#else
+using EigenIndex = EIGEN_DEFAULT_DENSE_INDEX_TYPE;
+#endif
+// Matches Eigen::Map, Eigen::Ref, blocks, etc:
+template <typename T> using is_eigen_dense_map = all_of<is_template_base_of<Eigen::DenseBase, T>, std::is_base_of<Eigen::MapBase<T, Eigen::ReadOnlyAccessors>, T>>;
+template <typename T> using is_eigen_mutable_map = std::is_base_of<Eigen::MapBase<T, Eigen::WriteAccessors>, T>;
+template <typename T> using is_eigen_dense_plain = all_of<negation<is_eigen_dense_map<T>>, is_template_base_of<Eigen::PlainObjectBase, T>>;
+template <typename T> using is_eigen_sparse = is_template_base_of<Eigen::SparseMatrixBase, T>;
// Test for objects inheriting from EigenBase<Derived> that aren't captured by the above. This
// basically covers anything that can be assigned to a dense matrix but that don't have a typical
// matrix data layout that can be copied from their .data(). For example, DiagonalMatrix and
// SelfAdjointView fall into this category.
-template <typename T> using is_eigen_base = bool_constant<
- is_template_base_of<Eigen::EigenBase, T>::value
- && !is_eigen_dense<T>::value && !is_eigen_sparse<T>::value
+template <typename T> using is_eigen_other = all_of<
+ is_template_base_of<Eigen::EigenBase, T>,
+ negation<any_of<is_eigen_dense_map<T>, is_eigen_dense_plain<T>, is_eigen_sparse<T>>>
>;
+// Captures numpy/eigen conformability status (returned by EigenProps::conformable()):
+template <bool EigenRowMajor> struct EigenConformable {
+ bool conformable = false;
+ EigenIndex rows = 0, cols = 0;
+ EigenDStride stride{0, 0};
+
+ EigenConformable(bool fits = false) : conformable{fits} {}
+ // Matrix type:
+ EigenConformable(EigenIndex r, EigenIndex c,
+ EigenIndex rstride, EigenIndex cstride) :
+ conformable{true}, rows{r}, cols{c},
+ stride(EigenRowMajor ? rstride : cstride /* outer stride */,
+ EigenRowMajor ? cstride : rstride /* inner stride */)
+ {}
+ // Vector type:
+ EigenConformable(EigenIndex r, EigenIndex c, EigenIndex stride)
+ : EigenConformable(r, c, r == 1 ? c*stride : stride, c == 1 ? r : r*stride) {}
+
+ template <typename props> bool stride_compatible() const {
+ // To have compatible strides, we need (on both dimensions) one of fully dynamic strides,
+ // matching strides, or a dimension size of 1 (in which case the stride value is irrelevant)
+ return
+ (props::inner_stride == Eigen::Dynamic || props::inner_stride == stride.inner() ||
+ (EigenRowMajor ? cols : rows) == 1) &&
+ (props::outer_stride == Eigen::Dynamic || props::outer_stride == stride.outer() ||
+ (EigenRowMajor ? rows : cols) == 1);
+ }
+ operator bool() const { return conformable; }
+};
+
+template <typename Type> struct eigen_extract_stride { using type = Type; };
+template <typename PlainObjectType, int MapOptions, typename StrideType>
+struct eigen_extract_stride<Eigen::Map<PlainObjectType, MapOptions, StrideType>> { using type = StrideType; };
+template <typename PlainObjectType, int Options, typename StrideType>
+struct eigen_extract_stride<Eigen::Ref<PlainObjectType, Options, StrideType>> { using type = StrideType; };
+
+// Helper struct for extracting information from an Eigen type
+template <typename Type_> struct EigenProps {
+ using Type = Type_;
+ using Scalar = typename Type::Scalar;
+ using StrideType = typename eigen_extract_stride<Type>::type;
+ static constexpr EigenIndex
+ rows = Type::RowsAtCompileTime,
+ cols = Type::ColsAtCompileTime,
+ size = Type::SizeAtCompileTime;
+ static constexpr bool
+ row_major = Type::IsRowMajor,
+ vector = Type::IsVectorAtCompileTime, // At least one dimension has fixed size 1
+ fixed_rows = rows != Eigen::Dynamic,
+ fixed_cols = cols != Eigen::Dynamic,
+ fixed = size != Eigen::Dynamic, // Fully-fixed size
+ dynamic = !fixed_rows && !fixed_cols; // Fully-dynamic size
+
+ template <EigenIndex i, EigenIndex ifzero> using if_zero = std::integral_constant<EigenIndex, i == 0 ? ifzero : i>;
+ static constexpr EigenIndex inner_stride = if_zero<StrideType::InnerStrideAtCompileTime, 1>::value,
+ outer_stride = if_zero<StrideType::OuterStrideAtCompileTime,
+ vector ? size : row_major ? cols : rows>::value;
+ static constexpr bool dynamic_stride = inner_stride == Eigen::Dynamic && outer_stride == Eigen::Dynamic;
+ static constexpr bool requires_row_major = !dynamic_stride && !vector && (row_major ? inner_stride : outer_stride) == 1;
+ static constexpr bool requires_col_major = !dynamic_stride && !vector && (row_major ? outer_stride : inner_stride) == 1;
+
+ // Takes an input array and determines whether we can make it fit into the Eigen type. If
+ // the array is a vector, we attempt to fit it into either an Eigen 1xN or Nx1 vector
+ // (preferring the latter if it will fit in either, i.e. for a fully dynamic matrix type).
+ static EigenConformable<row_major> conformable(const array &a) {
+ const auto dims = a.ndim();
+ if (dims < 1 || dims > 2)
+ return false;
+
+ if (dims == 2) { // Matrix type: require exact match (or dynamic)
+
+ EigenIndex
+ np_rows = a.shape(0),
+ np_cols = a.shape(1),
+ np_rstride = a.strides(0) / sizeof(Scalar),
+ np_cstride = a.strides(1) / sizeof(Scalar);
+ if ((fixed_rows && np_rows != rows) || (fixed_cols && np_cols != cols))
+ return false;
+
+ return {np_rows, np_cols, np_rstride, np_cstride};
+ }
+
+ // Otherwise we're storing an n-vector. Only one of the strides will be used, but whichever
+ // is used, we want the (single) numpy stride value.
+ const EigenIndex n = a.shape(0),
+ stride = a.strides(0) / sizeof(Scalar);
+
+ if (vector) { // Eigen type is a compile-time vector
+ if (fixed && size != n)
+ return false; // Vector size mismatch
+ return {rows == 1 ? 1 : n, cols == 1 ? 1 : n, stride};
+ }
+ else if (fixed) {
+ // The type has a fixed size, but is not a vector: abort
+ return false;
+ }
+ else if (fixed_cols) {
+ // Since this isn't a vector, cols must be != 1. We allow this only if it exactly
+ // equals the number of elements (rows is Dynamic, and so 1 row is allowed).
+ if (cols != n) return false;
+ return {1, n, stride};
+ }
+ else {
+ // Otherwise it's either fully dynamic, or column dynamic; both become a column vector
+ if (fixed_rows && rows != n) return false;
+ return {n, 1, stride};
+ }
+ }
+
+ static PYBIND11_DESCR descriptor() {
+ constexpr bool show_writeable = is_eigen_dense_map<Type>::value && is_eigen_mutable_map<Type>::value;
+ constexpr bool show_order = is_eigen_dense_map<Type>::value;
+ constexpr bool show_c_contiguous = show_order && requires_row_major;
+ constexpr bool show_f_contiguous = !show_c_contiguous && show_order && requires_col_major;
+
+ return _("numpy.ndarray[") + npy_format_descriptor<Scalar>::name() +
+ _("[") + _<fixed_rows>(_<(size_t) rows>(), _("m")) +
+ _(", ") + _<fixed_cols>(_<(size_t) cols>(), _("n")) +
+ _("]") +
+ // For a reference type (e.g. Ref<MatrixXd>) we have other constraints that might need to be
+ // satisfied: writeable=True (for a mutable reference), and, depending on the map's stride
+ // options, possibly f_contiguous or c_contiguous. We include them in the descriptor output
+ // to provide some hint as to why a TypeError is occurring (otherwise it can be confusing to
+ // see that a function accepts a 'numpy.ndarray[float64[3,2]]' and an error message that you
+ // *gave* a numpy.ndarray of the right type and dimensions.
+ _<show_writeable>(", flags.writeable", "") +
+ _<show_c_contiguous>(", flags.c_contiguous", "") +
+ _<show_f_contiguous>(", flags.f_contiguous", "") +
+ _("]");
+ }
+};
+
+// Casts an Eigen type to numpy array. If given a base, the numpy array references the src data,
+// otherwise it'll make a copy. writeable lets you turn off the writeable flag for the array.
+template <typename props> handle eigen_array_cast(typename props::Type const &src, handle base = handle(), bool writeable = true) {
+ constexpr size_t elem_size = sizeof(typename props::Scalar);
+ std::vector<size_t> shape, strides;
+ if (props::vector) {
+ shape.push_back(src.size());
+ strides.push_back(elem_size * src.innerStride());
+ }
+ else {
+ shape.push_back(src.rows());
+ shape.push_back(src.cols());
+ strides.push_back(elem_size * src.rowStride());
+ strides.push_back(elem_size * src.colStride());
+ }
+ array a(std::move(shape), std::move(strides), src.data(), base);
+ if (!writeable)
+ array_proxy(a.ptr())->flags &= ~detail::npy_api::NPY_ARRAY_WRITEABLE_;
+
+ return a.release();
+}
+
+// Takes an lvalue ref to some Eigen type and a (python) base object, creating a numpy array that
+// reference the Eigen object's data with `base` as the python-registered base class (if omitted,
+// the base will be set to None, and lifetime management is up to the caller). The numpy array is
+// non-writeable if the given type is const.
+template <typename props, typename Type>
+handle eigen_ref_array(Type &src, handle parent = none()) {
+ // none here is to get past array's should-we-copy detection, which currently always
+ // copies when there is no base. Setting the base to None should be harmless.
+ return eigen_array_cast<props>(src, parent, !std::is_const<Type>::value);
+}
+
+// Takes a pointer to some dense, plain Eigen type, builds a capsule around it, then returns a numpy
+// array that references the encapsulated data with a python-side reference to the capsule to tie
+// its destruction to that of any dependent python objects. Const-ness is determined by whether or
+// not the Type of the pointer given is const.
+template <typename props, typename Type, typename = enable_if_t<is_eigen_dense_plain<Type>::value>>
+handle eigen_encapsulate(Type *src) {
+ capsule base(src, [](void *o) { delete static_cast<Type *>(o); });
+ return eigen_ref_array<props>(*src, base);
+}
+
+// Type caster for regular, dense matrix types (e.g. MatrixXd), but not maps/refs/etc. of dense
+// types.
template<typename Type>
-struct type_caster<Type, enable_if_t<is_eigen_dense<Type>::value && !is_eigen_ref<Type>::value>> {
- typedef typename Type::Scalar Scalar;
- static constexpr bool rowMajor = Type::Flags & Eigen::RowMajorBit;
- static constexpr bool isVector = Type::IsVectorAtCompileTime;
+struct type_caster<Type, enable_if_t<is_eigen_dense_plain<Type>::value>> {
+ using Scalar = typename Type::Scalar;
+ using props = EigenProps<Type>;
bool load(handle src, bool) {
auto buf = array_t<Scalar>::ensure(src);
if (!buf)
return false;
- if (buf.ndim() == 1) {
- typedef Eigen::InnerStride<> Strides;
- if (!isVector &&
- !(Type::RowsAtCompileTime == Eigen::Dynamic &&
- Type::ColsAtCompileTime == Eigen::Dynamic))
- return false;
+ auto dims = buf.ndim();
+ if (dims < 1 || dims > 2)
+ return false;
- if (Type::SizeAtCompileTime != Eigen::Dynamic &&
- buf.shape(0) != (size_t) Type::SizeAtCompileTime)
- return false;
+ auto fits = props::conformable(buf);
+ if (!fits)
+ return false; // Non-comformable vector/matrix types
- Strides::Index n_elts = (Strides::Index) buf.shape(0);
- Strides::Index unity = 1;
+ value = Eigen::Map<const Type, 0, EigenDStride>(buf.data(), fits.rows, fits.cols, fits.stride);
- value = Eigen::Map<Type, 0, Strides>(
- buf.mutable_data(),
- rowMajor ? unity : n_elts,
- rowMajor ? n_elts : unity,
- Strides(buf.strides(0) / sizeof(Scalar))
- );
- } else if (buf.ndim() == 2) {
- typedef Eigen::Stride<Eigen::Dynamic, Eigen::Dynamic> Strides;
+ return true;
+ }
- if ((Type::RowsAtCompileTime != Eigen::Dynamic && buf.shape(0) != (size_t) Type::RowsAtCompileTime) ||
- (Type::ColsAtCompileTime != Eigen::Dynamic && buf.shape(1) != (size_t) Type::ColsAtCompileTime))
- return false;
+private:
+
+ // Cast implementation
+ template <typename CType>
+ static handle cast_impl(CType *src, return_value_policy policy, handle parent) {
+ switch (policy) {
+ case return_value_policy::take_ownership:
+ case return_value_policy::automatic:
+ return eigen_encapsulate<props>(src);
+ case return_value_policy::move:
+ return eigen_encapsulate<props>(new CType(std::move(*src)));
+ case return_value_policy::copy:
+ return eigen_array_cast<props>(*src);
+ case return_value_policy::reference:
+ case return_value_policy::automatic_reference:
+ return eigen_ref_array<props>(*src);
+ case return_value_policy::reference_internal:
+ return eigen_ref_array<props>(*src, parent);
+ default:
+ throw cast_error("unhandled return_value_policy: should not happen!");
+ };
+ }
- value = Eigen::Map<Type, 0, Strides>(
- buf.mutable_data(),
- typename Strides::Index(buf.shape(0)),
- typename Strides::Index(buf.shape(1)),
- Strides(buf.strides(rowMajor ? 0 : 1) / sizeof(Scalar),
- buf.strides(rowMajor ? 1 : 0) / sizeof(Scalar))
- );
- } else {
- return false;
- }
- return true;
+public:
+
+ // Normal returned non-reference, non-const value:
+ static handle cast(Type &&src, return_value_policy /* policy */, handle parent) {
+ return cast_impl(&src, return_value_policy::move, parent);
+ }
+ // If you return a non-reference const, we mark the numpy array readonly:
+ static handle cast(const Type &&src, return_value_policy /* policy */, handle parent) {
+ return cast_impl(&src, return_value_policy::move, parent);
+ }
+ // lvalue reference return; default (automatic) becomes copy
+ static handle cast(Type &src, return_value_policy policy, handle parent) {
+ if (policy == return_value_policy::automatic || policy == return_value_policy::automatic_reference)
+ policy = return_value_policy::copy;
+ return cast_impl(&src, policy, parent);
+ }
+ // const lvalue reference return; default (automatic) becomes copy
+ static handle cast(const Type &src, return_value_policy policy, handle parent) {
+ if (policy == return_value_policy::automatic || policy == return_value_policy::automatic_reference)
+ policy = return_value_policy::copy;
+ return cast(&src, policy, parent);
+ }
+ // non-const pointer return
+ static handle cast(Type *src, return_value_policy policy, handle parent) {
+ return cast_impl(src, policy, parent);
+ }
+ // const pointer return
+ static handle cast(const Type *src, return_value_policy policy, handle parent) {
+ return cast_impl(src, policy, parent);
}
- static handle cast(const Type &src, return_value_policy /* policy */, handle /* parent */) {
- if (isVector) {
- return array(
- { (size_t) src.size() }, // shape
- { sizeof(Scalar) * static_cast<size_t>(src.innerStride()) }, // strides
- src.data() // data
- ).release();
- } else {
- return array(
- { (size_t) src.rows(), // shape
- (size_t) src.cols() },
- { sizeof(Scalar) * static_cast<size_t>(src.rowStride()), // strides
- sizeof(Scalar) * static_cast<size_t>(src.colStride()) },
- src.data() // data
- ).release();
+ static PYBIND11_DESCR name() { return type_descr(props::descriptor()); }
+
+ operator Type*() { return &value; }
+ operator Type&() { return value; }
+ template <typename T> using cast_op_type = cast_op_type<T>;
+
+private:
+ Type value;
+};
+
+// Eigen Ref/Map classes have slightly different policy requirements, meaning we don't want to force
+// `move` when a Ref/Map rvalue is returned; we treat Ref<> sort of like a pointer (we care about
+// the underlying data, not the outer shell).
+template <typename Return>
+struct return_value_policy_override<Return, enable_if_t<is_eigen_dense_map<Return>::value>> {
+ static return_value_policy policy(return_value_policy p) { return p; }
+};
+
+// Base class for casting reference/map/block/etc. objects back to python.
+template <typename MapType> struct eigen_map_caster {
+private:
+ using props = EigenProps<MapType>;
+
+public:
+
+ // Directly referencing a ref/map's data is a bit dangerous (whatever the map/ref points to has
+ // to stay around), but we'll allow it under the assumption that you know what you're doing (and
+ // have an appropriate keep_alive in place). We return a numpy array pointing directly at the
+ // ref's data (The numpy array ends up read-only if the ref was to a const matrix type.) Note
+ // that this means you need to ensure you don't destroy the object in some other way (e.g. with
+ // an appropriate keep_alive, or with a reference to a statically allocated matrix).
+ static handle cast(const MapType &src, return_value_policy policy, handle parent) {
+ switch (policy) {
+ case return_value_policy::copy:
+ return eigen_array_cast<props>(src);
+ case return_value_policy::reference_internal:
+ return eigen_array_cast<props>(src, parent, is_eigen_mutable_map<MapType>::value);
+ case return_value_policy::reference:
+ case return_value_policy::automatic:
+ case return_value_policy::automatic_reference:
+ return eigen_array_cast<props>(src, none(), is_eigen_mutable_map<MapType>::value);
+ default:
+ // move, take_ownership don't make any sense for a ref/map:
+ pybind11_fail("Invalid return_value_policy for Eigen Map/Ref/Block type");
}
}
- PYBIND11_TYPE_CASTER(Type, _("numpy.ndarray[") + npy_format_descriptor<Scalar>::name() +
- _("[") + rows() + _(", ") + cols() + _("]]"));
+ static PYBIND11_DESCR name() { return props::descriptor(); }
-protected:
- template <typename T = Type, enable_if_t<T::RowsAtCompileTime == Eigen::Dynamic, int> = 0>
- static PYBIND11_DESCR rows() { return _("m"); }
- template <typename T = Type, enable_if_t<T::RowsAtCompileTime != Eigen::Dynamic, int> = 0>
- static PYBIND11_DESCR rows() { return _<T::RowsAtCompileTime>(); }
- template <typename T = Type, enable_if_t<T::ColsAtCompileTime == Eigen::Dynamic, int> = 0>
- static PYBIND11_DESCR cols() { return _("n"); }
- template <typename T = Type, enable_if_t<T::ColsAtCompileTime != Eigen::Dynamic, int> = 0>
- static PYBIND11_DESCR cols() { return _<T::ColsAtCompileTime>(); }
+ // Explicitly delete these: support python -> C++ conversion on these (i.e. these can be return
+ // types but not bound arguments). We still provide them (with an explicitly delete) so that
+ // you end up here if you try anyway.
+ bool load(handle, bool) = delete;
+ operator MapType() = delete;
+ template <typename> using cast_op_type = MapType;
};
-// Eigen::Ref<Derived> satisfies is_eigen_dense, but isn't constructable, so it needs a special
-// type_caster to handle argument copying/forwarding.
-template <typename CVDerived, int Options, typename StrideType>
-struct type_caster<Eigen::Ref<CVDerived, Options, StrideType>> {
-protected:
- using Type = Eigen::Ref<CVDerived, Options, StrideType>;
- using Derived = typename std::remove_const<CVDerived>::type;
- using DerivedCaster = type_caster<Derived>;
- DerivedCaster derived_caster;
- std::unique_ptr<Type> value;
+// We can return any map-like object (but can only load Refs, specialized next):
+template <typename Type> struct type_caster<Type, enable_if_t<is_eigen_dense_map<Type>::value>>
+ : eigen_map_caster<Type> {};
+
+// Loader for Ref<...> arguments. See the documentation for info on how to make this work without
+// copying (it requires some extra effort in many cases).
+template <typename PlainObjectType, typename StrideType>
+struct type_caster<
+ Eigen::Ref<PlainObjectType, 0, StrideType>,
+ enable_if_t<is_eigen_dense_map<Eigen::Ref<PlainObjectType, 0, StrideType>>::value>
+> : public eigen_map_caster<Eigen::Ref<PlainObjectType, 0, StrideType>> {
+private:
+ using Type = Eigen::Ref<PlainObjectType, 0, StrideType>;
+ using props = EigenProps<Type>;
+ using Scalar = typename props::Scalar;
+ using MapType = Eigen::Map<PlainObjectType, 0, StrideType>;
+ using Array = array_t<Scalar, array::forcecast |
+ ((props::row_major ? props::inner_stride : props::outer_stride) == 1 ? array::c_style :
+ (props::row_major ? props::outer_stride : props::inner_stride) == 1 ? array::f_style : 0)>;
+ static constexpr bool need_writeable = is_eigen_mutable_map<Type>::value;
+ // Delay construction (these have no default constructor)
+ std::unique_ptr<MapType> map;
+ std::unique_ptr<Type> ref;
+ // Our array. When possible, this is just a numpy array pointing to the source data, but
+ // sometimes we can't avoid copying (e.g. input is not a numpy array at all, has an incompatible
+ // layout, or is an array of a type that needs to be converted). Using a numpy temporary
+ // (rather than an Eigen temporary) saves an extra copy when we need both type conversion and
+ // storage order conversion. (Note that we refuse to use this temporary copy when loading an
+ // argument for a Ref<M> with M non-const, i.e. a read-write reference).
+ Array copy_or_ref;
public:
- bool load(handle src, bool convert) { if (derived_caster.load(src, convert)) { value.reset(new Type(derived_caster.operator Derived&())); return true; } return false; }
- static handle cast(const Type &src, return_value_policy policy, handle parent) { return DerivedCaster::cast(src, policy, parent); }
- static handle cast(const Type *src, return_value_policy policy, handle parent) { return DerivedCaster::cast(*src, policy, parent); }
+ bool load(handle src, bool convert) {
+ // First check whether what we have is already an array of the right type. If not, we can't
+ // avoid a copy (because the copy is also going to do type conversion).
+ bool need_copy = !isinstance<Array>(src);
+
+ EigenConformable<props::row_major> fits;
+ if (!need_copy) {
+ // We don't need a converting copy, but we also need to check whether the strides are
+ // compatible with the Ref's stride requirements
+ Array aref = reinterpret_borrow<Array>(src);
+
+ if (aref && (!need_writeable || aref.writeable())) {
+ fits = props::conformable(aref);
+ if (!fits) return false; // Incompatible dimensions
+ if (!fits.template stride_compatible<props>())
+ need_copy = true;
+ else
+ copy_or_ref = std::move(aref);
+ }
+ else {
+ need_copy = true;
+ }
+ }
+
+ if (need_copy) {
+ // We need to copy: If we need a mutable reference, or we're not supposed to convert
+ // (either because we're in the no-convert overload pass, or because we're explicitly
+ // instructed not to copy (via `py::arg().noconvert()`) we have to fail loading.
+ if (!convert || need_writeable) return false;
+
+ Array copy = Array::ensure(src);
+ if (!copy) return false;
+ fits = props::conformable(copy);
+ if (!fits || !fits.template stride_compatible<props>())
+ return false;
+ copy_or_ref = std::move(copy);
+ }
+
+ ref.reset();
+ map.reset(new MapType(data(copy_or_ref), fits.rows, fits.cols, make_stride(fits.stride.outer(), fits.stride.inner())));
+ ref.reset(new Type(*map));
- static PYBIND11_DESCR name() { return DerivedCaster::name(); }
+ return true;
+ }
- operator Type*() { return value.get(); }
- operator Type&() { if (!value) pybind11_fail("Eigen::Ref<...> value not loaded"); return *value; }
+ operator Type*() { return ref.get(); }
+ operator Type&() { return *ref; }
template <typename _T> using cast_op_type = pybind11::detail::cast_op_type<_T>;
+
+private:
+ template <typename T = Type, enable_if_t<is_eigen_mutable_map<T>::value, int> = 0>
+ Scalar *data(Array &a) { return a.mutable_data(); }
+
+ template <typename T = Type, enable_if_t<!is_eigen_mutable_map<T>::value, int> = 0>
+ const Scalar *data(Array &a) { return a.data(); }
+
+ // Attempt to figure out a constructor of `Stride` that will work.
+ // If both strides are fixed, use a default constructor:
+ template <typename S> using stride_ctor_default = bool_constant<
+ S::InnerStrideAtCompileTime != Eigen::Dynamic && S::OuterStrideAtCompileTime != Eigen::Dynamic &&
+ std::is_default_constructible<S>::value>;
+ // Otherwise, if there is a two-index constructor, assume it is (outer,inner) like
+ // Eigen::Stride, and use it:
+ template <typename S> using stride_ctor_dual = bool_constant<
+ !stride_ctor_default<S>::value && std::is_constructible<S, EigenIndex, EigenIndex>::value>;
+ // Otherwise, if there is a one-index constructor, and just one of the strides is dynamic, use
+ // it (passing whichever stride is dynamic).
+ template <typename S> using stride_ctor_outer = bool_constant<
+ !any_of<stride_ctor_default<S>, stride_ctor_dual<S>>::value &&
+ S::OuterStrideAtCompileTime == Eigen::Dynamic && S::InnerStrideAtCompileTime != Eigen::Dynamic &&
+ std::is_constructible<S, EigenIndex>::value>;
+ template <typename S> using stride_ctor_inner = bool_constant<
+ !any_of<stride_ctor_default<S>, stride_ctor_dual<S>>::value &&
+ S::InnerStrideAtCompileTime == Eigen::Dynamic && S::OuterStrideAtCompileTime != Eigen::Dynamic &&
+ std::is_constructible<S, EigenIndex>::value>;
+
+ template <typename S = StrideType, enable_if_t<stride_ctor_default<S>::value, int> = 0>
+ static S make_stride(EigenIndex, EigenIndex) { return S(); }
+ template <typename S = StrideType, enable_if_t<stride_ctor_dual<S>::value, int> = 0>
+ static S make_stride(EigenIndex outer, EigenIndex inner) { return S(outer, inner); }
+ template <typename S = StrideType, enable_if_t<stride_ctor_outer<S>::value, int> = 0>
+ static S make_stride(EigenIndex outer, EigenIndex) { return S(outer); }
+ template <typename S = StrideType, enable_if_t<stride_ctor_inner<S>::value, int> = 0>
+ static S make_stride(EigenIndex, EigenIndex inner) { return S(inner); }
+
};
-// type_caster for special matrix types (e.g. DiagonalMatrix): load() is not supported, but we can
-// cast them into the python domain by first copying to a regular Eigen::Matrix, then casting that.
+// type_caster for special matrix types (e.g. DiagonalMatrix), which are EigenBase, but not
+// EigenDense (i.e. they don't have a data(), at least not with the usual matrix layout).
+// load() is not supported, but we can cast them into the python domain by first copying to a
+// regular Eigen::Matrix, then casting that.
template <typename Type>
-struct type_caster<Type, enable_if_t<is_eigen_base<Type>::value && !is_eigen_ref<Type>::value>> {
+struct type_caster<Type, enable_if_t<is_eigen_other<Type>::value>> {
protected:
- using Matrix = Eigen::Matrix<typename Type::Scalar, Eigen::Dynamic, Eigen::Dynamic>;
- using MatrixCaster = type_caster<Matrix>;
+ using Matrix = Eigen::Matrix<typename Type::Scalar, Type::RowsAtCompileTime, Type::ColsAtCompileTime>;
+ using props = EigenProps<Matrix>;
public:
- [[noreturn]] bool load(handle, bool) { pybind11_fail("Unable to load() into specialized EigenBase object"); }
- static handle cast(const Type &src, return_value_policy policy, handle parent) { return MatrixCaster::cast(Matrix(src), policy, parent); }
- static handle cast(const Type *src, return_value_policy policy, handle parent) { return MatrixCaster::cast(Matrix(*src), policy, parent); }
+ static handle cast(const Type &src, return_value_policy /* policy */, handle /* parent */) {
+ handle h = eigen_encapsulate<props>(new Matrix(src));
+ return h;
+ }
+ static handle cast(const Type *src, return_value_policy policy, handle parent) { return cast(*src, policy, parent); }
- static PYBIND11_DESCR name() { return MatrixCaster::name(); }
+ static PYBIND11_DESCR name() { return props::descriptor(); }
- [[noreturn]] operator Type*() { pybind11_fail("Loading not supported for specialized EigenBase object"); }
- [[noreturn]] operator Type&() { pybind11_fail("Loading not supported for specialized EigenBase object"); }
- template <typename _T> using cast_op_type = pybind11::detail::cast_op_type<_T>;
+ // Explicitly delete these: support python -> C++ conversion on these (i.e. these can be return
+ // types but not bound arguments). We still provide them (with an explicitly delete) so that
+ // you end up here if you try anyway.
+ bool load(handle, bool) = delete;
+ operator Type() = delete;
+ template <typename> using cast_op_type = Type;
};
template<typename Type>
@@ -176,7 +524,7 @@ struct type_caster<Type, enable_if_t<is_eigen_sparse<Type>::value>> {
typedef typename Type::Scalar Scalar;
typedef typename std::remove_reference<decltype(*std::declval<Type>().outerIndexPtr())>::type StorageIndex;
typedef typename Type::Index Index;
- static constexpr bool rowMajor = Type::Flags & Eigen::RowMajorBit;
+ static constexpr bool rowMajor = Type::IsRowMajor;
bool load(handle src, bool) {
if (!src)
@@ -227,13 +575,15 @@ struct type_caster<Type, enable_if_t<is_eigen_sparse<Type>::value>> {
).release();
}
- PYBIND11_TYPE_CASTER(Type, _<(Type::Flags & Eigen::RowMajorBit) != 0>("scipy.sparse.csr_matrix[", "scipy.sparse.csc_matrix[")
+ PYBIND11_TYPE_CASTER(Type, _<(Type::IsRowMajor) != 0>("scipy.sparse.csr_matrix[", "scipy.sparse.csc_matrix[")
+ npy_format_descriptor<Scalar>::name() + _("]"));
};
NAMESPACE_END(detail)
NAMESPACE_END(pybind11)
-#if defined(_MSC_VER)
-#pragma warning(pop)
+#if defined(__GNUG__) || defined(__clang__)
+# pragma GCC diagnostic pop
+#elif defined(_MSC_VER)
+# pragma warning(pop)
#endif
diff --git a/ext/pybind11/include/pybind11/eval.h b/ext/pybind11/include/pybind11/eval.h
index 204427d77..5b2b98272 100644
--- a/ext/pybind11/include/pybind11/eval.h
+++ b/ext/pybind11/include/pybind11/eval.h
@@ -95,8 +95,15 @@ object eval_file(str fname, object global = object(), object local = object()) {
pybind11_fail("File \"" + fname_str + "\" could not be opened!");
}
+#if PY_VERSION_HEX < 0x03000000 && defined(PYPY_VERSION)
+ PyObject *result = PyRun_File(f, fname_str.c_str(), start, global.ptr(),
+ local.ptr());
+ (void) closeFile;
+#else
PyObject *result = PyRun_FileEx(f, fname_str.c_str(), start, global.ptr(),
local.ptr(), closeFile);
+#endif
+
if (!result)
throw error_already_set();
return reinterpret_steal<object>(result);
diff --git a/ext/pybind11/include/pybind11/functional.h b/ext/pybind11/include/pybind11/functional.h
index f1b0ebbbf..a99ee737f 100644
--- a/ext/pybind11/include/pybind11/functional.h
+++ b/ext/pybind11/include/pybind11/functional.h
@@ -15,9 +15,12 @@
NAMESPACE_BEGIN(pybind11)
NAMESPACE_BEGIN(detail)
-template <typename Return, typename... Args> struct type_caster<std::function<Return(Args...)>> {
- typedef std::function<Return(Args...)> type;
- typedef typename std::conditional<std::is_same<Return, void>::value, void_type, Return>::type retval_type;
+template <typename Return, typename... Args>
+struct type_caster<std::function<Return(Args...)>> {
+ using type = std::function<Return(Args...)>;
+ using retval_type = conditional_t<std::is_same<Return, void>::value, void_type, Return>;
+ using function_type = Return (*) (Args...);
+
public:
bool load(handle src_, bool) {
if (src_.is_none())
@@ -36,12 +39,11 @@ public:
captured variables), in which case the roundtrip can be avoided.
*/
if (PyCFunction_Check(src_.ptr())) {
- auto c = reinterpret_borrow<capsule>(PyCFunction_GetSelf(src_.ptr()));
+ auto c = reinterpret_borrow<capsule>(PyCFunction_GET_SELF(src_.ptr()));
auto rec = (function_record *) c;
- using FunctionType = Return (*) (Args...);
- if (rec && rec->is_stateless && rec->data[1] == &typeid(FunctionType)) {
- struct capture { FunctionType f; };
+ if (rec && rec->is_stateless && rec->data[1] == &typeid(function_type)) {
+ struct capture { function_type f; };
value = ((capture *) &rec->data)->f;
return true;
}
@@ -50,7 +52,7 @@ public:
auto src = reinterpret_borrow<object>(src_);
value = [src](Args... args) -> Return {
gil_scoped_acquire acq;
- object retval(src(std::move(args)...));
+ object retval(src(std::forward<Args>(args)...));
/* Visual studio 2015 parser issue: need parentheses around this expression */
return (retval.template cast<Return>());
};
@@ -62,7 +64,7 @@ public:
if (!f_)
return none().inc_ref();
- auto result = f_.template target<Return (*)(Args...)>();
+ auto result = f_.template target<function_type>();
if (result)
return cpp_function(*result, policy).release();
else
@@ -71,7 +73,7 @@ public:
PYBIND11_TYPE_CASTER(type, _("Callable[[") +
argument_loader<Args...>::arg_names() + _("], ") +
- type_caster<retval_type>::name() +
+ make_caster<retval_type>::name() +
_("]"));
};
diff --git a/ext/pybind11/include/pybind11/numpy.h b/ext/pybind11/include/pybind11/numpy.h
index e6f4efdf9..3227a12eb 100644
--- a/ext/pybind11/include/pybind11/numpy.h
+++ b/ext/pybind11/include/pybind11/numpy.h
@@ -35,9 +35,11 @@
static_assert(sizeof(size_t) == sizeof(Py_intptr_t), "size_t != Py_intptr_t");
NAMESPACE_BEGIN(pybind11)
+
+class array; // Forward declaration
+
NAMESPACE_BEGIN(detail)
-template <typename type, typename SFINAE = void> struct npy_format_descriptor { };
-template <typename type> struct is_pod_struct;
+template <typename type, typename SFINAE = void> struct npy_format_descriptor;
struct PyArrayDescr_Proxy {
PyObject_HEAD
@@ -108,11 +110,11 @@ inline numpy_internals& get_numpy_internals() {
struct npy_api {
enum constants {
- NPY_C_CONTIGUOUS_ = 0x0001,
- NPY_F_CONTIGUOUS_ = 0x0002,
+ NPY_ARRAY_C_CONTIGUOUS_ = 0x0001,
+ NPY_ARRAY_F_CONTIGUOUS_ = 0x0002,
NPY_ARRAY_OWNDATA_ = 0x0004,
NPY_ARRAY_FORCECAST_ = 0x0010,
- NPY_ENSURE_ARRAY_ = 0x0040,
+ NPY_ARRAY_ENSUREARRAY_ = 0x0040,
NPY_ARRAY_ALIGNED_ = 0x0100,
NPY_ARRAY_WRITEABLE_ = 0x0400,
NPY_BOOL_ = 0,
@@ -155,6 +157,7 @@ struct npy_api {
int (*PyArray_GetArrayParamsFromObject_)(PyObject *, PyObject *, char, PyObject **, int *,
Py_ssize_t *, PyObject **, PyObject *);
PyObject *(*PyArray_Squeeze_)(PyObject *);
+ int (*PyArray_SetBaseObject_)(PyObject *, PyObject *);
private:
enum functions {
API_PyArray_Type = 2,
@@ -169,7 +172,8 @@ private:
API_PyArray_DescrConverter = 174,
API_PyArray_EquivTypes = 182,
API_PyArray_GetArrayParamsFromObject = 278,
- API_PyArray_Squeeze = 136
+ API_PyArray_Squeeze = 136,
+ API_PyArray_SetBaseObject = 282
};
static npy_api lookup() {
@@ -195,6 +199,7 @@ private:
DECL_NPY_API(PyArray_EquivTypes);
DECL_NPY_API(PyArray_GetArrayParamsFromObject);
DECL_NPY_API(PyArray_Squeeze);
+ DECL_NPY_API(PyArray_SetBaseObject);
#undef DECL_NPY_API
return api;
}
@@ -220,6 +225,128 @@ inline bool check_flags(const void* ptr, int flag) {
return (flag == (array_proxy(ptr)->flags & flag));
}
+template <typename T> struct is_std_array : std::false_type { };
+template <typename T, size_t N> struct is_std_array<std::array<T, N>> : std::true_type { };
+template <typename T> struct is_complex : std::false_type { };
+template <typename T> struct is_complex<std::complex<T>> : std::true_type { };
+
+template <typename T> using is_pod_struct = all_of<
+ std::is_pod<T>, // since we're accessing directly in memory we need a POD type
+ satisfies_none_of<T, std::is_reference, std::is_array, is_std_array, std::is_arithmetic, is_complex, std::is_enum>
+>;
+
+template <size_t Dim = 0, typename Strides> size_t byte_offset_unsafe(const Strides &) { return 0; }
+template <size_t Dim = 0, typename Strides, typename... Ix>
+size_t byte_offset_unsafe(const Strides &strides, size_t i, Ix... index) {
+ return i * strides[Dim] + byte_offset_unsafe<Dim + 1>(strides, index...);
+}
+
+/** Proxy class providing unsafe, unchecked const access to array data. This is constructed through
+ * the `unchecked<T, N>()` method of `array` or the `unchecked<N>()` method of `array_t<T>`. `Dims`
+ * will be -1 for dimensions determined at runtime.
+ */
+template <typename T, ssize_t Dims>
+class unchecked_reference {
+protected:
+ static constexpr bool Dynamic = Dims < 0;
+ const unsigned char *data_;
+ // Storing the shape & strides in local variables (i.e. these arrays) allows the compiler to
+ // make large performance gains on big, nested loops, but requires compile-time dimensions
+ conditional_t<Dynamic, const size_t *, std::array<size_t, (size_t) Dims>>
+ shape_, strides_;
+ const size_t dims_;
+
+ friend class pybind11::array;
+ // Constructor for compile-time dimensions:
+ template <bool Dyn = Dynamic>
+ unchecked_reference(const void *data, const size_t *shape, const size_t *strides, enable_if_t<!Dyn, size_t>)
+ : data_{reinterpret_cast<const unsigned char *>(data)}, dims_{Dims} {
+ for (size_t i = 0; i < dims_; i++) {
+ shape_[i] = shape[i];
+ strides_[i] = strides[i];
+ }
+ }
+ // Constructor for runtime dimensions:
+ template <bool Dyn = Dynamic>
+ unchecked_reference(const void *data, const size_t *shape, const size_t *strides, enable_if_t<Dyn, size_t> dims)
+ : data_{reinterpret_cast<const unsigned char *>(data)}, shape_{shape}, strides_{strides}, dims_{dims} {}
+
+public:
+ /** Unchecked const reference access to data at the given indices. For a compile-time known
+ * number of dimensions, this requires the correct number of arguments; for run-time
+ * dimensionality, this is not checked (and so is up to the caller to use safely).
+ */
+ template <typename... Ix> const T &operator()(Ix... index) const {
+ static_assert(sizeof...(Ix) == Dims || Dynamic,
+ "Invalid number of indices for unchecked array reference");
+ return *reinterpret_cast<const T *>(data_ + byte_offset_unsafe(strides_, size_t(index)...));
+ }
+ /** Unchecked const reference access to data; this operator only participates if the reference
+ * is to a 1-dimensional array. When present, this is exactly equivalent to `obj(index)`.
+ */
+ template <size_t D = Dims, typename = enable_if_t<D == 1 || Dynamic>>
+ const T &operator[](size_t index) const { return operator()(index); }
+
+ /// Pointer access to the data at the given indices.
+ template <typename... Ix> const T *data(Ix... ix) const { return &operator()(size_t(ix)...); }
+
+ /// Returns the item size, i.e. sizeof(T)
+ constexpr static size_t itemsize() { return sizeof(T); }
+
+ /// Returns the shape (i.e. size) of dimension `dim`
+ size_t shape(size_t dim) const { return shape_[dim]; }
+
+ /// Returns the number of dimensions of the array
+ size_t ndim() const { return dims_; }
+
+ /// Returns the total number of elements in the referenced array, i.e. the product of the shapes
+ template <bool Dyn = Dynamic>
+ enable_if_t<!Dyn, size_t> size() const {
+ return std::accumulate(shape_.begin(), shape_.end(), (size_t) 1, std::multiplies<size_t>());
+ }
+ template <bool Dyn = Dynamic>
+ enable_if_t<Dyn, size_t> size() const {
+ return std::accumulate(shape_, shape_ + ndim(), (size_t) 1, std::multiplies<size_t>());
+ }
+
+ /// Returns the total number of bytes used by the referenced data. Note that the actual span in
+ /// memory may be larger if the referenced array has non-contiguous strides (e.g. for a slice).
+ size_t nbytes() const {
+ return size() * itemsize();
+ }
+};
+
+template <typename T, ssize_t Dims>
+class unchecked_mutable_reference : public unchecked_reference<T, Dims> {
+ friend class pybind11::array;
+ using ConstBase = unchecked_reference<T, Dims>;
+ using ConstBase::ConstBase;
+ using ConstBase::Dynamic;
+public:
+ /// Mutable, unchecked access to data at the given indices.
+ template <typename... Ix> T& operator()(Ix... index) {
+ static_assert(sizeof...(Ix) == Dims || Dynamic,
+ "Invalid number of indices for unchecked array reference");
+ return const_cast<T &>(ConstBase::operator()(index...));
+ }
+ /** Mutable, unchecked access data at the given index; this operator only participates if the
+ * reference is to a 1-dimensional array (or has runtime dimensions). When present, this is
+ * exactly equivalent to `obj(index)`.
+ */
+ template <size_t D = Dims, typename = enable_if_t<D == 1 || Dynamic>>
+ T &operator[](size_t index) { return operator()(index); }
+
+ /// Mutable pointer access to the data at the given indices.
+ template <typename... Ix> T *mutable_data(Ix... ix) { return &operator()(size_t(ix)...); }
+};
+
+template <typename T, size_t Dim>
+struct type_caster<unchecked_reference<T, Dim>> {
+ static_assert(Dim == 0 && Dim > 0 /* always fail */, "unchecked array proxy object is not castable");
+};
+template <typename T, size_t Dim>
+struct type_caster<unchecked_mutable_reference<T, Dim>> : type_caster<unchecked_reference<T, Dim>> {};
+
NAMESPACE_END(detail)
class dtype : public object {
@@ -321,8 +448,8 @@ public:
PYBIND11_OBJECT_CVT(array, buffer, detail::npy_api::get().PyArray_Check_, raw_array)
enum {
- c_style = detail::npy_api::NPY_C_CONTIGUOUS_,
- f_style = detail::npy_api::NPY_F_CONTIGUOUS_,
+ c_style = detail::npy_api::NPY_ARRAY_C_CONTIGUOUS_,
+ f_style = detail::npy_api::NPY_ARRAY_F_CONTIGUOUS_,
forcecast = detail::npy_api::NPY_ARRAY_FORCECAST_
};
@@ -340,7 +467,7 @@ public:
int flags = 0;
if (base && ptr) {
if (isinstance<array>(base))
- /* Copy flags from base (except baseship bit) */
+ /* Copy flags from base (except ownership bit) */
flags = reinterpret_borrow<array>(base).flags() & ~detail::npy_api::NPY_ARRAY_OWNDATA_;
else
/* Writable by default, easy to downgrade later on if needed */
@@ -348,13 +475,15 @@ public:
}
auto tmp = reinterpret_steal<object>(api.PyArray_NewFromDescr_(
- api.PyArray_Type_, descr.release().ptr(), (int) ndim, (Py_intptr_t *) shape.data(),
- (Py_intptr_t *) strides.data(), const_cast<void *>(ptr), flags, nullptr));
+ api.PyArray_Type_, descr.release().ptr(), (int) ndim,
+ reinterpret_cast<Py_intptr_t *>(const_cast<size_t*>(shape.data())),
+ reinterpret_cast<Py_intptr_t *>(const_cast<size_t*>(strides.data())),
+ const_cast<void *>(ptr), flags, nullptr));
if (!tmp)
pybind11_fail("NumPy: unable to create array!");
if (ptr) {
if (base) {
- detail::array_proxy(tmp.ptr())->base = base.inc_ref().ptr();
+ api.PyArray_SetBaseObject_(tmp.ptr(), base.inc_ref().ptr());
} else {
tmp = reinterpret_steal<object>(api.PyArray_NewCopy_(tmp.ptr(), -1 /* any order */));
}
@@ -373,7 +502,7 @@ public:
template<typename T> array(const std::vector<size_t>& shape,
const std::vector<size_t>& strides,
const T* ptr, handle base = handle())
- : array(pybind11::dtype::of<T>(), shape, strides, (void *) ptr, base) { }
+ : array(pybind11::dtype::of<T>(), shape, strides, (const void *) ptr, base) { }
template <typename T>
array(const std::vector<size_t> &shape, const T *ptr,
@@ -486,6 +615,31 @@ public:
return offset_at(index...) / itemsize();
}
+ /** Returns a proxy object that provides access to the array's data without bounds or
+ * dimensionality checking. Will throw if the array is missing the `writeable` flag. Use with
+ * care: the array must not be destroyed or reshaped for the duration of the returned object,
+ * and the caller must take care not to access invalid dimensions or dimension indices.
+ */
+ template <typename T, ssize_t Dims = -1> detail::unchecked_mutable_reference<T, Dims> mutable_unchecked() {
+ if (Dims >= 0 && ndim() != (size_t) Dims)
+ throw std::domain_error("array has incorrect number of dimensions: " + std::to_string(ndim()) +
+ "; expected " + std::to_string(Dims));
+ return detail::unchecked_mutable_reference<T, Dims>(mutable_data(), shape(), strides(), ndim());
+ }
+
+ /** Returns a proxy object that provides const access to the array's data without bounds or
+ * dimensionality checking. Unlike `mutable_unchecked()`, this does not require that the
+ * underlying array have the `writable` flag. Use with care: the array must not be destroyed or
+ * reshaped for the duration of the returned object, and the caller must take care not to access
+ * invalid dimensions or dimension indices.
+ */
+ template <typename T, ssize_t Dims = -1> detail::unchecked_reference<T, Dims> unchecked() const {
+ if (Dims >= 0 && ndim() != (size_t) Dims)
+ throw std::domain_error("array has incorrect number of dimensions: " + std::to_string(ndim()) +
+ "; expected " + std::to_string(Dims));
+ return detail::unchecked_reference<T, Dims>(data(), shape(), strides(), ndim());
+ }
+
/// Return a new view with all of the dimensions of length 1 removed
array squeeze() {
auto& api = detail::npy_api::get();
@@ -511,18 +665,12 @@ protected:
template<typename... Ix> size_t byte_offset(Ix... index) const {
check_dimensions(index...);
- return byte_offset_unsafe(index...);
- }
-
- template<size_t dim = 0, typename... Ix> size_t byte_offset_unsafe(size_t i, Ix... index) const {
- return i * strides()[dim] + byte_offset_unsafe<dim + 1>(index...);
+ return detail::byte_offset_unsafe(strides(), size_t(index)...);
}
- template<size_t dim = 0> size_t byte_offset_unsafe() const { return 0; }
-
void check_writeable() const {
if (!writeable())
- throw std::runtime_error("array is not writeable");
+ throw std::domain_error("array is not writeable");
}
static std::vector<size_t> default_strides(const std::vector<size_t>& shape, size_t itemsize) {
@@ -557,12 +705,14 @@ protected:
if (ptr == nullptr)
return nullptr;
return detail::npy_api::get().PyArray_FromAny_(
- ptr, nullptr, 0, 0, detail::npy_api::NPY_ENSURE_ARRAY_ | ExtraFlags, nullptr);
+ ptr, nullptr, 0, 0, detail::npy_api::NPY_ARRAY_ENSUREARRAY_ | ExtraFlags, nullptr);
}
};
template <typename T, int ExtraFlags = array::forcecast> class array_t : public array {
public:
+ using value_type = T;
+
array_t() : array(0, static_cast<const T *>(nullptr)) {}
array_t(handle h, borrowed_t) : array(h, borrowed) { }
array_t(handle h, stolen_t) : array(h, stolen) { }
@@ -621,8 +771,27 @@ public:
return *(static_cast<T*>(array::mutable_data()) + byte_offset(size_t(index)...) / itemsize());
}
- /// Ensure that the argument is a NumPy array of the correct dtype.
- /// In case of an error, nullptr is returned and the Python error is cleared.
+ /** Returns a proxy object that provides access to the array's data without bounds or
+ * dimensionality checking. Will throw if the array is missing the `writeable` flag. Use with
+ * care: the array must not be destroyed or reshaped for the duration of the returned object,
+ * and the caller must take care not to access invalid dimensions or dimension indices.
+ */
+ template <ssize_t Dims = -1> detail::unchecked_mutable_reference<T, Dims> mutable_unchecked() {
+ return array::mutable_unchecked<T, Dims>();
+ }
+
+ /** Returns a proxy object that provides const access to the array's data without bounds or
+ * dimensionality checking. Unlike `unchecked()`, this does not require that the underlying
+ * array have the `writable` flag. Use with care: the array must not be destroyed or reshaped
+ * for the duration of the returned object, and the caller must take care not to access invalid
+ * dimensions or dimension indices.
+ */
+ template <ssize_t Dims = -1> detail::unchecked_reference<T, Dims> unchecked() const {
+ return array::unchecked<T, Dims>();
+ }
+
+ /// Ensure that the argument is a NumPy array of the correct dtype (and if not, try to convert
+ /// it). In case of an error, nullptr is returned and the Python error is cleared.
static array_t ensure(handle h) {
auto result = reinterpret_steal<array_t>(raw_array_t(h.ptr()));
if (!result)
@@ -630,7 +799,7 @@ public:
return result;
}
- static bool _check(handle h) {
+ static bool check_(handle h) {
const auto &api = detail::npy_api::get();
return api.PyArray_Check_(h.ptr())
&& api.PyArray_EquivTypes_(detail::array_proxy(h.ptr())->descr, dtype::of<T>().ptr());
@@ -643,7 +812,7 @@ protected:
return nullptr;
return detail::npy_api::get().PyArray_FromAny_(
ptr, dtype::of<T>().release().ptr(), 0, 0,
- detail::npy_api::NPY_ENSURE_ARRAY_ | ExtraFlags, nullptr);
+ detail::npy_api::NPY_ARRAY_ENSUREARRAY_ | ExtraFlags, nullptr);
}
};
@@ -674,7 +843,9 @@ template <typename T, int ExtraFlags>
struct pyobject_caster<array_t<T, ExtraFlags>> {
using type = array_t<T, ExtraFlags>;
- bool load(handle src, bool /* convert */) {
+ bool load(handle src, bool convert) {
+ if (!convert && !type::check_(src))
+ return false;
value = type::ensure(src);
return static_cast<bool>(value);
}
@@ -685,65 +856,55 @@ struct pyobject_caster<array_t<T, ExtraFlags>> {
PYBIND11_TYPE_CASTER(type, handle_type_name<type>::name());
};
-template <typename T> struct is_std_array : std::false_type { };
-template <typename T, size_t N> struct is_std_array<std::array<T, N>> : std::true_type { };
-
template <typename T>
-struct is_pod_struct {
- enum { value = std::is_pod<T>::value && // offsetof only works correctly for POD types
- !std::is_reference<T>::value &&
- !std::is_array<T>::value &&
- !is_std_array<T>::value &&
- !std::is_integral<T>::value &&
- !std::is_enum<T>::value &&
- !std::is_same<typename std::remove_cv<T>::type, float>::value &&
- !std::is_same<typename std::remove_cv<T>::type, double>::value &&
- !std::is_same<typename std::remove_cv<T>::type, bool>::value &&
- !std::is_same<typename std::remove_cv<T>::type, std::complex<float>>::value &&
- !std::is_same<typename std::remove_cv<T>::type, std::complex<double>>::value };
+struct compare_buffer_info<T, detail::enable_if_t<detail::is_pod_struct<T>::value>> {
+ static bool compare(const buffer_info& b) {
+ return npy_api::get().PyArray_EquivTypes_(dtype::of<T>().ptr(), dtype(b).ptr());
+ }
};
-template <typename T> struct npy_format_descriptor<T, enable_if_t<std::is_integral<T>::value>> {
+template <typename T> struct npy_format_descriptor<T, enable_if_t<satisfies_any_of<T, std::is_arithmetic, is_complex>::value>> {
private:
- constexpr static const int values[8] = {
- npy_api::NPY_BYTE_, npy_api::NPY_UBYTE_, npy_api::NPY_SHORT_, npy_api::NPY_USHORT_,
- npy_api::NPY_INT_, npy_api::NPY_UINT_, npy_api::NPY_LONGLONG_, npy_api::NPY_ULONGLONG_ };
+ // NB: the order here must match the one in common.h
+ constexpr static const int values[15] = {
+ npy_api::NPY_BOOL_,
+ npy_api::NPY_BYTE_, npy_api::NPY_UBYTE_, npy_api::NPY_SHORT_, npy_api::NPY_USHORT_,
+ npy_api::NPY_INT_, npy_api::NPY_UINT_, npy_api::NPY_LONGLONG_, npy_api::NPY_ULONGLONG_,
+ npy_api::NPY_FLOAT_, npy_api::NPY_DOUBLE_, npy_api::NPY_LONGDOUBLE_,
+ npy_api::NPY_CFLOAT_, npy_api::NPY_CDOUBLE_, npy_api::NPY_CLONGDOUBLE_
+ };
+
public:
- enum { value = values[detail::log2(sizeof(T)) * 2 + (std::is_unsigned<T>::value ? 1 : 0)] };
+ static constexpr int value = values[detail::is_fmt_numeric<T>::index];
+
static pybind11::dtype dtype() {
if (auto ptr = npy_api::get().PyArray_DescrFromType_(value))
return reinterpret_borrow<pybind11::dtype>(ptr);
pybind11_fail("Unsupported buffer format!");
}
- template <typename T2 = T, enable_if_t<std::is_signed<T2>::value, int> = 0>
- static PYBIND11_DESCR name() { return _("int") + _<sizeof(T)*8>(); }
- template <typename T2 = T, enable_if_t<!std::is_signed<T2>::value, int> = 0>
- static PYBIND11_DESCR name() { return _("uint") + _<sizeof(T)*8>(); }
+ template <typename T2 = T, enable_if_t<std::is_integral<T2>::value, int> = 0>
+ static PYBIND11_DESCR name() {
+ return _<std::is_same<T, bool>::value>(_("bool"),
+ _<std::is_signed<T>::value>("int", "uint") + _<sizeof(T)*8>());
+ }
+ template <typename T2 = T, enable_if_t<std::is_floating_point<T2>::value, int> = 0>
+ static PYBIND11_DESCR name() {
+ return _<std::is_same<T, float>::value || std::is_same<T, double>::value>(
+ _("float") + _<sizeof(T)*8>(), _("longdouble"));
+ }
+ template <typename T2 = T, enable_if_t<is_complex<T2>::value, int> = 0>
+ static PYBIND11_DESCR name() {
+ return _<std::is_same<typename T2::value_type, float>::value || std::is_same<typename T2::value_type, double>::value>(
+ _("complex") + _<sizeof(typename T2::value_type)*16>(), _("longcomplex"));
+ }
};
-template <typename T> constexpr const int npy_format_descriptor<
- T, enable_if_t<std::is_integral<T>::value>>::values[8];
-
-#define DECL_FMT(Type, NumPyName, Name) template<> struct npy_format_descriptor<Type> { \
- enum { value = npy_api::NumPyName }; \
- static pybind11::dtype dtype() { \
- if (auto ptr = npy_api::get().PyArray_DescrFromType_(value)) \
- return reinterpret_borrow<pybind11::dtype>(ptr); \
- pybind11_fail("Unsupported buffer format!"); \
- } \
- static PYBIND11_DESCR name() { return _(Name); } }
-DECL_FMT(float, NPY_FLOAT_, "float32");
-DECL_FMT(double, NPY_DOUBLE_, "float64");
-DECL_FMT(bool, NPY_BOOL_, "bool");
-DECL_FMT(std::complex<float>, NPY_CFLOAT_, "complex64");
-DECL_FMT(std::complex<double>, NPY_CDOUBLE_, "complex128");
-#undef DECL_FMT
-
-#define DECL_CHAR_FMT \
+
+#define PYBIND11_DECL_CHAR_FMT \
static PYBIND11_DESCR name() { return _("S") + _<N>(); } \
static pybind11::dtype dtype() { return pybind11::dtype(std::string("S") + std::to_string(N)); }
-template <size_t N> struct npy_format_descriptor<char[N]> { DECL_CHAR_FMT };
-template <size_t N> struct npy_format_descriptor<std::array<char, N>> { DECL_CHAR_FMT };
-#undef DECL_CHAR_FMT
+template <size_t N> struct npy_format_descriptor<char[N]> { PYBIND11_DECL_CHAR_FMT };
+template <size_t N> struct npy_format_descriptor<std::array<char, N>> { PYBIND11_DECL_CHAR_FMT };
+#undef PYBIND11_DECL_CHAR_FMT
template<typename T> struct npy_format_descriptor<T, enable_if_t<std::is_enum<T>::value>> {
private:
@@ -798,9 +959,9 @@ inline PYBIND11_NOINLINE void register_structured_dtype(
for (auto& field : ordered_fields) {
if (field.offset > offset)
oss << (field.offset - offset) << 'x';
- // mark unaligned fields with '='
+ // mark unaligned fields with '^' (unaligned native type)
if (field.offset % field.alignment)
- oss << '=';
+ oss << '^';
oss << field.format << ':' << field.name << ':';
offset = field.offset + field.size;
}
@@ -820,9 +981,10 @@ inline PYBIND11_NOINLINE void register_structured_dtype(
get_internals().direct_conversions[tindex].push_back(direct_converter);
}
-template <typename T>
-struct npy_format_descriptor<T, enable_if_t<is_pod_struct<T>::value>> {
- static PYBIND11_DESCR name() { return _("struct"); }
+template <typename T, typename SFINAE> struct npy_format_descriptor {
+ static_assert(is_pod_struct<T>::value, "Attempt to use a non-POD or unimplemented POD type as a numpy dtype");
+
+ static PYBIND11_DESCR name() { return make_caster<T>::name(); }
static pybind11::dtype dtype() {
return reinterpret_borrow<pybind11::dtype>(dtype_ptr());
@@ -1043,87 +1205,146 @@ private:
std::array<common_iter, N> m_common_iterator;
};
+enum class broadcast_trivial { non_trivial, c_trivial, f_trivial };
+
+// Populates the shape and number of dimensions for the set of buffers. Returns a broadcast_trivial
+// enum value indicating whether the broadcast is "trivial"--that is, has each buffer being either a
+// singleton or a full-size, C-contiguous (`c_trivial`) or Fortran-contiguous (`f_trivial`) storage
+// buffer; returns `non_trivial` otherwise.
template <size_t N>
-bool broadcast(const std::array<buffer_info, N>& buffers, size_t& ndim, std::vector<size_t>& shape) {
+broadcast_trivial broadcast(const std::array<buffer_info, N> &buffers, size_t &ndim, std::vector<size_t> &shape) {
ndim = std::accumulate(buffers.begin(), buffers.end(), size_t(0), [](size_t res, const buffer_info& buf) {
return std::max(res, buf.ndim);
});
- shape = std::vector<size_t>(ndim, 1);
- bool trivial_broadcast = true;
+ shape.clear();
+ shape.resize(ndim, 1);
+
+ // Figure out the output size, and make sure all input arrays conform (i.e. are either size 1 or
+ // the full size).
for (size_t i = 0; i < N; ++i) {
auto res_iter = shape.rbegin();
- bool i_trivial_broadcast = (buffers[i].size == 1) || (buffers[i].ndim == ndim);
- for (auto shape_iter = buffers[i].shape.rbegin();
- shape_iter != buffers[i].shape.rend(); ++shape_iter, ++res_iter) {
-
- if (*res_iter == 1)
- *res_iter = *shape_iter;
- else if ((*shape_iter != 1) && (*res_iter != *shape_iter))
+ auto end = buffers[i].shape.rend();
+ for (auto shape_iter = buffers[i].shape.rbegin(); shape_iter != end; ++shape_iter, ++res_iter) {
+ const auto &dim_size_in = *shape_iter;
+ auto &dim_size_out = *res_iter;
+
+ // Each input dimension can either be 1 or `n`, but `n` values must match across buffers
+ if (dim_size_out == 1)
+ dim_size_out = dim_size_in;
+ else if (dim_size_in != 1 && dim_size_in != dim_size_out)
pybind11_fail("pybind11::vectorize: incompatible size/dimension of inputs!");
+ }
+ }
- i_trivial_broadcast = i_trivial_broadcast && (*res_iter == *shape_iter);
+ bool trivial_broadcast_c = true;
+ bool trivial_broadcast_f = true;
+ for (size_t i = 0; i < N && (trivial_broadcast_c || trivial_broadcast_f); ++i) {
+ if (buffers[i].size == 1)
+ continue;
+
+ // Require the same number of dimensions:
+ if (buffers[i].ndim != ndim)
+ return broadcast_trivial::non_trivial;
+
+ // Require all dimensions be full-size:
+ if (!std::equal(buffers[i].shape.cbegin(), buffers[i].shape.cend(), shape.cbegin()))
+ return broadcast_trivial::non_trivial;
+
+ // Check for C contiguity (but only if previous inputs were also C contiguous)
+ if (trivial_broadcast_c) {
+ size_t expect_stride = buffers[i].itemsize;
+ auto end = buffers[i].shape.crend();
+ for (auto shape_iter = buffers[i].shape.crbegin(), stride_iter = buffers[i].strides.crbegin();
+ trivial_broadcast_c && shape_iter != end; ++shape_iter, ++stride_iter) {
+ if (expect_stride == *stride_iter)
+ expect_stride *= *shape_iter;
+ else
+ trivial_broadcast_c = false;
+ }
+ }
+
+ // Check for Fortran contiguity (if previous inputs were also F contiguous)
+ if (trivial_broadcast_f) {
+ size_t expect_stride = buffers[i].itemsize;
+ auto end = buffers[i].shape.cend();
+ for (auto shape_iter = buffers[i].shape.cbegin(), stride_iter = buffers[i].strides.cbegin();
+ trivial_broadcast_f && shape_iter != end; ++shape_iter, ++stride_iter) {
+ if (expect_stride == *stride_iter)
+ expect_stride *= *shape_iter;
+ else
+ trivial_broadcast_f = false;
+ }
}
- trivial_broadcast = trivial_broadcast && i_trivial_broadcast;
}
- return trivial_broadcast;
+
+ return
+ trivial_broadcast_c ? broadcast_trivial::c_trivial :
+ trivial_broadcast_f ? broadcast_trivial::f_trivial :
+ broadcast_trivial::non_trivial;
}
template <typename Func, typename Return, typename... Args>
struct vectorize_helper {
typename std::remove_reference<Func>::type f;
+ static constexpr size_t N = sizeof...(Args);
template <typename T>
explicit vectorize_helper(T&&f) : f(std::forward<T>(f)) { }
- object operator()(array_t<Args, array::c_style | array::forcecast>... args) {
- return run(args..., make_index_sequence<sizeof...(Args)>());
+ object operator()(array_t<Args, array::forcecast>... args) {
+ return run(args..., make_index_sequence<N>());
}
- template <size_t ... Index> object run(array_t<Args, array::c_style | array::forcecast>&... args, index_sequence<Index...> index) {
+ template <size_t ... Index> object run(array_t<Args, array::forcecast>&... args, index_sequence<Index...> index) {
/* Request buffers from all parameters */
- const size_t N = sizeof...(Args);
-
std::array<buffer_info, N> buffers {{ args.request()... }};
/* Determine dimensions parameters of output array */
size_t ndim = 0;
std::vector<size_t> shape(0);
- bool trivial_broadcast = broadcast(buffers, ndim, shape);
+ auto trivial = broadcast(buffers, ndim, shape);
size_t size = 1;
std::vector<size_t> strides(ndim);
if (ndim > 0) {
- strides[ndim-1] = sizeof(Return);
- for (size_t i = ndim - 1; i > 0; --i) {
- strides[i - 1] = strides[i] * shape[i];
- size *= shape[i];
+ if (trivial == broadcast_trivial::f_trivial) {
+ strides[0] = sizeof(Return);
+ for (size_t i = 1; i < ndim; ++i) {
+ strides[i] = strides[i - 1] * shape[i - 1];
+ size *= shape[i - 1];
+ }
+ size *= shape[ndim - 1];
+ }
+ else {
+ strides[ndim-1] = sizeof(Return);
+ for (size_t i = ndim - 1; i > 0; --i) {
+ strides[i - 1] = strides[i] * shape[i];
+ size *= shape[i];
+ }
+ size *= shape[0];
}
- size *= shape[0];
}
if (size == 1)
- return cast(f(*((Args *) buffers[Index].ptr)...));
+ return cast(f(*reinterpret_cast<Args *>(buffers[Index].ptr)...));
array_t<Return> result(shape, strides);
auto buf = result.request();
auto output = (Return *) buf.ptr;
- if (trivial_broadcast) {
- /* Call the function */
- for (size_t i = 0; i < size; ++i) {
- output[i] = f((buffers[Index].size == 1
- ? *((Args *) buffers[Index].ptr)
- : ((Args *) buffers[Index].ptr)[i])...);
- }
+ /* Call the function */
+ if (trivial == broadcast_trivial::non_trivial) {
+ apply_broadcast<Index...>(buffers, buf, index);
} else {
- apply_broadcast<N, Index...>(buffers, buf, index);
+ for (size_t i = 0; i < size; ++i)
+ output[i] = f((reinterpret_cast<Args *>(buffers[Index].ptr)[buffers[Index].size == 1 ? 0 : i])...);
}
return result;
}
- template <size_t N, size_t... Index>
+ template <size_t... Index>
void apply_broadcast(const std::array<buffer_info, N> &buffers,
buffer_info &output, index_sequence<Index...>) {
using input_iterator = multi_array_iterator<N>;
@@ -1140,26 +1361,29 @@ struct vectorize_helper {
};
template <typename T, int Flags> struct handle_type_name<array_t<T, Flags>> {
- static PYBIND11_DESCR name() { return _("numpy.ndarray[") + type_caster<T>::name() + _("]"); }
+ static PYBIND11_DESCR name() {
+ return _("numpy.ndarray[") + npy_format_descriptor<T>::name() + _("]");
+ }
};
NAMESPACE_END(detail)
template <typename Func, typename Return, typename... Args>
-detail::vectorize_helper<Func, Return, Args...> vectorize(const Func &f, Return (*) (Args ...)) {
+detail::vectorize_helper<Func, Return, Args...>
+vectorize(const Func &f, Return (*) (Args ...)) {
return detail::vectorize_helper<Func, Return, Args...>(f);
}
template <typename Return, typename... Args>
-detail::vectorize_helper<Return (*) (Args ...), Return, Args...> vectorize(Return (*f) (Args ...)) {
+detail::vectorize_helper<Return (*) (Args ...), Return, Args...>
+vectorize(Return (*f) (Args ...)) {
return vectorize<Return (*) (Args ...), Return, Args...>(f, f);
}
-template <typename Func>
+template <typename Func, typename FuncType = typename detail::remove_class<decltype(&std::remove_reference<Func>::type::operator())>::type>
auto vectorize(Func &&f) -> decltype(
- vectorize(std::forward<Func>(f), (typename detail::remove_class<decltype(&std::remove_reference<Func>::type::operator())>::type *) nullptr)) {
- return vectorize(std::forward<Func>(f), (typename detail::remove_class<decltype(
- &std::remove_reference<Func>::type::operator())>::type *) nullptr);
+ vectorize(std::forward<Func>(f), (FuncType *) nullptr)) {
+ return vectorize(std::forward<Func>(f), (FuncType *) nullptr);
}
NAMESPACE_END(pybind11)
diff --git a/ext/pybind11/include/pybind11/pybind11.h b/ext/pybind11/include/pybind11/pybind11.h
index 1db9efb8c..5976a36d8 100644
--- a/ext/pybind11/include/pybind11/pybind11.h
+++ b/ext/pybind11/include/pybind11/pybind11.h
@@ -35,6 +35,7 @@
#include "attr.h"
#include "options.h"
+#include "class_support.h"
NAMESPACE_BEGIN(pybind11)
@@ -50,10 +51,16 @@ public:
}
/// Construct a cpp_function from a lambda function (possibly with internal state)
- template <typename Func, typename... Extra> cpp_function(Func &&f, const Extra&... extra) {
+ template <typename Func, typename... Extra, typename = detail::enable_if_t<
+ detail::satisfies_none_of<
+ typename std::remove_reference<Func>::type,
+ std::is_function, std::is_pointer, std::is_member_pointer
+ >::value>
+ >
+ cpp_function(Func &&f, const Extra&... extra) {
+ using FuncType = typename detail::remove_class<decltype(&std::remove_reference<Func>::type::operator())>::type;
initialize(std::forward<Func>(f),
- (typename detail::remove_class<decltype(
- &std::remove_reference<Func>::type::operator())>::type *) nullptr, extra...);
+ (FuncType *) nullptr, extra...);
}
/// Construct a cpp_function from a class method (non-const)
@@ -82,8 +89,6 @@ protected:
/// Special internal constructor for functors, lambda functions, etc.
template <typename Func, typename Return, typename... Args, typename... Extra>
void initialize(Func &&f, Return (*)(Args...), const Extra&... extra) {
- static_assert(detail::expected_num_args<Extra...>(sizeof...(Args)),
- "The number of named arguments does not match the function signature");
struct capture { typename std::remove_reference<Func>::type f; };
@@ -116,32 +121,34 @@ protected:
detail::conditional_t<std::is_void<Return>::value, detail::void_type, Return>
>;
+ static_assert(detail::expected_num_args<Extra...>(sizeof...(Args), cast_in::has_args, cast_in::has_kwargs),
+ "The number of argument annotations does not match the number of function arguments");
+
/* Dispatch code which converts function arguments and performs the actual function call */
- rec->impl = [](detail::function_record *rec, handle args, handle kwargs, handle parent) -> handle {
+ rec->impl = [](detail::function_call &call) -> handle {
cast_in args_converter;
/* Try to cast the function arguments into the C++ domain */
- if (!args_converter.load_args(args, kwargs, true))
+ if (!args_converter.load_args(call))
return PYBIND11_TRY_NEXT_OVERLOAD;
/* Invoke call policy pre-call hook */
- detail::process_attributes<Extra...>::precall(args);
+ detail::process_attributes<Extra...>::precall(call);
/* Get a pointer to the capture object */
- capture *cap = (capture *) (sizeof(capture) <= sizeof(rec->data)
- ? &rec->data : rec->data[0]);
+ auto data = (sizeof(capture) <= sizeof(call.func.data)
+ ? &call.func.data : call.func.data[0]);
+ capture *cap = const_cast<capture *>(reinterpret_cast<const capture *>(data));
- /* Override policy for rvalues -- always move */
- constexpr auto is_rvalue = !std::is_pointer<Return>::value
- && !std::is_lvalue_reference<Return>::value;
- const auto policy = is_rvalue ? return_value_policy::move : rec->policy;
+ /* Override policy for rvalues -- usually to enforce rvp::move on an rvalue */
+ const auto policy = detail::return_value_policy_override<Return>::policy(call.func.policy);
/* Perform the function call */
handle result = cast_out::cast(args_converter.template call<Return>(cap->f),
- policy, parent);
+ policy, call.parent);
/* Invoke call policy post-call hook */
- detail::process_attributes<Extra...>::postcall(args, result);
+ detail::process_attributes<Extra...>::postcall(call, result);
return result;
};
@@ -166,7 +173,7 @@ protected:
sizeof(capture) == sizeof(void *);
if (is_function_ptr) {
rec->is_stateless = true;
- rec->data[1] = (void *) &typeid(FunctionType);
+ rec->data[1] = const_cast<void *>(reinterpret_cast<const void *>(&typeid(FunctionType)));
}
}
@@ -197,7 +204,7 @@ protected:
if (c == '{') {
// Write arg name for everything except *args, **kwargs and return type.
if (type_depth == 0 && text[char_index] != '*' && arg_index < args) {
- if (!rec->args.empty()) {
+ if (!rec->args.empty() && rec->args[arg_index].name) {
signature += rec->args[arg_index].name;
} else if (arg_index == 0 && rec->is_method) {
signature += "self";
@@ -221,6 +228,11 @@ protected:
if (!t)
pybind11_fail("Internal error while parsing type signature (1)");
if (auto tinfo = detail::get_type_info(*t)) {
+#if defined(PYPY_VERSION)
+ signature += handle((PyObject *) tinfo->type)
+ .attr("__module__")
+ .cast<std::string>() + ".";
+#endif
signature += tinfo->type->tp_name;
} else {
std::string tname(t->name());
@@ -251,7 +263,7 @@ protected:
rec->signature = strdup(signature.c_str());
rec->args.shrink_to_fit();
rec->is_constructor = !strcmp(rec->name, "__init__") || !strcmp(rec->name, "__setstate__");
- rec->nargs = (uint16_t) args;
+ rec->nargs = (std::uint16_t) args;
#if PY_MAJOR_VERSION < 3
if (rec->sibling && PyMethod_Check(rec->sibling.ptr()))
@@ -261,7 +273,7 @@ protected:
detail::function_record *chain = nullptr, *chain_start = rec;
if (rec->sibling) {
if (PyCFunction_Check(rec->sibling.ptr())) {
- auto rec_capsule = reinterpret_borrow<capsule>(PyCFunction_GetSelf(rec->sibling.ptr()));
+ auto rec_capsule = reinterpret_borrow<capsule>(PyCFunction_GET_SELF(rec->sibling.ptr()));
chain = (detail::function_record *) rec_capsule;
/* Never append a method to an overload chain of a parent class;
instead, hide the parent's overloads in this case */
@@ -282,8 +294,8 @@ protected:
rec->def->ml_meth = reinterpret_cast<PyCFunction>(*dispatcher);
rec->def->ml_flags = METH_VARARGS | METH_KEYWORDS;
- capsule rec_capsule(rec, [](PyObject *o) {
- destruct((detail::function_record *) PyCapsule_GetPointer(o, nullptr));
+ capsule rec_capsule(rec, [](void *ptr) {
+ destruct((detail::function_record *) ptr);
});
object scope_module;
@@ -319,8 +331,10 @@ protected:
signatures += "Overloaded function.\n\n";
}
// Then specific overload signatures
+ bool first_user_def = true;
for (auto it = chain_start; it != nullptr; it = it->next) {
if (options::show_function_signatures()) {
+ if (index > 0) signatures += "\n";
if (chain)
signatures += std::to_string(++index) + ". ";
signatures += rec->name;
@@ -328,18 +342,22 @@ protected:
signatures += "\n";
}
if (it->doc && strlen(it->doc) > 0 && options::show_user_defined_docstrings()) {
+ // If we're appending another docstring, and aren't printing function signatures, we
+ // need to append a newline first:
+ if (!options::show_function_signatures()) {
+ if (first_user_def) first_user_def = false;
+ else signatures += "\n";
+ }
if (options::show_function_signatures()) signatures += "\n";
signatures += it->doc;
if (options::show_function_signatures()) signatures += "\n";
}
- if (it->next)
- signatures += "\n";
}
/* Install docstring */
PyCFunctionObject *func = (PyCFunctionObject *) m_ptr;
if (func->m_ml->ml_doc)
- std::free((char *) func->m_ml->ml_doc);
+ std::free(const_cast<char *>(func->m_ml->ml_doc));
func->m_ml->ml_doc = strdup(signatures.c_str());
if (rec->is_method) {
@@ -360,12 +378,12 @@ protected:
std::free((char *) rec->doc);
std::free((char *) rec->signature);
for (auto &arg: rec->args) {
- std::free((char *) arg.name);
- std::free((char *) arg.descr);
+ std::free(const_cast<char *>(arg.name));
+ std::free(const_cast<char *>(arg.descr));
arg.value.dec_ref();
}
if (rec->def) {
- std::free((char *) rec->def->ml_doc);
+ std::free(const_cast<char *>(rec->def->ml_doc));
delete rec->def;
}
delete rec;
@@ -374,72 +392,205 @@ protected:
}
/// Main dispatch logic for calls to functions bound using pybind11
- static PyObject *dispatcher(PyObject *self, PyObject *args, PyObject *kwargs) {
+ static PyObject *dispatcher(PyObject *self, PyObject *args_in, PyObject *kwargs_in) {
+ using namespace detail;
+
/* Iterator over the list of potentially admissible overloads */
- detail::function_record *overloads = (detail::function_record *) PyCapsule_GetPointer(self, nullptr),
- *it = overloads;
+ function_record *overloads = (function_record *) PyCapsule_GetPointer(self, nullptr),
+ *it = overloads;
/* Need to know how many arguments + keyword arguments there are to pick the right overload */
- size_t nargs = (size_t) PyTuple_GET_SIZE(args),
- nkwargs = kwargs ? (size_t) PyDict_Size(kwargs) : 0;
+ const size_t n_args_in = (size_t) PyTuple_GET_SIZE(args_in);
- handle parent = nargs > 0 ? PyTuple_GET_ITEM(args, 0) : nullptr,
+ handle parent = n_args_in > 0 ? PyTuple_GET_ITEM(args_in, 0) : nullptr,
result = PYBIND11_TRY_NEXT_OVERLOAD;
+
try {
+ // We do this in two passes: in the first pass, we load arguments with `convert=false`;
+ // in the second, we allow conversion (except for arguments with an explicit
+ // py::arg().noconvert()). This lets us prefer calls without conversion, with
+ // conversion as a fallback.
+ std::vector<function_call> second_pass;
+
+ // However, if there are no overloads, we can just skip the no-convert pass entirely
+ const bool overloaded = it != nullptr && it->next != nullptr;
+
for (; it != nullptr; it = it->next) {
- auto args_ = reinterpret_borrow<tuple>(args);
- size_t kwargs_consumed = 0;
/* For each overload:
- 1. If the required list of arguments is longer than the
- actually provided amount, create a copy of the argument
- list and fill in any available keyword/default arguments.
- 2. Ensure that all keyword arguments were "consumed"
- 3. Call the function call dispatcher (function_record::impl)
+ 1. Copy all positional arguments we were given, also checking to make sure that
+ named positional arguments weren't *also* specified via kwarg.
+ 2. If we weren't given enough, try to make up the omitted ones by checking
+ whether they were provided by a kwarg matching the `py::arg("name")` name. If
+ so, use it (and remove it from kwargs; if not, see if the function binding
+ provided a default that we can use.
+ 3. Ensure that either all keyword arguments were "consumed", or that the function
+ takes a kwargs argument to accept unconsumed kwargs.
+ 4. Any positional arguments still left get put into a tuple (for args), and any
+ leftover kwargs get put into a dict.
+ 5. Pack everything into a vector; if we have py::args or py::kwargs, they are an
+ extra tuple or dict at the end of the positional arguments.
+ 6. Call the function call dispatcher (function_record::impl)
+
+ If one of these fail, move on to the next overload and keep trying until we get a
+ result other than PYBIND11_TRY_NEXT_OVERLOAD.
*/
- size_t nargs_ = nargs;
- if (nargs < it->args.size()) {
- nargs_ = it->args.size();
- args_ = tuple(nargs_);
- for (size_t i = 0; i < nargs; ++i) {
- handle item = PyTuple_GET_ITEM(args, i);
- PyTuple_SET_ITEM(args_.ptr(), i, item.inc_ref().ptr());
+
+ function_record &func = *it;
+ size_t pos_args = func.nargs; // Number of positional arguments that we need
+ if (func.has_args) --pos_args; // (but don't count py::args
+ if (func.has_kwargs) --pos_args; // or py::kwargs)
+
+ if (!func.has_args && n_args_in > pos_args)
+ continue; // Too many arguments for this overload
+
+ if (n_args_in < pos_args && func.args.size() < pos_args)
+ continue; // Not enough arguments given, and not enough defaults to fill in the blanks
+
+ function_call call(func, parent);
+
+ size_t args_to_copy = std::min(pos_args, n_args_in);
+ size_t args_copied = 0;
+
+ // 1. Copy any position arguments given.
+ bool bad_kwarg = false;
+ for (; args_copied < args_to_copy; ++args_copied) {
+ if (kwargs_in && args_copied < func.args.size() && func.args[args_copied].name
+ && PyDict_GetItemString(kwargs_in, func.args[args_copied].name)) {
+ bad_kwarg = true;
+ break;
}
- int arg_ctr = 0;
- for (auto const &it2 : it->args) {
- int index = arg_ctr++;
- if (PyTuple_GET_ITEM(args_.ptr(), index))
- continue;
+ call.args.push_back(PyTuple_GET_ITEM(args_in, args_copied));
+ call.args_convert.push_back(args_copied < func.args.size() ? func.args[args_copied].convert : true);
+ }
+ if (bad_kwarg)
+ continue; // Maybe it was meant for another overload (issue #688)
+
+ // We'll need to copy this if we steal some kwargs for defaults
+ dict kwargs = reinterpret_borrow<dict>(kwargs_in);
+
+ // 2. Check kwargs and, failing that, defaults that may help complete the list
+ if (args_copied < pos_args) {
+ bool copied_kwargs = false;
+
+ for (; args_copied < pos_args; ++args_copied) {
+ const auto &arg = func.args[args_copied];
handle value;
- if (kwargs)
- value = PyDict_GetItemString(kwargs, it2.name);
+ if (kwargs_in && arg.name)
+ value = PyDict_GetItemString(kwargs.ptr(), arg.name);
- if (value)
- kwargs_consumed++;
- else if (it2.value)
- value = it2.value;
+ if (value) {
+ // Consume a kwargs value
+ if (!copied_kwargs) {
+ kwargs = reinterpret_steal<dict>(PyDict_Copy(kwargs.ptr()));
+ copied_kwargs = true;
+ }
+ PyDict_DelItemString(kwargs.ptr(), arg.name);
+ } else if (arg.value) {
+ value = arg.value;
+ }
if (value) {
- PyTuple_SET_ITEM(args_.ptr(), index, value.inc_ref().ptr());
- } else {
- kwargs_consumed = (size_t) -1; /* definite failure */
+ call.args.push_back(value);
+ call.args_convert.push_back(arg.convert);
+ }
+ else
break;
+ }
+
+ if (args_copied < pos_args)
+ continue; // Not enough arguments, defaults, or kwargs to fill the positional arguments
+ }
+
+ // 3. Check everything was consumed (unless we have a kwargs arg)
+ if (kwargs && kwargs.size() > 0 && !func.has_kwargs)
+ continue; // Unconsumed kwargs, but no py::kwargs argument to accept them
+
+ // 4a. If we have a py::args argument, create a new tuple with leftovers
+ tuple extra_args;
+ if (func.has_args) {
+ if (args_to_copy == 0) {
+ // We didn't copy out any position arguments from the args_in tuple, so we
+ // can reuse it directly without copying:
+ extra_args = reinterpret_borrow<tuple>(args_in);
+ } else if (args_copied >= n_args_in) {
+ extra_args = tuple(0);
+ } else {
+ size_t args_size = n_args_in - args_copied;
+ extra_args = tuple(args_size);
+ for (size_t i = 0; i < args_size; ++i) {
+ handle item = PyTuple_GET_ITEM(args_in, args_copied + i);
+ extra_args[i] = item.inc_ref().ptr();
}
}
+ call.args.push_back(extra_args);
+ call.args_convert.push_back(false);
}
+ // 4b. If we have a py::kwargs, pass on any remaining kwargs
+ if (func.has_kwargs) {
+ if (!kwargs.ptr())
+ kwargs = dict(); // If we didn't get one, send an empty one
+ call.args.push_back(kwargs);
+ call.args_convert.push_back(false);
+ }
+
+ // 5. Put everything in a vector. Not technically step 5, we've been building it
+ // in `call.args` all along.
+ #if !defined(NDEBUG)
+ if (call.args.size() != func.nargs || call.args_convert.size() != func.nargs)
+ pybind11_fail("Internal error: function call dispatcher inserted wrong number of arguments!");
+ #endif
+
+ std::vector<bool> second_pass_convert;
+ if (overloaded) {
+ // We're in the first no-convert pass, so swap out the conversion flags for a
+ // set of all-false flags. If the call fails, we'll swap the flags back in for
+ // the conversion-allowed call below.
+ second_pass_convert.resize(func.nargs, false);
+ call.args_convert.swap(second_pass_convert);
+ }
+
+ // 6. Call the function.
try {
- if ((kwargs_consumed == nkwargs || it->has_kwargs) &&
- (nargs_ == it->nargs || it->has_args))
- result = it->impl(it, args_, kwargs, parent);
+ result = func.impl(call);
} catch (reference_cast_error &) {
result = PYBIND11_TRY_NEXT_OVERLOAD;
}
if (result.ptr() != PYBIND11_TRY_NEXT_OVERLOAD)
break;
+
+ if (overloaded) {
+ // The (overloaded) call failed; if the call has at least one argument that
+ // permits conversion (i.e. it hasn't been explicitly specified `.noconvert()`)
+ // then add this call to the list of second pass overloads to try.
+ for (size_t i = func.is_method ? 1 : 0; i < pos_args; i++) {
+ if (second_pass_convert[i]) {
+ // Found one: swap the converting flags back in and store the call for
+ // the second pass.
+ call.args_convert.swap(second_pass_convert);
+ second_pass.push_back(std::move(call));
+ break;
+ }
+ }
+ }
+ }
+
+ if (overloaded && !second_pass.empty() && result.ptr() == PYBIND11_TRY_NEXT_OVERLOAD) {
+ // The no-conversion pass finished without success, try again with conversion allowed
+ for (auto &call : second_pass) {
+ try {
+ result = call.func.impl(call);
+ } catch (reference_cast_error &) {
+ result = PYBIND11_TRY_NEXT_OVERLOAD;
+ }
+
+ if (result.ptr() != PYBIND11_TRY_NEXT_OVERLOAD)
+ break;
+ }
}
} catch (error_already_set &e) {
e.restore();
@@ -457,7 +608,7 @@ protected:
- delegate translation to the next translator by throwing a new type of exception. */
auto last_exception = std::current_exception();
- auto &registered_exception_translators = pybind11::detail::get_internals().registered_exception_translators;
+ auto &registered_exception_translators = get_internals().registered_exception_translators;
for (auto& translator : registered_exception_translators) {
try {
translator(last_exception);
@@ -480,7 +631,7 @@ protected:
" arguments. The following argument types are supported:\n";
int ctr = 0;
- for (detail::function_record *it2 = overloads; it2 != nullptr; it2 = it2->next) {
+ for (function_record *it2 = overloads; it2 != nullptr; it2 = it2->next) {
msg += " "+ std::to_string(++ctr) + ". ";
bool wrote_sig = false;
@@ -507,12 +658,27 @@ protected:
msg += "\n";
}
msg += "\nInvoked with: ";
- auto args_ = reinterpret_borrow<tuple>(args);
+ auto args_ = reinterpret_borrow<tuple>(args_in);
+ bool some_args = false;
for (size_t ti = overloads->is_constructor ? 1 : 0; ti < args_.size(); ++ti) {
+ if (!some_args) some_args = true;
+ else msg += ", ";
msg += pybind11::repr(args_[ti]);
- if ((ti + 1) != args_.size() )
- msg += ", ";
}
+ if (kwargs_in) {
+ auto kwargs = reinterpret_borrow<dict>(kwargs_in);
+ if (kwargs.size() > 0) {
+ if (some_args) msg += "; ";
+ msg += "kwargs: ";
+ bool first = true;
+ for (auto kwarg : kwargs) {
+ if (first) first = false;
+ else msg += ", ";
+ msg += pybind11::str("{}={!r}").format(kwarg.first, kwarg.second);
+ }
+ }
+ }
+
PyErr_SetString(PyExc_TypeError, msg.c_str());
return nullptr;
} else if (!result) {
@@ -525,9 +691,8 @@ protected:
if (overloads->is_constructor) {
/* When a constructor ran successfully, the corresponding
holder type (e.g. std::unique_ptr) must still be initialized. */
- PyObject *inst = PyTuple_GET_ITEM(args, 0);
- auto tinfo = detail::get_type_info(Py_TYPE(inst));
- tinfo->init_holder(inst, nullptr);
+ auto tinfo = get_type_info(Py_TYPE(parent.ptr()));
+ tinfo->init_holder(parent.ptr(), nullptr);
}
return result.ptr();
}
@@ -539,6 +704,7 @@ class module : public object {
public:
PYBIND11_OBJECT_DEFAULT(module, object, PyModule_Check)
+ /// Create a new top-level Python module with the given name and docstring
explicit module(const char *name, const char *doc = nullptr) {
if (!options::show_user_defined_docstrings()) doc = nullptr;
#if PY_MAJOR_VERSION >= 3
@@ -557,6 +723,11 @@ public:
inc_ref();
}
+ /** \rst
+ Create Python binding for a new function within the module scope. ``Func``
+ can be a plain C++ function, a function pointer, or a lambda function. For
+ details on the ``Extra&& ... extra`` argument, see section :ref:`extras`.
+ \endrst */
template <typename Func, typename... Extra>
module &def(const char *name_, Func &&f, const Extra& ... extra) {
cpp_function func(std::forward<Func>(f), name(name_), scope(*this),
@@ -567,6 +738,16 @@ public:
return *this;
}
+ /** \rst
+ Create and return a new Python submodule with the given name and docstring.
+ This also works recursively, i.e.
+
+ .. code-block:: cpp
+
+ py::module m("example", "pybind11 example plugin");
+ py::module m2 = m.def_submodule("sub", "A submodule of 'example'");
+ py::module m3 = m2.def_submodule("subsub", "A submodule of 'example.sub'");
+ \endrst */
module def_submodule(const char *name, const char *doc = nullptr) {
std::string full_name = std::string(PyModule_GetName(m_ptr))
+ std::string(".") + std::string(name);
@@ -577,6 +758,7 @@ public:
return result;
}
+ /// Import and return a module or throws `error_already_set`.
static module import(const char *name) {
PyObject *obj = PyImport_ImportModule(name);
if (!obj)
@@ -600,175 +782,40 @@ public:
};
NAMESPACE_BEGIN(detail)
-extern "C" inline PyObject *get_dict(PyObject *op, void *) {
- PyObject *&dict = *_PyObject_GetDictPtr(op);
- if (!dict) {
- dict = PyDict_New();
- }
- Py_XINCREF(dict);
- return dict;
-}
-
-extern "C" inline int set_dict(PyObject *op, PyObject *new_dict, void *) {
- if (!PyDict_Check(new_dict)) {
- PyErr_Format(PyExc_TypeError, "__dict__ must be set to a dictionary, not a '%.200s'",
- Py_TYPE(new_dict)->tp_name);
- return -1;
- }
- PyObject *&dict = *_PyObject_GetDictPtr(op);
- Py_INCREF(new_dict);
- Py_CLEAR(dict);
- dict = new_dict;
- return 0;
-}
-
-static PyGetSetDef generic_getset[] = {
- {const_cast<char*>("__dict__"), get_dict, set_dict, nullptr, nullptr},
- {nullptr, nullptr, nullptr, nullptr, nullptr}
-};
-
/// Generic support for creating new Python heap types
class generic_type : public object {
template <typename...> friend class class_;
public:
PYBIND11_OBJECT_DEFAULT(generic_type, object, PyType_Check)
protected:
- void initialize(type_record *rec) {
- auto &internals = get_internals();
- auto tindex = std::type_index(*(rec->type));
+ void initialize(const type_record &rec) {
+ if (rec.scope && hasattr(rec.scope, rec.name))
+ pybind11_fail("generic_type: cannot initialize type \"" + std::string(rec.name) +
+ "\": an object with that name is already defined");
- if (get_type_info(*(rec->type)))
- pybind11_fail("generic_type: type \"" + std::string(rec->name) +
+ if (get_type_info(*rec.type))
+ pybind11_fail("generic_type: type \"" + std::string(rec.name) +
"\" is already registered!");
- auto name = reinterpret_steal<object>(PYBIND11_FROM_STRING(rec->name));
- object scope_module;
- if (rec->scope) {
- if (hasattr(rec->scope, rec->name))
- pybind11_fail("generic_type: cannot initialize type \"" + std::string(rec->name) +
- "\": an object with that name is already defined");
-
- if (hasattr(rec->scope, "__module__")) {
- scope_module = rec->scope.attr("__module__");
- } else if (hasattr(rec->scope, "__name__")) {
- scope_module = rec->scope.attr("__name__");
- }
- }
-
-#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 3
- /* Qualified names for Python >= 3.3 */
- object scope_qualname;
- if (rec->scope && hasattr(rec->scope, "__qualname__"))
- scope_qualname = rec->scope.attr("__qualname__");
- object ht_qualname;
- if (scope_qualname) {
- ht_qualname = reinterpret_steal<object>(PyUnicode_FromFormat(
- "%U.%U", scope_qualname.ptr(), name.ptr()));
- } else {
- ht_qualname = name;
- }
-#endif
-
- size_t num_bases = rec->bases.size();
- auto bases = tuple(rec->bases);
-
- std::string full_name = (scope_module ? ((std::string) pybind11::str(scope_module) + "." + rec->name)
- : std::string(rec->name));
-
- char *tp_doc = nullptr;
- if (rec->doc && options::show_user_defined_docstrings()) {
- /* Allocate memory for docstring (using PyObject_MALLOC, since
- Python will free this later on) */
- size_t size = strlen(rec->doc) + 1;
- tp_doc = (char *) PyObject_MALLOC(size);
- memcpy((void *) tp_doc, rec->doc, size);
- }
-
- /* Danger zone: from now (and until PyType_Ready), make sure to
- issue no Python C API calls which could potentially invoke the
- garbage collector (the GC will call type_traverse(), which will in
- turn find the newly constructed type in an invalid state) */
-
- auto type_holder = reinterpret_steal<object>(PyType_Type.tp_alloc(&PyType_Type, 0));
- auto type = (PyHeapTypeObject*) type_holder.ptr();
-
- if (!type_holder || !name)
- pybind11_fail(std::string(rec->name) + ": Unable to create type object!");
+ m_ptr = make_new_python_type(rec);
/* Register supplemental type information in C++ dict */
- detail::type_info *tinfo = new detail::type_info();
- tinfo->type = (PyTypeObject *) type;
- tinfo->type_size = rec->type_size;
- tinfo->init_holder = rec->init_holder;
+ auto *tinfo = new detail::type_info();
+ tinfo->type = (PyTypeObject *) m_ptr;
+ tinfo->type_size = rec.type_size;
+ tinfo->operator_new = rec.operator_new;
+ tinfo->init_holder = rec.init_holder;
+ tinfo->dealloc = rec.dealloc;
+
+ auto &internals = get_internals();
+ auto tindex = std::type_index(*rec.type);
tinfo->direct_conversions = &internals.direct_conversions[tindex];
+ tinfo->default_holder = rec.default_holder;
internals.registered_types_cpp[tindex] = tinfo;
- internals.registered_types_py[type] = tinfo;
-
- /* Basic type attributes */
- type->ht_type.tp_name = strdup(full_name.c_str());
- type->ht_type.tp_basicsize = (ssize_t) rec->instance_size;
-
- if (num_bases > 0) {
- type->ht_type.tp_base = (PyTypeObject *) ((object) bases[0]).inc_ref().ptr();
- type->ht_type.tp_bases = bases.release().ptr();
- rec->multiple_inheritance |= num_bases > 1;
- }
-
- type->ht_name = name.release().ptr();
-
-#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 3
- type->ht_qualname = ht_qualname.release().ptr();
-#endif
+ internals.registered_types_py[m_ptr] = tinfo;
- /* Supported protocols */
- type->ht_type.tp_as_number = &type->as_number;
- type->ht_type.tp_as_sequence = &type->as_sequence;
- type->ht_type.tp_as_mapping = &type->as_mapping;
-
- /* Supported elementary operations */
- type->ht_type.tp_init = (initproc) init;
- type->ht_type.tp_new = (newfunc) new_instance;
- type->ht_type.tp_dealloc = rec->dealloc;
-
- /* Support weak references (needed for the keep_alive feature) */
- type->ht_type.tp_weaklistoffset = offsetof(instance_essentials<void>, weakrefs);
-
- /* Flags */
- type->ht_type.tp_flags |= Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE;
-#if PY_MAJOR_VERSION < 3
- type->ht_type.tp_flags |= Py_TPFLAGS_CHECKTYPES;
-#endif
- type->ht_type.tp_flags &= ~Py_TPFLAGS_HAVE_GC;
-
- /* Support dynamic attributes */
- if (rec->dynamic_attr) {
- type->ht_type.tp_flags |= Py_TPFLAGS_HAVE_GC;
- type->ht_type.tp_dictoffset = type->ht_type.tp_basicsize; // place the dict at the end
- type->ht_type.tp_basicsize += sizeof(PyObject *); // and allocate enough space for it
- type->ht_type.tp_getset = generic_getset;
- type->ht_type.tp_traverse = traverse;
- type->ht_type.tp_clear = clear;
- }
-
- type->ht_type.tp_doc = tp_doc;
-
- if (PyType_Ready(&type->ht_type) < 0)
- pybind11_fail(std::string(rec->name) + ": PyType_Ready failed (" +
- detail::error_string() + ")!");
-
- m_ptr = type_holder.ptr();
-
- if (scope_module) // Needed by pydoc
- attr("__module__") = scope_module;
-
- /* Register type with the parent scope */
- if (rec->scope)
- rec->scope.attr(handle(type->ht_name)) = *this;
-
- if (rec->multiple_inheritance)
- mark_parents_nonsimple(&type->ht_type);
-
- type_holder.release();
+ if (rec.bases.size() > 1 || rec.multiple_inheritance)
+ mark_parents_nonsimple(tinfo->type);
}
/// Helper function which tags all parents of a type using mult. inheritance
@@ -782,141 +829,50 @@ protected:
}
}
- /// Allocate a metaclass on demand (for static properties)
- handle metaclass() {
- auto &ht_type = ((PyHeapTypeObject *) m_ptr)->ht_type;
- auto &ob_type = PYBIND11_OB_TYPE(ht_type);
-
- if (ob_type == &PyType_Type) {
- std::string name_ = std::string(ht_type.tp_name) + "__Meta";
-#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 3
- auto ht_qualname = reinterpret_steal<object>(PyUnicode_FromFormat("%U__Meta", attr("__qualname__").ptr()));
-#endif
- auto name = reinterpret_steal<object>(PYBIND11_FROM_STRING(name_.c_str()));
- auto type_holder = reinterpret_steal<object>(PyType_Type.tp_alloc(&PyType_Type, 0));
- if (!type_holder || !name)
- pybind11_fail("generic_type::metaclass(): unable to create type object!");
-
- auto type = (PyHeapTypeObject*) type_holder.ptr();
- type->ht_name = name.release().ptr();
-
-#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 3
- /* Qualified names for Python >= 3.3 */
- type->ht_qualname = ht_qualname.release().ptr();
-#endif
- type->ht_type.tp_name = strdup(name_.c_str());
- type->ht_type.tp_base = ob_type;
- type->ht_type.tp_flags |= (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HEAPTYPE) &
- ~Py_TPFLAGS_HAVE_GC;
-
- if (PyType_Ready(&type->ht_type) < 0)
- pybind11_fail("generic_type::metaclass(): PyType_Ready failed!");
-
- ob_type = (PyTypeObject *) type_holder.release().ptr();
- }
- return handle((PyObject *) ob_type);
- }
-
- static int init(void *self, PyObject *, PyObject *) {
- std::string msg = std::string(Py_TYPE(self)->tp_name) + ": No constructor defined!";
- PyErr_SetString(PyExc_TypeError, msg.c_str());
- return -1;
- }
-
- static PyObject *new_instance(PyTypeObject *type, PyObject *, PyObject *) {
- instance<void> *self = (instance<void> *) PyType_GenericAlloc((PyTypeObject *) type, 0);
- auto tinfo = detail::get_type_info(type);
- self->value = ::operator new(tinfo->type_size);
- self->owned = true;
- self->holder_constructed = false;
- detail::get_internals().registered_instances.emplace(self->value, (PyObject *) self);
- return (PyObject *) self;
- }
-
- static void dealloc(instance<void> *self) {
- if (self->value) {
- auto instance_type = Py_TYPE(self);
- auto &registered_instances = detail::get_internals().registered_instances;
- auto range = registered_instances.equal_range(self->value);
- bool found = false;
- for (auto it = range.first; it != range.second; ++it) {
- if (instance_type == Py_TYPE(it->second)) {
- registered_instances.erase(it);
- found = true;
- break;
- }
- }
- if (!found)
- pybind11_fail("generic_type::dealloc(): Tried to deallocate unregistered instance!");
-
- if (self->weakrefs)
- PyObject_ClearWeakRefs((PyObject *) self);
-
- PyObject **dict_ptr = _PyObject_GetDictPtr((PyObject *) self);
- if (dict_ptr) {
- Py_CLEAR(*dict_ptr);
- }
- }
- Py_TYPE(self)->tp_free((PyObject*) self);
- }
-
- static int traverse(PyObject *op, visitproc visit, void *arg) {
- PyObject *&dict = *_PyObject_GetDictPtr(op);
- Py_VISIT(dict);
- return 0;
- }
-
- static int clear(PyObject *op) {
- PyObject *&dict = *_PyObject_GetDictPtr(op);
- Py_CLEAR(dict);
- return 0;
- }
-
void install_buffer_funcs(
buffer_info *(*get_buffer)(PyObject *, void *),
void *get_buffer_data) {
PyHeapTypeObject *type = (PyHeapTypeObject*) m_ptr;
- type->ht_type.tp_as_buffer = &type->as_buffer;
-#if PY_MAJOR_VERSION < 3
- type->ht_type.tp_flags |= Py_TPFLAGS_HAVE_NEWBUFFER;
-#endif
- type->as_buffer.bf_getbuffer = getbuffer;
- type->as_buffer.bf_releasebuffer = releasebuffer;
auto tinfo = detail::get_type_info(&type->ht_type);
+
+ if (!type->ht_type.tp_as_buffer)
+ pybind11_fail(
+ "To be able to register buffer protocol support for the type '" +
+ std::string(tinfo->type->tp_name) +
+ "' the associated class<>(..) invocation must "
+ "include the pybind11::buffer_protocol() annotation!");
+
tinfo->get_buffer = get_buffer;
tinfo->get_buffer_data = get_buffer_data;
}
- static int getbuffer(PyObject *obj, Py_buffer *view, int flags) {
- auto tinfo = detail::get_type_info(Py_TYPE(obj));
- if (view == nullptr || obj == nullptr || !tinfo || !tinfo->get_buffer) {
- PyErr_SetString(PyExc_BufferError, "generic_type::getbuffer(): Internal error");
- return -1;
- }
- memset(view, 0, sizeof(Py_buffer));
- buffer_info *info = tinfo->get_buffer(obj, tinfo->get_buffer_data);
- view->obj = obj;
- view->ndim = 1;
- view->internal = info;
- view->buf = info->ptr;
- view->itemsize = (ssize_t) info->itemsize;
- view->len = view->itemsize;
- for (auto s : info->shape)
- view->len *= s;
- if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT)
- view->format = const_cast<char *>(info->format.c_str());
- if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES) {
- view->ndim = (int) info->ndim;
- view->strides = (ssize_t *) &info->strides[0];
- view->shape = (ssize_t *) &info->shape[0];
- }
- Py_INCREF(view->obj);
- return 0;
- }
+ void def_property_static_impl(const char *name,
+ handle fget, handle fset,
+ detail::function_record *rec_fget) {
+ const auto is_static = !(rec_fget->is_method && rec_fget->scope);
+ const auto has_doc = rec_fget->doc && pybind11::options::show_user_defined_docstrings();
- static void releasebuffer(PyObject *, Py_buffer *view) { delete (buffer_info *) view->internal; }
+ auto property = handle((PyObject *) (is_static ? get_internals().static_property_type
+ : &PyProperty_Type));
+ attr(name) = property(fget.ptr() ? fget : none(),
+ fset.ptr() ? fset : none(),
+ /*deleter*/none(),
+ pybind11::str(has_doc ? rec_fget->doc : ""));
+ }
};
+/// Set the pointer to operator new if it exists. The cast is needed because it can be overloaded.
+template <typename T, typename = void_t<decltype(static_cast<void *(*)(size_t)>(T::operator new))>>
+void set_operator_new(type_record *r) { r->operator_new = &T::operator new; }
+
+template <typename> void set_operator_new(...) { }
+
+/// Call class-specific delete if it exists or global otherwise. Can also be an overload set.
+template <typename T, typename = void_t<decltype(static_cast<void (*)(void *)>(T::operator delete))>>
+void call_operator_delete(T *p) { T::operator delete(p); }
+
+inline void call_operator_delete(void *p) { ::operator delete(p); }
+
NAMESPACE_END(detail)
template <typename type_, typename... options>
@@ -924,12 +880,9 @@ class class_ : public detail::generic_type {
template <typename T> using is_holder = detail::is_holder_type<type_, T>;
template <typename T> using is_subtype = detail::bool_constant<std::is_base_of<type_, T>::value && !std::is_same<T, type_>::value>;
template <typename T> using is_base = detail::bool_constant<std::is_base_of<T, type_>::value && !std::is_same<T, type_>::value>;
- template <typename T> using is_valid_class_option =
- detail::bool_constant<
- is_holder<T>::value ||
- is_subtype<T>::value ||
- is_base<T>::value
- >;
+ // struct instead of using here to help MSVC:
+ template <typename T> struct is_valid_class_option :
+ detail::any_of<is_holder<T>, is_subtype<T>, is_base<T>> {};
public:
using type = type_;
@@ -938,33 +891,46 @@ public:
using holder_type = detail::first_of_t<is_holder, std::unique_ptr<type>, options...>;
using instance_type = detail::instance<type, holder_type>;
- static_assert(detail::all_of_t<is_valid_class_option, options...>::value,
+ static_assert(detail::all_of<is_valid_class_option<options>...>::value,
"Unknown/invalid class_ template parameters provided");
PYBIND11_OBJECT(class_, generic_type, PyType_Check)
template <typename... Extra>
class_(handle scope, const char *name, const Extra &... extra) {
- detail::type_record record;
+ using namespace detail;
+
+ // MI can only be specified via class_ template options, not constructor parameters
+ static_assert(
+ none_of<is_pyobject<Extra>...>::value || // no base class arguments, or:
+ ( constexpr_sum(is_pyobject<Extra>::value...) == 1 && // Exactly one base
+ constexpr_sum(is_base<options>::value...) == 0 && // no template option bases
+ none_of<std::is_same<multiple_inheritance, Extra>...>::value), // no multiple_inheritance attr
+ "Error: multiple inheritance bases must be specified via class_ template options");
+
+ type_record record;
record.scope = scope;
record.name = name;
record.type = &typeid(type);
- record.type_size = sizeof(detail::conditional_t<has_alias, type_alias, type>);
+ record.type_size = sizeof(conditional_t<has_alias, type_alias, type>);
record.instance_size = sizeof(instance_type);
record.init_holder = init_holder;
record.dealloc = dealloc;
+ record.default_holder = std::is_same<holder_type, std::unique_ptr<type>>::value;
+
+ set_operator_new<type>(&record);
/* Register base classes specified via template arguments to class_, if any */
bool unused[] = { (add_base<options>(record), false)..., false };
(void) unused;
/* Process optional arguments, if any */
- detail::process_attributes<Extra...>::init(extra..., &record);
+ process_attributes<Extra...>::init(extra..., &record);
- detail::generic_type::initialize(&record);
+ generic_type::initialize(record);
if (has_alias) {
- auto &instances = pybind11::detail::get_internals().registered_types_cpp;
+ auto &instances = get_internals().registered_types_cpp;
instances[std::type_index(typeid(type_alias))] = instances[std::type_index(typeid(type))];
}
}
@@ -988,7 +954,9 @@ public:
}
template <typename Func, typename... Extra> class_ &
- def_static(const char *name_, Func f, const Extra&... extra) {
+ def_static(const char *name_, Func &&f, const Extra&... extra) {
+ static_assert(!std::is_member_function_pointer<Func>::value,
+ "def_static(...) called with a non-static member function pointer");
cpp_function cf(std::forward<Func>(f), name(name_), scope(*this),
sibling(getattr(*this, name_, none())), extra...);
attr(cf.name()) = cf;
@@ -1023,7 +991,7 @@ public:
struct capture { Func func; };
capture *ptr = new capture { std::forward<Func>(func) };
install_buffer_funcs([](PyObject *obj, void *ptr) -> buffer_info* {
- detail::type_caster<type> caster;
+ detail::make_caster<type> caster;
if (!caster.load(obj, false))
return nullptr;
return new buffer_info(((capture *) ptr)->func(caster));
@@ -1121,14 +1089,7 @@ public:
rec_fset->doc = strdup(rec_fset->doc);
}
}
- pybind11::str doc_obj = pybind11::str((rec_fget->doc && pybind11::options::show_user_defined_docstrings()) ? rec_fget->doc : "");
- const auto property = reinterpret_steal<object>(
- PyObject_CallFunctionObjArgs((PyObject *) &PyProperty_Type, fget.ptr() ? fget.ptr() : Py_None,
- fset.ptr() ? fset.ptr() : Py_None, Py_None, doc_obj.ptr(), nullptr));
- if (rec_fget->is_method && rec_fget->scope)
- attr(name) = property;
- else
- metaclass().attr(name) = property;
+ def_property_static_impl(name, fget, fset, rec_fget);
return *this;
}
@@ -1147,24 +1108,22 @@ private:
}
}
+ static void init_holder_from_existing(instance_type *inst, const holder_type *holder_ptr,
+ std::true_type /*is_copy_constructible*/) {
+ new (&inst->holder) holder_type(*holder_ptr);
+ }
+
+ static void init_holder_from_existing(instance_type *inst, const holder_type *holder_ptr,
+ std::false_type /*is_copy_constructible*/) {
+ new (&inst->holder) holder_type(std::move(*const_cast<holder_type *>(holder_ptr)));
+ }
+
/// Initialize holder object, variant 2: try to construct from existing holder object, if possible
- template <typename T = holder_type,
- detail::enable_if_t<std::is_copy_constructible<T>::value, int> = 0>
static void init_holder_helper(instance_type *inst, const holder_type *holder_ptr, const void * /* dummy */) {
if (holder_ptr) {
- new (&inst->holder) holder_type(*holder_ptr);
+ init_holder_from_existing(inst, holder_ptr, std::is_copy_constructible<holder_type>());
inst->holder_constructed = true;
- } else if (inst->owned) {
- new (&inst->holder) holder_type(inst->value);
- inst->holder_constructed = true;
- }
- }
-
- /// Initialize holder object, variant 3: holder is not copy constructible (e.g. unique_ptr), always initialize from raw pointer
- template <typename T = holder_type,
- detail::enable_if_t<!std::is_copy_constructible<T>::value, int> = 0>
- static void init_holder_helper(instance_type *inst, const holder_type * /* unused */, const void * /* dummy */) {
- if (inst->owned) {
+ } else if (inst->owned || detail::always_construct_holder<holder_type>::value) {
new (&inst->holder) holder_type(inst->value);
inst->holder_constructed = true;
}
@@ -1181,14 +1140,12 @@ private:
if (inst->holder_constructed)
inst->holder.~holder_type();
else if (inst->owned)
- ::operator delete(inst->value);
-
- generic_type::dealloc((detail::instance<void> *) inst);
+ detail::call_operator_delete(inst->value);
}
static detail::function_record *get_function_record(handle h) {
h = detail::get_function(h);
- return h ? (detail::function_record *) reinterpret_borrow<capsule>(PyCFunction_GetSelf(h.ptr()))
+ return h ? (detail::function_record *) reinterpret_borrow<capsule>(PyCFunction_GET_SELF(h.ptr()))
: nullptr;
}
};
@@ -1197,26 +1154,33 @@ private:
template <typename Type> class enum_ : public class_<Type> {
public:
using class_<Type>::def;
+ using class_<Type>::def_property_readonly_static;
using Scalar = typename std::underlying_type<Type>::type;
template <typename T> using arithmetic_tag = std::is_same<T, arithmetic>;
template <typename... Extra>
enum_(const handle &scope, const char *name, const Extra&... extra)
- : class_<Type>(scope, name, extra...), m_parent(scope) {
+ : class_<Type>(scope, name, extra...), m_entries(), m_parent(scope) {
constexpr bool is_arithmetic =
!std::is_same<detail::first_of_t<arithmetic_tag, void, Extra...>,
void>::value;
- auto entries = new std::unordered_map<Scalar, const char *>();
- def("__repr__", [name, entries](Type value) -> std::string {
- auto it = entries->find((Scalar) value);
- return std::string(name) + "." +
- ((it == entries->end()) ? std::string("???")
- : std::string(it->second));
+ auto m_entries_ptr = m_entries.inc_ref().ptr();
+ def("__repr__", [name, m_entries_ptr](Type value) -> pybind11::str {
+ for (const auto &kv : reinterpret_borrow<dict>(m_entries_ptr)) {
+ if (pybind11::cast<Type>(kv.second) == value)
+ return pybind11::str("{}.{}").format(name, kv.first);
+ }
+ return pybind11::str("{}.???").format(name);
});
+ def_property_readonly_static("__members__", [m_entries_ptr](object /* self */) {
+ dict m;
+ for (const auto &kv : reinterpret_borrow<dict>(m_entries_ptr))
+ m[kv.first] = kv.second;
+ return m;
+ }, return_value_policy::copy);
def("__init__", [](Type& value, Scalar i) { value = (Type)i; });
- def("__init__", [](Type& value, Scalar i) { new (&value) Type((Type) i); });
def("__int__", [](Type value) { return (Scalar) value; });
def("__eq__", [](const Type &value, Type *value2) { return value2 && value == *value2; });
def("__ne__", [](const Type &value, Type *value2) { return !value2 || value != *value2; });
@@ -1253,28 +1217,25 @@ public:
// Pickling and unpickling -- needed for use with the 'multiprocessing' module
def("__getstate__", [](const Type &value) { return pybind11::make_tuple((Scalar) value); });
def("__setstate__", [](Type &p, tuple t) { new (&p) Type((Type) t[0].cast<Scalar>()); });
- m_entries = entries;
}
/// Export enumeration entries into the parent scope
- enum_ &export_values() {
- PyObject *dict = ((PyTypeObject *) this->m_ptr)->tp_dict;
- PyObject *key, *value;
- ssize_t pos = 0;
- while (PyDict_Next(dict, &pos, &key, &value))
- if (PyObject_IsInstance(value, this->m_ptr))
- m_parent.attr(key) = value;
+ enum_& export_values() {
+ for (const auto &kv : m_entries)
+ m_parent.attr(kv.first) = kv.second;
return *this;
}
/// Add an enumeration entry
enum_& value(char const* name, Type value) {
- this->attr(name) = pybind11::cast(value, return_value_policy::copy);
- (*m_entries)[(Scalar) value] = name;
+ auto v = pybind11::cast(value, return_value_policy::copy);
+ this->attr(name) = v;
+ m_entries[pybind11::str(name)] = v;
return *this;
}
+
private:
- std::unordered_map<Scalar, const char *> *m_entries;
+ dict m_entries;
handle m_parent;
};
@@ -1336,11 +1297,11 @@ inline void keep_alive_impl(handle nurse, handle patient) {
(void) wr.release();
}
-PYBIND11_NOINLINE inline void keep_alive_impl(int Nurse, int Patient, handle args, handle ret) {
- handle nurse (Nurse > 0 ? PyTuple_GetItem(args.ptr(), Nurse - 1) : ret.ptr());
- handle patient(Patient > 0 ? PyTuple_GetItem(args.ptr(), Patient - 1) : ret.ptr());
-
- keep_alive_impl(nurse, patient);
+PYBIND11_NOINLINE inline void keep_alive_impl(size_t Nurse, size_t Patient, function_call &call, handle ret) {
+ keep_alive_impl(
+ Nurse == 0 ? ret : Nurse <= call.args.size() ? call.args[Nurse - 1] : handle(),
+ Patient == 0 ? ret : Patient <= call.args.size() ? call.args[Patient - 1] : handle()
+ );
}
template <typename Iterator, typename Sentinel, bool KeyIterator, return_value_policy Policy>
@@ -1355,6 +1316,7 @@ NAMESPACE_END(detail)
template <typename... Args> detail::init<Args...> init() { return detail::init<Args...>(); }
template <typename... Args> detail::init_alias<Args...> init_alias() { return detail::init_alias<Args...>(); }
+/// Makes a python iterator from a first and past-the-end C++ InputIterator.
template <return_value_policy Policy = return_value_policy::reference_internal,
typename Iterator,
typename Sentinel,
@@ -1380,6 +1342,8 @@ iterator make_iterator(Iterator first, Sentinel last, Extra &&... extra) {
return (iterator) cast(state { first, last, true });
}
+/// Makes an python iterator over the keys (`.first`) of a iterator over pairs from a
+/// first and past-the-end InputIterator.
template <return_value_policy Policy = return_value_policy::reference_internal,
typename Iterator,
typename Sentinel,
@@ -1405,11 +1369,15 @@ iterator make_key_iterator(Iterator first, Sentinel last, Extra &&... extra) {
return (iterator) cast(state { first, last, true });
}
+/// Makes an iterator over values of an stl container or other container supporting
+/// `std::begin()`/`std::end()`
template <return_value_policy Policy = return_value_policy::reference_internal,
typename Type, typename... Extra> iterator make_iterator(Type &value, Extra&&... extra) {
return make_iterator<Policy>(std::begin(value), std::end(value), extra...);
}
+/// Makes an iterator over the keys (`.first`) of a stl map-like container supporting
+/// `std::begin()`/`std::end()`
template <return_value_policy Policy = return_value_policy::reference_internal,
typename Type, typename... Extra> iterator make_key_iterator(Type &value, Extra&&... extra) {
return make_key_iterator<Policy>(std::begin(value), std::end(value), extra...);
@@ -1417,7 +1385,7 @@ template <return_value_policy Policy = return_value_policy::reference_internal,
template <typename InputType, typename OutputType> void implicitly_convertible() {
auto implicit_caster = [](PyObject *obj, PyTypeObject *type) -> PyObject * {
- if (!detail::type_caster<InputType>().load(obj, false))
+ if (!detail::make_caster<InputType>().load(obj, false))
return nullptr;
tuple args(1);
args[0] = obj;
@@ -1451,7 +1419,7 @@ public:
exception(handle scope, const char *name, PyObject *base = PyExc_Exception) {
std::string full_name = scope.attr("__name__").cast<std::string>() +
std::string(".") + name;
- m_ptr = PyErr_NewException((char *) full_name.c_str(), base, NULL);
+ m_ptr = PyErr_NewException(const_cast<char *>(full_name.c_str()), base, NULL);
if (hasattr(scope, name))
pybind11_fail("Error during initialization: multiple incompatible "
"definitions with name \"" + std::string(name) + "\"");
@@ -1524,7 +1492,7 @@ void print(Args &&...args) {
detail::print(c.args(), c.kwargs());
}
-#if defined(WITH_THREAD)
+#if defined(WITH_THREAD) && !defined(PYPY_VERSION)
/* The functions below essentially reproduce the PyGILState_* API using a RAII
* pattern, but there are a few important differences:
@@ -1647,6 +1615,20 @@ private:
PyThreadState *tstate;
bool disassoc;
};
+#elif defined(PYPY_VERSION)
+class gil_scoped_acquire {
+ PyGILState_STATE state;
+public:
+ gil_scoped_acquire() { state = PyGILState_Ensure(); }
+ ~gil_scoped_acquire() { PyGILState_Release(state); }
+};
+
+class gil_scoped_release {
+ PyThreadState *state;
+public:
+ gil_scoped_release() { state = PyEval_SaveThread(); }
+ ~gil_scoped_release() { PyEval_RestoreThread(state); }
+};
#else
class gil_scoped_acquire { };
class gil_scoped_release { };
@@ -1655,16 +1637,15 @@ class gil_scoped_release { };
error_already_set::~error_already_set() {
if (value) {
gil_scoped_acquire gil;
- PyErr_Restore(type, value, trace);
- PyErr_Clear();
+ clear();
}
}
inline function get_type_overload(const void *this_ptr, const detail::type_info *this_type, const char *name) {
- handle py_object = detail::get_object_handle(this_ptr, this_type);
- if (!py_object)
+ handle self = detail::get_object_handle(this_ptr, this_type);
+ if (!self)
return function();
- handle type = py_object.get_type();
+ handle type = self.get_type();
auto key = std::make_pair(type.ptr(), name);
/* Cache functions that aren't overloaded in Python to avoid
@@ -1673,22 +1654,47 @@ inline function get_type_overload(const void *this_ptr, const detail::type_info
if (cache.find(key) != cache.end())
return function();
- function overload = getattr(py_object, name, function());
+ function overload = getattr(self, name, function());
if (overload.is_cpp_function()) {
cache.insert(key);
return function();
}
- /* Don't call dispatch code if invoked from overridden function */
+ /* Don't call dispatch code if invoked from overridden function.
+ Unfortunately this doesn't work on PyPy. */
+#if !defined(PYPY_VERSION)
PyFrameObject *frame = PyThreadState_Get()->frame;
if (frame && (std::string) str(frame->f_code->co_name) == name &&
frame->f_code->co_argcount > 0) {
PyFrame_FastToLocals(frame);
PyObject *self_caller = PyDict_GetItem(
frame->f_locals, PyTuple_GET_ITEM(frame->f_code->co_varnames, 0));
- if (self_caller == py_object.ptr())
+ if (self_caller == self.ptr())
return function();
}
+#else
+ /* PyPy currently doesn't provide a detailed cpyext emulation of
+ frame objects, so we have to emulate this using Python. This
+ is going to be slow..*/
+ dict d; d["self"] = self; d["name"] = pybind11::str(name);
+ PyObject *result = PyRun_String(
+ "import inspect\n"
+ "frame = inspect.currentframe()\n"
+ "if frame is not None:\n"
+ " frame = frame.f_back\n"
+ " if frame is not None and str(frame.f_code.co_name) == name and "
+ "frame.f_code.co_argcount > 0:\n"
+ " self_caller = frame.f_locals[frame.f_code.co_varnames[0]]\n"
+ " if self_caller == self:\n"
+ " self = None\n",
+ Py_file_input, d.ptr(), d.ptr());
+ if (result == nullptr)
+ throw error_already_set();
+ if ((handle) d["self"] == Py_None)
+ return function();
+ Py_DECREF(result);
+#endif
+
return overload;
}
diff --git a/ext/pybind11/include/pybind11/pytypes.h b/ext/pybind11/include/pybind11/pytypes.h
index 2b49ecfc9..900c57564 100644
--- a/ext/pybind11/include/pybind11/pytypes.h
+++ b/ext/pybind11/include/pybind11/pytypes.h
@@ -45,51 +45,130 @@ using tuple_accessor = accessor<accessor_policies::tuple_item>;
class pyobject_tag { };
template <typename T> using is_pyobject = std::is_base_of<pyobject_tag, typename std::remove_reference<T>::type>;
-/// Mixin which adds common functions to handle, object and various accessors.
-/// The only requirement for `Derived` is to implement `PyObject *Derived::ptr() const`.
+/** \rst
+ A mixin class which adds common functions to `handle`, `object` and various accessors.
+ The only requirement for `Derived` is to implement ``PyObject *Derived::ptr() const``.
+\endrst */
template <typename Derived>
class object_api : public pyobject_tag {
const Derived &derived() const { return static_cast<const Derived &>(*this); }
public:
+ /** \rst
+ Return an iterator equivalent to calling ``iter()`` in Python. The object
+ must be a collection which supports the iteration protocol.
+ \endrst */
iterator begin() const;
+ /// Return a sentinel which ends iteration.
iterator end() const;
+
+ /** \rst
+ Return an internal functor to invoke the object's sequence protocol. Casting
+ the returned ``detail::item_accessor`` instance to a `handle` or `object`
+ subclass causes a corresponding call to ``__getitem__``. Assigning a `handle`
+ or `object` subclass causes a call to ``__setitem__``.
+ \endrst */
item_accessor operator[](handle key) const;
+ /// See above (the only difference is that they key is provided as a string literal)
item_accessor operator[](const char *key) const;
+
+ /** \rst
+ Return an internal functor to access the object's attributes. Casting the
+ returned ``detail::obj_attr_accessor`` instance to a `handle` or `object`
+ subclass causes a corresponding call to ``getattr``. Assigning a `handle`
+ or `object` subclass causes a call to ``setattr``.
+ \endrst */
obj_attr_accessor attr(handle key) const;
+ /// See above (the only difference is that they key is provided as a string literal)
str_attr_accessor attr(const char *key) const;
+
+ /** \rst
+ Matches * unpacking in Python, e.g. to unpack arguments out of a ``tuple``
+ or ``list`` for a function call. Applying another * to the result yields
+ ** unpacking, e.g. to unpack a dict as function keyword arguments.
+ See :ref:`calling_python_functions`.
+ \endrst */
args_proxy operator*() const;
- template <typename T> bool contains(T &&key) const;
+ /// Check if the given item is contained within this object, i.e. ``item in obj``.
+ template <typename T> bool contains(T &&item) const;
+
+ /** \rst
+ Assuming the Python object is a function or implements the ``__call__``
+ protocol, ``operator()`` invokes the underlying function, passing an
+ arbitrary set of parameters. The result is returned as a `object` and
+ may need to be converted back into a Python object using `handle::cast()`.
+
+ When some of the arguments cannot be converted to Python objects, the
+ function will throw a `cast_error` exception. When the Python function
+ call fails, a `error_already_set` exception is thrown.
+ \endrst */
template <return_value_policy policy = return_value_policy::automatic_reference, typename... Args>
object operator()(Args &&...args) const;
template <return_value_policy policy = return_value_policy::automatic_reference, typename... Args>
PYBIND11_DEPRECATED("call(...) was deprecated in favor of operator()(...)")
object call(Args&&... args) const;
+ /// Equivalent to ``obj is None`` in Python.
bool is_none() const { return derived().ptr() == Py_None; }
- PYBIND11_DEPRECATED("Instead of obj.str(), use py::str(obj)")
+ PYBIND11_DEPRECATED("Use py::str(obj) instead")
pybind11::str str() const;
+ /// Return the object's current reference count
int ref_count() const { return static_cast<int>(Py_REFCNT(derived().ptr())); }
+ /// Return a handle to the Python type object underlying the instance
handle get_type() const;
};
NAMESPACE_END(detail)
-/// Holds a reference to a Python object (no reference counting)
+/** \rst
+ Holds a reference to a Python object (no reference counting)
+
+ The `handle` class is a thin wrapper around an arbitrary Python object (i.e. a
+ ``PyObject *`` in Python's C API). It does not perform any automatic reference
+ counting and merely provides a basic C++ interface to various Python API functions.
+
+ .. seealso::
+ The `object` class inherits from `handle` and adds automatic reference
+ counting features.
+\endrst */
class handle : public detail::object_api<handle> {
public:
+ /// The default constructor creates a handle with a ``nullptr``-valued pointer
handle() = default;
+ /// Creates a ``handle`` from the given raw Python object pointer
handle(PyObject *ptr) : m_ptr(ptr) { } // Allow implicit conversion from PyObject*
+ /// Return the underlying ``PyObject *`` pointer
PyObject *ptr() const { return m_ptr; }
PyObject *&ptr() { return m_ptr; }
- const handle& inc_ref() const { Py_XINCREF(m_ptr); return *this; }
- const handle& dec_ref() const { Py_XDECREF(m_ptr); return *this; }
+ /** \rst
+ Manually increase the reference count of the Python object. Usually, it is
+ preferable to use the `object` class which derives from `handle` and calls
+ this function automatically. Returns a reference to itself.
+ \endrst */
+ const handle& inc_ref() const & { Py_XINCREF(m_ptr); return *this; }
+
+ /** \rst
+ Manually decrease the reference count of the Python object. Usually, it is
+ preferable to use the `object` class which derives from `handle` and calls
+ this function automatically. Returns a reference to itself.
+ \endrst */
+ const handle& dec_ref() const & { Py_XDECREF(m_ptr); return *this; }
+
+ /** \rst
+ Attempt to cast the Python object into the given C++ type. A `cast_error`
+ will be throw upon failure.
+ \endrst */
template <typename T> T cast() const;
+ /// Return ``true`` when the `handle` wraps a valid Python object
explicit operator bool() const { return m_ptr != nullptr; }
+ /** \rst
+ Check that the underlying pointers are the same.
+ Equivalent to ``obj1 is obj2`` in Python.
+ \endrst */
bool operator==(const handle &h) const { return m_ptr == h.m_ptr; }
bool operator!=(const handle &h) const { return m_ptr != h.m_ptr; }
PYBIND11_DEPRECATED("Use handle::operator bool() instead")
@@ -98,16 +177,33 @@ protected:
PyObject *m_ptr = nullptr;
};
-/// Holds a reference to a Python object (with reference counting)
+/** \rst
+ Holds a reference to a Python object (with reference counting)
+
+ Like `handle`, the `object` class is a thin wrapper around an arbitrary Python
+ object (i.e. a ``PyObject *`` in Python's C API). In contrast to `handle`, it
+ optionally increases the object's reference count upon construction, and it
+ *always* decreases the reference count when the `object` instance goes out of
+ scope and is destructed. When using `object` instances consistently, it is much
+ easier to get reference counting right at the first attempt.
+\endrst */
class object : public handle {
public:
object() = default;
PYBIND11_DEPRECATED("Use reinterpret_borrow<object>() or reinterpret_steal<object>()")
object(handle h, bool is_borrowed) : handle(h) { if (is_borrowed) inc_ref(); }
+ /// Copy constructor; always increases the reference count
object(const object &o) : handle(o) { inc_ref(); }
+ /// Move constructor; steals the object from ``other`` and preserves its reference count
object(object &&other) noexcept { m_ptr = other.m_ptr; other.m_ptr = nullptr; }
+ /// Destructor; automatically calls `handle::dec_ref()`
~object() { dec_ref(); }
+ /** \rst
+ Resets the internal pointer to ``nullptr`` without without decreasing the
+ object's reference count. The function returns a raw handle to the original
+ Python object.
+ \endrst */
handle release() {
PyObject *tmp = m_ptr;
m_ptr = nullptr;
@@ -150,14 +246,43 @@ public:
object(handle h, stolen_t) : handle(h) { }
};
-/** The following functions don't do any kind of conversion, they simply declare
- that a PyObject is a certain type and borrow or steal the reference. */
+/** \rst
+ Declare that a `handle` or ``PyObject *`` is a certain type and borrow the reference.
+ The target type ``T`` must be `object` or one of its derived classes. The function
+ doesn't do any conversions or checks. It's up to the user to make sure that the
+ target type is correct.
+
+ .. code-block:: cpp
+
+ PyObject *p = PyList_GetItem(obj, index);
+ py::object o = reinterpret_borrow<py::object>(p);
+ // or
+ py::tuple t = reinterpret_borrow<py::tuple>(p); // <-- `p` must be already be a `tuple`
+\endrst */
template <typename T> T reinterpret_borrow(handle h) { return {h, object::borrowed}; }
+
+/** \rst
+ Like `reinterpret_borrow`, but steals the reference.
+
+ .. code-block:: cpp
+
+ PyObject *p = PyObject_Str(obj);
+ py::str s = reinterpret_steal<py::str>(p); // <-- `p` must be already be a `str`
+\endrst */
template <typename T> T reinterpret_steal(handle h) { return {h, object::stolen}; }
-/// Check if `obj` is an instance of type `T`
+/** \defgroup python_builtins _
+ Unless stated otherwise, the following C++ functions behave the same
+ as their Python counterparts.
+ */
+
+/** \ingroup python_builtins
+ \rst
+ Return true if ``obj`` is an instance of ``T``. Type ``T`` must be a subclass of
+ `object` or a class which was exposed to Python as ``py::class_<T>``.
+\endrst */
template <typename T, detail::enable_if_t<std::is_base_of<object, T>::value, int> = 0>
-bool isinstance(handle obj) { return T::_check(obj); }
+bool isinstance(handle obj) { return T::check_(obj); }
template <typename T, detail::enable_if_t<!std::is_base_of<object, T>::value, int> = 0>
bool isinstance(handle obj) { return detail::isinstance_generic(obj, typeid(T)); }
@@ -165,6 +290,17 @@ bool isinstance(handle obj) { return detail::isinstance_generic(obj, typeid(T));
template <> inline bool isinstance<handle>(handle obj) = delete;
template <> inline bool isinstance<object>(handle obj) { return obj.ptr() != nullptr; }
+/// \ingroup python_builtins
+/// Return true if ``obj`` is an instance of the ``type``.
+inline bool isinstance(handle obj, handle type) {
+ const auto result = PyObject_IsInstance(obj.ptr(), type.ptr());
+ if (result == -1)
+ throw error_already_set();
+ return result != 0;
+}
+
+/// \addtogroup python_builtins
+/// @{
inline bool hasattr(handle obj, handle name) {
return PyObject_HasAttr(obj.ptr(), name.ptr()) == 1;
}
@@ -210,6 +346,7 @@ inline void setattr(handle obj, handle name, handle value) {
inline void setattr(handle obj, const char *name, handle value) {
if (PyObject_SetAttrString(obj.ptr(), name, value.ptr()) != 0) { throw error_already_set(); }
}
+/// @} python_builtins
NAMESPACE_BEGIN(detail)
inline handle get_function(handle value) {
@@ -316,7 +453,7 @@ struct sequence_item {
static object get(handle obj, size_t index) {
PyObject *result = PySequence_GetItem(obj.ptr(), static_cast<ssize_t>(index));
if (!result) { throw error_already_set(); }
- return reinterpret_borrow<object>(result);
+ return reinterpret_steal<object>(result);
}
static void set(handle obj, size_t index, handle val) {
@@ -362,24 +499,131 @@ struct tuple_item {
};
NAMESPACE_END(accessor_policies)
-struct dict_iterator {
+/// STL iterator template used for tuple, list, sequence and dict
+template <typename Policy>
+class generic_iterator : public Policy {
+ using It = generic_iterator;
+
public:
- explicit dict_iterator(handle dict = handle(), ssize_t pos = -1) : dict(dict), pos(pos) { }
- dict_iterator& operator++() {
- if (!PyDict_Next(dict.ptr(), &pos, &key.ptr(), &value.ptr()))
- pos = -1;
- return *this;
- }
- std::pair<handle, handle> operator*() const {
- return std::make_pair(key, value);
- }
- bool operator==(const dict_iterator &it) const { return it.pos == pos; }
- bool operator!=(const dict_iterator &it) const { return it.pos != pos; }
+ using difference_type = ssize_t;
+ using iterator_category = typename Policy::iterator_category;
+ using value_type = typename Policy::value_type;
+ using reference = typename Policy::reference;
+ using pointer = typename Policy::pointer;
+
+ generic_iterator() = default;
+ generic_iterator(handle seq, ssize_t index) : Policy(seq, index) { }
+
+ reference operator*() const { return Policy::dereference(); }
+ reference operator[](difference_type n) const { return *(*this + n); }
+ pointer operator->() const { return **this; }
+
+ It &operator++() { Policy::increment(); return *this; }
+ It operator++(int) { auto copy = *this; Policy::increment(); return copy; }
+ It &operator--() { Policy::decrement(); return *this; }
+ It operator--(int) { auto copy = *this; Policy::decrement(); return copy; }
+ It &operator+=(difference_type n) { Policy::advance(n); return *this; }
+ It &operator-=(difference_type n) { Policy::advance(-n); return *this; }
+
+ friend It operator+(const It &a, difference_type n) { auto copy = a; return copy += n; }
+ friend It operator+(difference_type n, const It &b) { return b + n; }
+ friend It operator-(const It &a, difference_type n) { auto copy = a; return copy -= n; }
+ friend difference_type operator-(const It &a, const It &b) { return a.distance_to(b); }
+
+ friend bool operator==(const It &a, const It &b) { return a.equal(b); }
+ friend bool operator!=(const It &a, const It &b) { return !(a == b); }
+ friend bool operator< (const It &a, const It &b) { return b - a > 0; }
+ friend bool operator> (const It &a, const It &b) { return b < a; }
+ friend bool operator>=(const It &a, const It &b) { return !(a < b); }
+ friend bool operator<=(const It &a, const It &b) { return !(a > b); }
+};
+
+NAMESPACE_BEGIN(iterator_policies)
+/// Quick proxy class needed to implement ``operator->`` for iterators which can't return pointers
+template <typename T>
+struct arrow_proxy {
+ T value;
+
+ arrow_proxy(T &&value) : value(std::move(value)) { }
+ T *operator->() const { return &value; }
+};
+
+/// Lightweight iterator policy using just a simple pointer: see ``PySequence_Fast_ITEMS``
+class sequence_fast_readonly {
+protected:
+ using iterator_category = std::random_access_iterator_tag;
+ using value_type = handle;
+ using reference = const handle;
+ using pointer = arrow_proxy<const handle>;
+
+ sequence_fast_readonly(handle obj, ssize_t n) : ptr(PySequence_Fast_ITEMS(obj.ptr()) + n) { }
+
+ reference dereference() const { return *ptr; }
+ void increment() { ++ptr; }
+ void decrement() { --ptr; }
+ void advance(ssize_t n) { ptr += n; }
+ bool equal(const sequence_fast_readonly &b) const { return ptr == b.ptr; }
+ ssize_t distance_to(const sequence_fast_readonly &b) const { return ptr - b.ptr; }
+
+private:
+ PyObject **ptr;
+};
+
+/// Full read and write access using the sequence protocol: see ``detail::sequence_accessor``
+class sequence_slow_readwrite {
+protected:
+ using iterator_category = std::random_access_iterator_tag;
+ using value_type = object;
+ using reference = sequence_accessor;
+ using pointer = arrow_proxy<const sequence_accessor>;
+
+ sequence_slow_readwrite(handle obj, ssize_t index) : obj(obj), index(index) { }
+
+ reference dereference() const { return {obj, static_cast<size_t>(index)}; }
+ void increment() { ++index; }
+ void decrement() { --index; }
+ void advance(ssize_t n) { index += n; }
+ bool equal(const sequence_slow_readwrite &b) const { return index == b.index; }
+ ssize_t distance_to(const sequence_slow_readwrite &b) const { return index - b.index; }
+
private:
- handle dict, key, value;
- ssize_t pos = 0;
+ handle obj;
+ ssize_t index;
};
+/// Python's dictionary protocol permits this to be a forward iterator
+class dict_readonly {
+protected:
+ using iterator_category = std::forward_iterator_tag;
+ using value_type = std::pair<handle, handle>;
+ using reference = const value_type;
+ using pointer = arrow_proxy<const value_type>;
+
+ dict_readonly() = default;
+ dict_readonly(handle obj, ssize_t pos) : obj(obj), pos(pos) { increment(); }
+
+ reference dereference() const { return {key, value}; }
+ void increment() { if (!PyDict_Next(obj.ptr(), &pos, &key, &value)) { pos = -1; } }
+ bool equal(const dict_readonly &b) const { return pos == b.pos; }
+
+private:
+ handle obj;
+ PyObject *key, *value;
+ ssize_t pos = -1;
+};
+NAMESPACE_END(iterator_policies)
+
+#if !defined(PYPY_VERSION)
+using tuple_iterator = generic_iterator<iterator_policies::sequence_fast_readonly>;
+using list_iterator = generic_iterator<iterator_policies::sequence_fast_readonly>;
+#else
+using tuple_iterator = generic_iterator<iterator_policies::sequence_slow_readwrite>;
+using list_iterator = generic_iterator<iterator_policies::sequence_slow_readwrite>;
+#endif
+
+using sequence_iterator = generic_iterator<iterator_policies::sequence_slow_readwrite>;
+using dict_iterator = generic_iterator<iterator_policies::dict_readonly>;
+
inline bool PyIterable_Check(PyObject *obj) {
PyObject *iter = PyObject_GetIter(obj);
if (iter) {
@@ -410,12 +654,10 @@ public:
template <typename T> using is_keyword = std::is_base_of<arg, T>;
template <typename T> using is_s_unpacking = std::is_same<args_proxy, T>; // * unpacking
template <typename T> using is_ds_unpacking = std::is_same<kwargs_proxy, T>; // ** unpacking
-template <typename T> using is_positional = bool_constant<
- !is_keyword<T>::value && !is_s_unpacking<T>::value && !is_ds_unpacking<T>::value
->;
-template <typename T> using is_keyword_or_ds = bool_constant<
- is_keyword<T>::value || is_ds_unpacking<T>::value
+template <typename T> using is_positional = satisfies_none_of<T,
+ is_keyword, is_s_unpacking, is_ds_unpacking
>;
+template <typename T> using is_keyword_or_ds = satisfies_any_of<T, is_keyword, is_ds_unpacking>;
// Call argument collector forward declarations
template <return_value_policy policy = return_value_policy::automatic_reference>
@@ -437,7 +679,7 @@ NAMESPACE_END(detail)
Name(handle h, stolen_t) : Parent(h, stolen) { } \
PYBIND11_DEPRECATED("Use py::isinstance<py::python_type>(obj) instead") \
bool check() const { return m_ptr != nullptr && (bool) CheckFun(m_ptr); } \
- static bool _check(handle h) { return h.ptr() != nullptr && CheckFun(h.ptr()); }
+ static bool check_(handle h) { return h.ptr() != nullptr && CheckFun(h.ptr()); }
#define PYBIND11_OBJECT_CVT(Name, Parent, CheckFun, ConvertFun) \
PYBIND11_OBJECT_COMMON(Name, Parent, CheckFun) \
@@ -454,47 +696,74 @@ NAMESPACE_END(detail)
PYBIND11_OBJECT(Name, Parent, CheckFun) \
Name() : Parent() { }
+/// \addtogroup pytypes
+/// @{
+
+/** \rst
+ Wraps a Python iterator so that it can also be used as a C++ input iterator
+
+ Caveat: copying an iterator does not (and cannot) clone the internal
+ state of the Python iterable. This also applies to the post-increment
+ operator. This iterator should only be used to retrieve the current
+ value using ``operator*()``.
+\endrst */
class iterator : public object {
public:
- /** Caveat: copying an iterator does not (and cannot) clone the internal
- state of the Python iterable */
+ using iterator_category = std::input_iterator_tag;
+ using difference_type = ssize_t;
+ using value_type = handle;
+ using reference = const handle;
+ using pointer = const handle *;
+
PYBIND11_OBJECT_DEFAULT(iterator, object, PyIter_Check)
iterator& operator++() {
- if (m_ptr)
- advance();
+ advance();
return *this;
}
- /** Caveat: this postincrement operator does not (and cannot) clone the
- internal state of the Python iterable. It should only be used to
- retrieve the current iterate using <tt>operator*()</tt> */
iterator operator++(int) {
- iterator rv(*this);
- rv.value = value;
- if (m_ptr)
- advance();
+ auto rv = *this;
+ advance();
return rv;
}
- bool operator==(const iterator &it) const { return *it == **this; }
- bool operator!=(const iterator &it) const { return *it != **this; }
-
- handle operator*() const {
- if (!ready && m_ptr) {
+ reference operator*() const {
+ if (m_ptr && !value.ptr()) {
auto& self = const_cast<iterator &>(*this);
self.advance();
- self.ready = true;
}
return value;
}
+ pointer operator->() const { operator*(); return &value; }
+
+ /** \rst
+ The value which marks the end of the iteration. ``it == iterator::sentinel()``
+ is equivalent to catching ``StopIteration`` in Python.
+
+ .. code-block:: cpp
+
+ void foo(py::iterator it) {
+ while (it != py::iterator::sentinel()) {
+ // use `*it`
+ ++it;
+ }
+ }
+ \endrst */
+ static iterator sentinel() { return {}; }
+
+ friend bool operator==(const iterator &a, const iterator &b) { return a->ptr() == b->ptr(); }
+ friend bool operator!=(const iterator &a, const iterator &b) { return a->ptr() != b->ptr(); }
+
private:
- void advance() { value = reinterpret_steal<object>(PyIter_Next(m_ptr)); }
+ void advance() {
+ value = reinterpret_steal<object>(PyIter_Next(m_ptr));
+ if (PyErr_Occurred()) { throw error_already_set(); }
+ }
private:
object value = {};
- bool ready = false;
};
class iterable : public object {
@@ -523,6 +792,10 @@ public:
explicit str(const bytes &b);
+ /** \rst
+ Return a string representation of the object. This is analogous to
+ the ``str()`` function in Python.
+ \endrst */
explicit str(handle h) : object(raw_str(h.ptr()), stolen) { }
operator std::string() const {
@@ -556,12 +829,17 @@ private:
return str_value;
}
};
+/// @} pytypes
inline namespace literals {
-/// String literal version of str
+/** \rst
+ String literal version of `str`
+ \endrst */
inline str operator"" _s(const char *s, size_t size) { return {s, size}; }
}
+/// \addtogroup pytypes
+/// @{
class bytes : public object {
public:
PYBIND11_OBJECT(bytes, object, PYBIND11_BYTES_CHECK)
@@ -726,10 +1004,44 @@ public:
PYBIND11_OBJECT_DEFAULT(capsule, object, PyCapsule_CheckExact)
PYBIND11_DEPRECATED("Use reinterpret_borrow<capsule>() or reinterpret_steal<capsule>()")
capsule(PyObject *ptr, bool is_borrowed) : object(is_borrowed ? object(ptr, borrowed) : object(ptr, stolen)) { }
- explicit capsule(const void *value, void (*destruct)(PyObject *) = nullptr)
+
+ explicit capsule(const void *value)
+ : object(PyCapsule_New(const_cast<void *>(value), nullptr, nullptr), stolen) {
+ if (!m_ptr)
+ pybind11_fail("Could not allocate capsule object!");
+ }
+
+ PYBIND11_DEPRECATED("Please pass a destructor that takes a void pointer as input")
+ capsule(const void *value, void (*destruct)(PyObject *))
: object(PyCapsule_New(const_cast<void*>(value), nullptr, destruct), stolen) {
- if (!m_ptr) pybind11_fail("Could not allocate capsule object!");
+ if (!m_ptr)
+ pybind11_fail("Could not allocate capsule object!");
+ }
+
+ capsule(const void *value, void (*destructor)(void *)) {
+ m_ptr = PyCapsule_New(const_cast<void *>(value), nullptr, [](PyObject *o) {
+ auto destructor = reinterpret_cast<void (*)(void *)>(PyCapsule_GetContext(o));
+ void *ptr = PyCapsule_GetPointer(o, nullptr);
+ destructor(ptr);
+ });
+
+ if (!m_ptr)
+ pybind11_fail("Could not allocate capsule object!");
+
+ if (PyCapsule_SetContext(m_ptr, (void *) destructor) != 0)
+ pybind11_fail("Could not set capsule context!");
}
+
+ capsule(void (*destructor)()) {
+ m_ptr = PyCapsule_New(reinterpret_cast<void *>(destructor), nullptr, [](PyObject *o) {
+ auto destructor = reinterpret_cast<void (*)()>(PyCapsule_GetPointer(o, nullptr));
+ destructor();
+ });
+
+ if (!m_ptr)
+ pybind11_fail("Could not allocate capsule object!");
+ }
+
template <typename T> operator T *() const {
T * result = static_cast<T *>(PyCapsule_GetPointer(m_ptr, nullptr));
if (!result) pybind11_fail("Unable to extract capsule contents!");
@@ -745,6 +1057,8 @@ public:
}
size_t size() const { return (size_t) PyTuple_Size(m_ptr); }
detail::tuple_accessor operator[](size_t index) const { return {*this, index}; }
+ detail::tuple_iterator begin() const { return {*this, 0}; }
+ detail::tuple_iterator end() const { return {*this, PyTuple_GET_SIZE(m_ptr)}; }
};
class dict : public object {
@@ -754,14 +1068,14 @@ public:
if (!m_ptr) pybind11_fail("Could not allocate dict object!");
}
template <typename... Args,
- typename = detail::enable_if_t<detail::all_of_t<detail::is_keyword_or_ds, Args...>::value>,
+ typename = detail::enable_if_t<detail::all_of<detail::is_keyword_or_ds<Args>...>::value>,
// MSVC workaround: it can't compile an out-of-line definition, so defer the collector
typename collector = detail::deferred_t<detail::unpacking_collector<>, Args...>>
explicit dict(Args &&...args) : dict(collector(std::forward<Args>(args)...).kwargs()) { }
size_t size() const { return (size_t) PyDict_Size(m_ptr); }
- detail::dict_iterator begin() const { return (++detail::dict_iterator(*this, 0)); }
- detail::dict_iterator end() const { return detail::dict_iterator(); }
+ detail::dict_iterator begin() const { return {*this, 0}; }
+ detail::dict_iterator end() const { return {}; }
void clear() const { PyDict_Clear(ptr()); }
bool contains(handle key) const { return PyDict_Contains(ptr(), key.ptr()) == 1; }
bool contains(const char *key) const { return PyDict_Contains(ptr(), pybind11::str(key).ptr()) == 1; }
@@ -777,9 +1091,11 @@ private:
class sequence : public object {
public:
- PYBIND11_OBJECT(sequence, object, PySequence_Check)
+ PYBIND11_OBJECT_DEFAULT(sequence, object, PySequence_Check)
size_t size() const { return (size_t) PySequence_Size(m_ptr); }
detail::sequence_accessor operator[](size_t index) const { return {*this, index}; }
+ detail::sequence_iterator begin() const { return {*this, 0}; }
+ detail::sequence_iterator end() const { return {*this, PySequence_Size(m_ptr)}; }
};
class list : public object {
@@ -790,6 +1106,8 @@ public:
}
size_t size() const { return (size_t) PyList_Size(m_ptr); }
detail::list_accessor operator[](size_t index) const { return {*this, index}; }
+ detail::list_iterator begin() const { return {*this, 0}; }
+ detail::list_iterator end() const { return {*this, PyList_GET_SIZE(m_ptr)}; }
template <typename T> void append(T &&val) const {
PyList_Append(m_ptr, detail::object_or_cast(std::forward<T>(val)).ptr());
}
@@ -865,7 +1183,10 @@ public:
PYBIND11_OBJECT_CVT(memoryview, object, PyMemoryView_Check, PyMemoryView_FromObject)
};
+/// @} pytypes
+/// \addtogroup python_builtins
+/// @{
inline size_t len(handle h) {
ssize_t result = PyObject_Length(h.ptr());
if (result < 0)
@@ -884,13 +1205,16 @@ inline str repr(handle h) {
return reinterpret_steal<str>(str_value);
}
-NAMESPACE_BEGIN(detail)
-template <typename D> iterator object_api<D>::begin() const {
- return reinterpret_steal<iterator>(PyObject_GetIter(derived().ptr()));
-}
-template <typename D> iterator object_api<D>::end() const {
- return {};
+inline iterator iter(handle obj) {
+ PyObject *result = PyObject_GetIter(obj.ptr());
+ if (!result) { throw error_already_set(); }
+ return reinterpret_steal<iterator>(result);
}
+/// @} python_builtins
+
+NAMESPACE_BEGIN(detail)
+template <typename D> iterator object_api<D>::begin() const { return iter(derived()); }
+template <typename D> iterator object_api<D>::end() const { return iterator::sentinel(); }
template <typename D> item_accessor object_api<D>::operator[](handle key) const {
return {derived(), reinterpret_borrow<object>(key)};
}
@@ -906,8 +1230,8 @@ template <typename D> str_attr_accessor object_api<D>::attr(const char *key) con
template <typename D> args_proxy object_api<D>::operator*() const {
return args_proxy(derived().ptr());
}
-template <typename D> template <typename T> bool object_api<D>::contains(T &&key) const {
- return attr("__contains__")(std::forward<T>(key)).template cast<bool>();
+template <typename D> template <typename T> bool object_api<D>::contains(T &&item) const {
+ return attr("__contains__")(std::forward<T>(item)).template cast<bool>();
}
template <typename D>
diff --git a/ext/pybind11/include/pybind11/stl.h b/ext/pybind11/include/pybind11/stl.h
index 7d6e8b102..37b6bcde3 100644
--- a/ext/pybind11/include/pybind11/stl.h
+++ b/ext/pybind11/include/pybind11/stl.h
@@ -139,7 +139,7 @@ public:
auto value_ = reinterpret_steal<object>(value_conv::cast(value, policy, parent));
if (!value_)
return handle();
- PyList_SET_ITEM(l.ptr(), index++, value_.release().ptr()); // steals a reference
+ PyList_SET_ITEM(l.ptr(), (ssize_t) index++, value_.release().ptr()); // steals a reference
}
return l.release();
}
@@ -192,7 +192,7 @@ public:
auto value_ = reinterpret_steal<object>(value_conv::cast(value, policy, parent));
if (!value_)
return handle();
- PyList_SET_ITEM(l.ptr(), index++, value_.release().ptr()); // steals a reference
+ PyList_SET_ITEM(l.ptr(), (ssize_t) index++, value_.release().ptr()); // steals a reference
}
return l.release();
}
diff --git a/ext/pybind11/include/pybind11/stl_bind.h b/ext/pybind11/include/pybind11/stl_bind.h
index ef9950ebb..897188220 100644
--- a/ext/pybind11/include/pybind11/stl_bind.h
+++ b/ext/pybind11/include/pybind11/stl_bind.h
@@ -70,7 +70,7 @@ void vector_if_copy_constructible(enable_if_t<
std::is_copy_constructible<Vector>::value &&
std::is_copy_constructible<typename Vector::value_type>::value, Class_> &cl) {
- cl.def(pybind11::init<const Vector &>(), "Copy constructor");
+ cl.def(init<const Vector &>(), "Copy constructor");
}
template<typename Vector, typename Class_>
@@ -93,7 +93,7 @@ void vector_if_equal_operator(enable_if_t<is_comparable<Vector>::value, Class_>
if (p != v.end())
v.erase(p);
else
- throw pybind11::value_error();
+ throw value_error();
},
arg("x"),
"Remove the first item from the list whose value is x. "
@@ -155,7 +155,7 @@ void vector_modifiers(enable_if_t<std::is_copy_constructible<typename Vector::va
cl.def("pop",
[](Vector &v) {
if (v.empty())
- throw pybind11::index_error();
+ throw index_error();
T t = v.back();
v.pop_back();
return t;
@@ -166,7 +166,7 @@ void vector_modifiers(enable_if_t<std::is_copy_constructible<typename Vector::va
cl.def("pop",
[](Vector &v, SizeType i) {
if (i >= v.size())
- throw pybind11::index_error();
+ throw index_error();
T t = v[i];
v.erase(v.begin() + (DiffType) i);
return t;
@@ -178,7 +178,7 @@ void vector_modifiers(enable_if_t<std::is_copy_constructible<typename Vector::va
cl.def("__setitem__",
[](Vector &v, SizeType i, const T &t) {
if (i >= v.size())
- throw pybind11::index_error();
+ throw index_error();
v[i] = t;
}
);
@@ -189,7 +189,7 @@ void vector_modifiers(enable_if_t<std::is_copy_constructible<typename Vector::va
size_t start, stop, step, slicelength;
if (!slice.compute(v.size(), &start, &stop, &step, &slicelength))
- throw pybind11::error_already_set();
+ throw error_already_set();
Vector *seq = new Vector();
seq->reserve((size_t) slicelength);
@@ -208,7 +208,7 @@ void vector_modifiers(enable_if_t<std::is_copy_constructible<typename Vector::va
[](Vector &v, slice slice, const Vector &value) {
size_t start, stop, step, slicelength;
if (!slice.compute(v.size(), &start, &stop, &step, &slicelength))
- throw pybind11::error_already_set();
+ throw error_already_set();
if (slicelength != value.size())
throw std::runtime_error("Left and right hand size of slice assignment have different sizes!");
@@ -224,7 +224,7 @@ void vector_modifiers(enable_if_t<std::is_copy_constructible<typename Vector::va
cl.def("__delitem__",
[](Vector &v, SizeType i) {
if (i >= v.size())
- throw pybind11::index_error();
+ throw index_error();
v.erase(v.begin() + DiffType(i));
},
"Delete the list elements at index ``i``"
@@ -235,7 +235,7 @@ void vector_modifiers(enable_if_t<std::is_copy_constructible<typename Vector::va
size_t start, stop, step, slicelength;
if (!slice.compute(v.size(), &start, &stop, &step, &slicelength))
- throw pybind11::error_already_set();
+ throw error_already_set();
if (step == 1 && false) {
v.erase(v.begin() + (DiffType) start, v.begin() + DiffType(start + slicelength));
@@ -253,8 +253,8 @@ void vector_modifiers(enable_if_t<std::is_copy_constructible<typename Vector::va
// If the type has an operator[] that doesn't return a reference (most notably std::vector<bool>),
// we have to access by copying; otherwise we return by reference.
-template <typename Vector> using vector_needs_copy = bool_constant<
- !std::is_same<decltype(std::declval<Vector>()[typename Vector::size_type()]), typename Vector::value_type &>::value>;
+template <typename Vector> using vector_needs_copy = negation<
+ std::is_same<decltype(std::declval<Vector>()[typename Vector::size_type()]), typename Vector::value_type &>>;
// The usual case: access and iterate by reference
template <typename Vector, typename Class_>
@@ -266,7 +266,7 @@ void vector_accessor(enable_if_t<!vector_needs_copy<Vector>::value, Class_> &cl)
cl.def("__getitem__",
[](Vector &v, SizeType i) -> T & {
if (i >= v.size())
- throw pybind11::index_error();
+ throw index_error();
return v[i];
},
return_value_policy::reference_internal // ref + keepalive
@@ -274,7 +274,7 @@ void vector_accessor(enable_if_t<!vector_needs_copy<Vector>::value, Class_> &cl)
cl.def("__iter__",
[](Vector &v) {
- return pybind11::make_iterator<
+ return make_iterator<
return_value_policy::reference_internal, ItType, ItType, T&>(
v.begin(), v.end());
},
@@ -291,14 +291,14 @@ void vector_accessor(enable_if_t<vector_needs_copy<Vector>::value, Class_> &cl)
cl.def("__getitem__",
[](const Vector &v, SizeType i) -> T {
if (i >= v.size())
- throw pybind11::index_error();
+ throw index_error();
return v[i];
}
);
cl.def("__iter__",
[](Vector &v) {
- return pybind11::make_iterator<
+ return make_iterator<
return_value_policy::copy, ItType, ItType, T>(
v.begin(), v.end());
},
@@ -326,18 +326,64 @@ template <typename Vector, typename Class_> auto vector_if_insertion_operator(Cl
);
}
+// Provide the buffer interface for vectors if we have data() and we have a format for it
+// GCC seems to have "void std::vector<bool>::data()" - doing SFINAE on the existence of data() is insufficient, we need to check it returns an appropriate pointer
+template <typename Vector, typename = void>
+struct vector_has_data_and_format : std::false_type {};
+template <typename Vector>
+struct vector_has_data_and_format<Vector, enable_if_t<std::is_same<decltype(format_descriptor<typename Vector::value_type>::format(), std::declval<Vector>().data()), typename Vector::value_type*>::value>> : std::true_type {};
+
+// Add the buffer interface to a vector
+template <typename Vector, typename Class_, typename... Args>
+enable_if_t<detail::any_of<std::is_same<Args, buffer_protocol>...>::value>
+vector_buffer(Class_& cl) {
+ using T = typename Vector::value_type;
+
+ static_assert(vector_has_data_and_format<Vector>::value, "There is not an appropriate format descriptor for this vector");
+
+ // numpy.h declares this for arbitrary types, but it may raise an exception and crash hard at runtime if PYBIND11_NUMPY_DTYPE hasn't been called, so check here
+ format_descriptor<T>::format();
+
+ cl.def_buffer([](Vector& v) -> buffer_info {
+ return buffer_info(v.data(), sizeof(T), format_descriptor<T>::format(), 1, {v.size()}, {sizeof(T)});
+ });
+
+ cl.def("__init__", [](Vector& vec, buffer buf) {
+ auto info = buf.request();
+ if (info.ndim != 1 || info.strides[0] <= 0 || info.strides[0] % sizeof(T))
+ throw type_error("Only valid 1D buffers can be copied to a vector");
+ if (!detail::compare_buffer_info<T>::compare(info) || sizeof(T) != info.itemsize)
+ throw type_error("Format mismatch (Python: " + info.format + " C++: " + format_descriptor<T>::format() + ")");
+ new (&vec) Vector();
+ vec.reserve(info.shape[0]);
+ T *p = static_cast<T*>(info.ptr);
+ auto step = info.strides[0] / sizeof(T);
+ T *end = p + info.shape[0] * step;
+ for (; p < end; p += step)
+ vec.push_back(*p);
+ });
+
+ return;
+}
+
+template <typename Vector, typename Class_, typename... Args>
+enable_if_t<!detail::any_of<std::is_same<Args, buffer_protocol>...>::value> vector_buffer(Class_&) {}
+
NAMESPACE_END(detail)
//
// std::vector
//
template <typename Vector, typename holder_type = std::unique_ptr<Vector>, typename... Args>
-pybind11::class_<Vector, holder_type> bind_vector(pybind11::module &m, std::string const &name, Args&&... args) {
- using Class_ = pybind11::class_<Vector, holder_type>;
+class_<Vector, holder_type> bind_vector(module &m, std::string const &name, Args&&... args) {
+ using Class_ = class_<Vector, holder_type>;
Class_ cl(m, name.c_str(), std::forward<Args>(args)...);
- cl.def(pybind11::init<>());
+ // Declare the buffer interface if a buffer_protocol() is passed in
+ detail::vector_buffer<Vector, Class_, Args...>(cl);
+
+ cl.def(init<>());
// Register copy constructor (if possible)
detail::vector_if_copy_constructible<Vector, Class_>(cl);
@@ -368,7 +414,7 @@ pybind11::class_<Vector, holder_type> bind_vector(pybind11::module &m, std::stri
#if 0
// C++ style functions deprecated, leaving it here as an example
- cl.def(pybind11::init<size_type>());
+ cl.def(init<size_type>());
cl.def("resize",
(void (Vector::*) (size_type count)) & Vector::resize,
@@ -377,7 +423,7 @@ pybind11::class_<Vector, holder_type> bind_vector(pybind11::module &m, std::stri
cl.def("erase",
[](Vector &v, SizeType i) {
if (i >= v.size())
- throw pybind11::index_error();
+ throw index_error();
v.erase(v.begin() + i);
}, "erases element at index ``i``");
@@ -396,12 +442,12 @@ pybind11::class_<Vector, holder_type> bind_vector(pybind11::module &m, std::stri
cl.def("front", [](Vector &v) {
if (v.size()) return v.front();
- else throw pybind11::index_error();
+ else throw index_error();
}, "access the first element");
cl.def("back", [](Vector &v) {
if (v.size()) return v.back();
- else throw pybind11::index_error();
+ else throw index_error();
}, "access the last element ");
#endif
@@ -484,14 +530,14 @@ template <typename Map, typename Class_> auto map_if_insertion_operator(Class_ &
NAMESPACE_END(detail)
template <typename Map, typename holder_type = std::unique_ptr<Map>, typename... Args>
-pybind11::class_<Map, holder_type> bind_map(module &m, const std::string &name, Args&&... args) {
+class_<Map, holder_type> bind_map(module &m, const std::string &name, Args&&... args) {
using KeyType = typename Map::key_type;
using MappedType = typename Map::mapped_type;
- using Class_ = pybind11::class_<Map, holder_type>;
+ using Class_ = class_<Map, holder_type>;
Class_ cl(m, name.c_str(), std::forward<Args>(args)...);
- cl.def(pybind11::init<>());
+ cl.def(init<>());
// Register stream insertion operator (if possible)
detail::map_if_insertion_operator<Map, Class_>(cl, name);
@@ -502,20 +548,20 @@ pybind11::class_<Map, holder_type> bind_map(module &m, const std::string &name,
);
cl.def("__iter__",
- [](Map &m) { return pybind11::make_key_iterator(m.begin(), m.end()); },
- pybind11::keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */
+ [](Map &m) { return make_key_iterator(m.begin(), m.end()); },
+ keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */
);
cl.def("items",
- [](Map &m) { return pybind11::make_iterator(m.begin(), m.end()); },
- pybind11::keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */
+ [](Map &m) { return make_iterator(m.begin(), m.end()); },
+ keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */
);
cl.def("__getitem__",
[](Map &m, const KeyType &k) -> MappedType & {
auto it = m.find(k);
if (it == m.end())
- throw pybind11::key_error();
+ throw key_error();
return it->second;
},
return_value_policy::reference_internal // ref + keepalive
@@ -528,7 +574,7 @@ pybind11::class_<Map, holder_type> bind_map(module &m, const std::string &name,
[](Map &m, const KeyType &k) {
auto it = m.find(k);
if (it == m.end())
- throw pybind11::key_error();
+ throw key_error();
return m.erase(it);
}
);