Commit beece207 authored by Davis King's avatar Davis King

Updated to pybind11 2.2.2

parent 5bde5c52
...@@ -87,8 +87,9 @@ In addition to the core functionality, pybind11 provides some extra goodies: ...@@ -87,8 +87,9 @@ In addition to the core functionality, pybind11 provides some extra goodies:
[reported](http://graylab.jhu.edu/RosettaCon2016/PyRosetta-4.pdf) a binary [reported](http://graylab.jhu.edu/RosettaCon2016/PyRosetta-4.pdf) a binary
size reduction of **5.4x** and compile time reduction by **5.8x**. size reduction of **5.4x** and compile time reduction by **5.8x**.
- Function signatures are precomputed at compile time (using ``constexpr``), - When supported by the compiler, two new C++14 features (relaxed constexpr and
leading to smaller binaries. return value deduction) are used to precompute function signatures at compile
time, leading to smaller binaries.
- With little extra effort, C++ types can be pickled and unpickled similar to - With little extra effort, C++ types can be pickled and unpickled similar to
regular Python objects. regular Python objects.
......
...@@ -778,7 +778,7 @@ template <typename T1, typename T2> struct is_copy_constructible<std::pair<T1, T ...@@ -778,7 +778,7 @@ template <typename T1, typename T2> struct is_copy_constructible<std::pair<T1, T
template <typename type> class type_caster_base : public type_caster_generic { template <typename type> class type_caster_base : public type_caster_generic {
using itype = intrinsic_t<type>; using itype = intrinsic_t<type>;
public: public:
static constexpr auto name = _<type>(); static PYBIND11_DESCR name() { return type_descr(_<type>()); }
type_caster_base() : type_caster_base(typeid(type)) { } type_caster_base() : type_caster_base(typeid(type)) { }
explicit type_caster_base(const std::type_info &info) : type_caster_generic(info) { } explicit type_caster_base(const std::type_info &info) : type_caster_generic(info) { }
...@@ -835,7 +835,7 @@ public: ...@@ -835,7 +835,7 @@ public:
nullptr, nullptr, holder); nullptr, nullptr, holder);
} }
template <typename T> using cast_op_type = detail::cast_op_type<T>; template <typename T> using cast_op_type = cast_op_type<T>;
operator itype*() { return (type *) value; } operator itype*() { return (type *) value; }
operator itype&() { if (!value) throw reference_cast_error(); return *((itype *) value); } operator itype&() { if (!value) throw reference_cast_error(); return *((itype *) value); }
...@@ -885,7 +885,7 @@ private: ...@@ -885,7 +885,7 @@ private:
"std::reference_wrapper<T> caster requires T to have a caster with an `T &` operator"); "std::reference_wrapper<T> caster requires T to have a caster with an `T &` operator");
public: public:
bool load(handle src, bool convert) { return subcaster.load(src, convert); } bool load(handle src, bool convert) { return subcaster.load(src, convert); }
static constexpr auto name = caster_t::name; static PYBIND11_DESCR name() { return caster_t::name(); }
static handle cast(const std::reference_wrapper<type> &src, return_value_policy policy, handle parent) { static handle cast(const std::reference_wrapper<type> &src, return_value_policy policy, handle parent) {
// It is definitely wrong to take ownership of this pointer, so mask that rvp // It is definitely wrong to take ownership of this pointer, so mask that rvp
if (policy == return_value_policy::take_ownership || policy == return_value_policy::automatic) if (policy == return_value_policy::take_ownership || policy == return_value_policy::automatic)
...@@ -900,7 +900,7 @@ public: ...@@ -900,7 +900,7 @@ public:
protected: \ protected: \
type value; \ type value; \
public: \ public: \
static constexpr auto name = py_name; \ static PYBIND11_DESCR name() { return type_descr(py_name); } \
template <typename T_, enable_if_t<std::is_same<type, remove_cv_t<T_>>::value, int> = 0> \ template <typename T_, enable_if_t<std::is_same<type, remove_cv_t<T_>>::value, int> = 0> \
static handle cast(T_ *src, return_value_policy policy, handle parent) { \ static handle cast(T_ *src, return_value_policy policy, handle parent) { \
if (!src) return none().release(); \ if (!src) return none().release(); \
...@@ -980,12 +980,11 @@ public: ...@@ -980,12 +980,11 @@ public:
static handle cast(T src, return_value_policy /* policy */, handle /* parent */) { static handle cast(T src, return_value_policy /* policy */, handle /* parent */) {
if (std::is_floating_point<T>::value) { if (std::is_floating_point<T>::value) {
return PyFloat_FromDouble((double) src); return PyFloat_FromDouble((double) src);
} else if (sizeof(T) <= sizeof(ssize_t)) { } else if (sizeof(T) <= sizeof(long)) {
// This returns a long automatically if needed
if (std::is_signed<T>::value) if (std::is_signed<T>::value)
return PYBIND11_LONG_FROM_SIGNED(src); return PyLong_FromLong((long) src);
else else
return PYBIND11_LONG_FROM_UNSIGNED(src); return PyLong_FromUnsignedLong((unsigned long) src);
} else { } else {
if (std::is_signed<T>::value) if (std::is_signed<T>::value)
return PyLong_FromLongLong((long long) src); return PyLong_FromLongLong((long long) src);
...@@ -1050,7 +1049,7 @@ public: ...@@ -1050,7 +1049,7 @@ public:
template <typename T> using cast_op_type = void*&; template <typename T> using cast_op_type = void*&;
operator void *&() { return value; } operator void *&() { return value; }
static constexpr auto name = _("capsule"); static PYBIND11_DESCR name() { return type_descr(_("capsule")); }
private: private:
void *value = nullptr; void *value = nullptr;
}; };
...@@ -1293,7 +1292,7 @@ public: ...@@ -1293,7 +1292,7 @@ public:
return one_char; return one_char;
} }
static constexpr auto name = _(PYBIND11_STRING_NAME); static PYBIND11_DESCR name() { return type_descr(_(PYBIND11_STRING_NAME)); }
template <typename _T> using cast_op_type = pybind11::detail::cast_op_type<_T>; template <typename _T> using cast_op_type = pybind11::detail::cast_op_type<_T>;
}; };
...@@ -1318,7 +1317,9 @@ public: ...@@ -1318,7 +1317,9 @@ public:
return cast_impl(std::forward<T>(src), policy, parent, indices{}); return cast_impl(std::forward<T>(src), policy, parent, indices{});
} }
static constexpr auto name = _("Tuple[") + concat(make_caster<Ts>::name...) + _("]"); static PYBIND11_DESCR name() {
return type_descr(_("Tuple[") + detail::concat(make_caster<Ts>::name()...) + _("]"));
}
template <typename T> using cast_op_type = type; template <typename T> using cast_op_type = type;
...@@ -1463,7 +1464,7 @@ struct move_only_holder_caster { ...@@ -1463,7 +1464,7 @@ struct move_only_holder_caster {
auto *ptr = holder_helper<holder_type>::get(src); auto *ptr = holder_helper<holder_type>::get(src);
return type_caster_base<type>::cast_holder(ptr, &src); return type_caster_base<type>::cast_holder(ptr, &src);
} }
static constexpr auto name = type_caster_base<type>::name; static PYBIND11_DESCR name() { return type_caster_base<type>::name(); }
}; };
template <typename type, typename deleter> template <typename type, typename deleter>
...@@ -1494,10 +1495,10 @@ template <typename base, typename holder> struct is_holder_type : ...@@ -1494,10 +1495,10 @@ template <typename base, typename holder> struct is_holder_type :
template <typename base, typename deleter> struct is_holder_type<base, std::unique_ptr<base, deleter>> : template <typename base, typename deleter> struct is_holder_type<base, std::unique_ptr<base, deleter>> :
std::true_type {}; std::true_type {};
template <typename T> struct handle_type_name { static constexpr auto name = _<T>(); }; template <typename T> struct handle_type_name { static PYBIND11_DESCR name() { return _<T>(); } };
template <> struct handle_type_name<bytes> { static constexpr auto name = _(PYBIND11_BYTES_NAME); }; template <> struct handle_type_name<bytes> { static PYBIND11_DESCR name() { return _(PYBIND11_BYTES_NAME); } };
template <> struct handle_type_name<args> { static constexpr auto name = _("*args"); }; template <> struct handle_type_name<args> { static PYBIND11_DESCR name() { return _("*args"); } };
template <> struct handle_type_name<kwargs> { static constexpr auto name = _("**kwargs"); }; template <> struct handle_type_name<kwargs> { static PYBIND11_DESCR name() { return _("**kwargs"); } };
template <typename type> template <typename type>
struct pyobject_caster { struct pyobject_caster {
...@@ -1515,7 +1516,7 @@ struct pyobject_caster { ...@@ -1515,7 +1516,7 @@ struct pyobject_caster {
static handle cast(const handle &src, return_value_policy /* policy */, handle /* parent */) { static handle cast(const handle &src, return_value_policy /* policy */, handle /* parent */) {
return src.inc_ref(); return src.inc_ref();
} }
PYBIND11_TYPE_CASTER(type, handle_type_name<type>::name); PYBIND11_TYPE_CASTER(type, handle_type_name<type>::name());
}; };
template <typename T> template <typename T>
...@@ -1685,6 +1686,9 @@ template <> inline void cast_safe<void>(object &&) {} ...@@ -1685,6 +1686,9 @@ template <> inline void cast_safe<void>(object &&) {}
NAMESPACE_END(detail) NAMESPACE_END(detail)
template <return_value_policy policy = return_value_policy::automatic_reference>
tuple make_tuple() { return tuple(0); }
template <return_value_policy policy = return_value_policy::automatic_reference, template <return_value_policy policy = return_value_policy::automatic_reference,
typename... Args> tuple make_tuple(Args&&... args_) { typename... Args> tuple make_tuple(Args&&... args_) {
constexpr size_t size = sizeof...(Args); constexpr size_t size = sizeof...(Args);
...@@ -1801,6 +1805,10 @@ struct function_call { ...@@ -1801,6 +1805,10 @@ struct function_call {
/// The `convert` value the arguments should be loaded with /// The `convert` value the arguments should be loaded with
std::vector<bool> args_convert; std::vector<bool> args_convert;
/// Extra references for the optional `py::args` and/or `py::kwargs` arguments (which, if
/// present, are also in `args` but without a reference).
object args_ref, kwargs_ref;
/// The parent, if any /// The parent, if any
handle parent; handle parent;
...@@ -1828,7 +1836,7 @@ public: ...@@ -1828,7 +1836,7 @@ public:
static constexpr bool has_kwargs = kwargs_pos < 0; static constexpr bool has_kwargs = kwargs_pos < 0;
static constexpr bool has_args = args_pos < 0; static constexpr bool has_args = args_pos < 0;
static constexpr auto arg_names = concat(type_descr(make_caster<Args>::name)...); static PYBIND11_DESCR arg_names() { return detail::concat(make_caster<Args>::name()...); }
bool load_args(function_call &call) { bool load_args(function_call &call) {
return load_impl_sequence(call, indices{}); return load_impl_sequence(call, indices{});
......
...@@ -25,13 +25,9 @@ template <typename T> struct format_descriptor<std::complex<T>, detail::enable_i ...@@ -25,13 +25,9 @@ template <typename T> struct format_descriptor<std::complex<T>, detail::enable_i
static std::string format() { return std::string(value); } static std::string format() { return std::string(value); }
}; };
#ifndef PYBIND11_CPP17
template <typename T> constexpr const char format_descriptor< template <typename T> constexpr const char format_descriptor<
std::complex<T>, detail::enable_if_t<std::is_floating_point<T>::value>>::value[3]; std::complex<T>, detail::enable_if_t<std::is_floating_point<T>::value>>::value[3];
#endif
NAMESPACE_BEGIN(detail) NAMESPACE_BEGIN(detail)
template <typename T> struct is_fmt_numeric<std::complex<T>, detail::enable_if_t<std::is_floating_point<T>::value>> { template <typename T> struct is_fmt_numeric<std::complex<T>, detail::enable_if_t<std::is_floating_point<T>::value>> {
......
...@@ -289,9 +289,13 @@ extern "C" inline int pybind11_object_init(PyObject *self, PyObject *, PyObject ...@@ -289,9 +289,13 @@ extern "C" inline int pybind11_object_init(PyObject *self, PyObject *, PyObject
inline void add_patient(PyObject *nurse, PyObject *patient) { inline void add_patient(PyObject *nurse, PyObject *patient) {
auto &internals = get_internals(); auto &internals = get_internals();
auto instance = reinterpret_cast<detail::instance *>(nurse); auto instance = reinterpret_cast<detail::instance *>(nurse);
auto &current_patients = internals.patients[nurse];
instance->has_patients = true; instance->has_patients = true;
for (auto &p : current_patients)
if (p == patient)
return;
Py_INCREF(patient); Py_INCREF(patient);
internals.patients[nurse].push_back(patient); current_patients.push_back(patient);
} }
inline void clear_patients(PyObject *self) { inline void clear_patients(PyObject *self) {
......
...@@ -92,8 +92,8 @@ ...@@ -92,8 +92,8 @@
#endif #endif
#define PYBIND11_VERSION_MAJOR 2 #define PYBIND11_VERSION_MAJOR 2
#define PYBIND11_VERSION_MINOR 3 #define PYBIND11_VERSION_MINOR 2
#define PYBIND11_VERSION_PATCH dev0 #define PYBIND11_VERSION_PATCH 2
/// Include Python header, disable linking to pythonX_d.lib on Windows in debug mode /// Include Python header, disable linking to pythonX_d.lib on Windows in debug mode
#if defined(_MSC_VER) #if defined(_MSC_VER)
...@@ -158,8 +158,6 @@ ...@@ -158,8 +158,6 @@
#define PYBIND11_BYTES_SIZE PyBytes_Size #define PYBIND11_BYTES_SIZE PyBytes_Size
#define PYBIND11_LONG_CHECK(o) PyLong_Check(o) #define PYBIND11_LONG_CHECK(o) PyLong_Check(o)
#define PYBIND11_LONG_AS_LONGLONG(o) PyLong_AsLongLong(o) #define PYBIND11_LONG_AS_LONGLONG(o) PyLong_AsLongLong(o)
#define PYBIND11_LONG_FROM_SIGNED(o) PyLong_FromSsize_t((ssize_t) o)
#define PYBIND11_LONG_FROM_UNSIGNED(o) PyLong_FromSize_t((size_t) o)
#define PYBIND11_BYTES_NAME "bytes" #define PYBIND11_BYTES_NAME "bytes"
#define PYBIND11_STRING_NAME "str" #define PYBIND11_STRING_NAME "str"
#define PYBIND11_SLICE_OBJECT PyObject #define PYBIND11_SLICE_OBJECT PyObject
...@@ -182,8 +180,6 @@ ...@@ -182,8 +180,6 @@
#define PYBIND11_BYTES_SIZE PyString_Size #define PYBIND11_BYTES_SIZE PyString_Size
#define PYBIND11_LONG_CHECK(o) (PyInt_Check(o) || PyLong_Check(o)) #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_LONGLONG(o) (PyInt_Check(o) ? (long long) PyLong_AsLong(o) : PyLong_AsLongLong(o))
#define PYBIND11_LONG_FROM_SIGNED(o) PyInt_FromSsize_t((ssize_t) o) // Returns long if needed.
#define PYBIND11_LONG_FROM_UNSIGNED(o) PyInt_FromSize_t((size_t) o) // Returns long if needed.
#define PYBIND11_BYTES_NAME "str" #define PYBIND11_BYTES_NAME "str"
#define PYBIND11_STRING_NAME "unicode" #define PYBIND11_STRING_NAME "unicode"
#define PYBIND11_SLICE_OBJECT PySliceObject #define PYBIND11_SLICE_OBJECT PySliceObject
...@@ -381,18 +377,20 @@ constexpr size_t instance_simple_holder_in_ptrs() { ...@@ -381,18 +377,20 @@ constexpr size_t instance_simple_holder_in_ptrs() {
struct type_info; struct type_info;
struct value_and_holder; struct value_and_holder;
struct nonsimple_values_and_holders {
void **values_and_holders;
uint8_t *status;
};
/// The 'instance' type which needs to be standard layout (need to be able to use 'offsetof') /// The 'instance' type which needs to be standard layout (need to be able to use 'offsetof')
struct instance { struct instance {
PyObject_HEAD PyObject_HEAD
/// Storage for pointers and holder; see simple_layout, below, for a description /// Storage for pointers and holder; see simple_layout, below, for a description
union { union {
void *simple_value_holder[1 + instance_simple_holder_in_ptrs()]; void *simple_value_holder[1 + instance_simple_holder_in_ptrs()];
struct { nonsimple_values_and_holders nonsimple;
void **values_and_holders;
uint8_t *status;
} nonsimple;
}; };
/// Weak references /// Weak references (needed for keep alive):
PyObject *weakrefs; PyObject *weakrefs;
/// If true, the pointer is owned which means we're free to manage it with a holder. /// If true, the pointer is owned which means we're free to manage it with a holder.
bool owned : 1; bool owned : 1;
...@@ -409,10 +407,10 @@ struct instance { ...@@ -409,10 +407,10 @@ struct instance {
* (which is typically the size of two pointers), or when multiple inheritance is used on the * (which is typically the size of two pointers), or when multiple inheritance is used on the
* python side. Non-simple layout allocates the required amount of memory to have multiple * python side. Non-simple layout allocates the required amount of memory to have multiple
* bound C++ classes as parents. Under this layout, `nonsimple.values_and_holders` is set to a * bound C++ classes as parents. Under this layout, `nonsimple.values_and_holders` is set to a
* pointer to allocated space of the required space to hold a sequence of value pointers and * pointer to allocated space of the required space to hold a a sequence of value pointers and
* holders followed `status`, a set of bit flags (1 byte each), i.e. * holders followed `status`, a set of bit flags (1 byte each), i.e.
* [val1*][holder1][val2*][holder2]...[bb...] where each [block] is rounded up to a multiple of * [val1*][holder1][val2*][holder2]...[bb...] where each [block] is rounded up to a multiple of
* `sizeof(void *)`. `nonsimple.status` is, for convenience, a pointer to the * `sizeof(void *)`. `nonsimple.holder_constructed` is, for convenience, a pointer to the
* beginning of the [bb...] block (but not independently allocated). * beginning of the [bb...] block (but not independently allocated).
* *
* Status bits indicate whether the associated holder is constructed (& * Status bits indicate whether the associated holder is constructed (&
...@@ -585,11 +583,6 @@ template <typename T, typename... Us> using deferred_t = typename deferred_type< ...@@ -585,11 +583,6 @@ template <typename T, typename... Us> using deferred_t = typename deferred_type<
template <typename Base, typename Derived> using is_strict_base_of = bool_constant< template <typename Base, typename Derived> using is_strict_base_of = bool_constant<
std::is_base_of<Base, Derived>::value && !std::is_same<Base, Derived>::value>; std::is_base_of<Base, Derived>::value && !std::is_same<Base, Derived>::value>;
/// Like is_base_of, but also requires that the base type is accessible (i.e. that a Derived pointer
/// can be converted to a Base pointer)
template <typename Base, typename Derived> using is_accessible_base_of = bool_constant<
std::is_base_of<Base, Derived>::value && std::is_convertible<Derived *, Base *>::value>;
template <template<typename...> class Base> template <template<typename...> class Base>
struct is_template_base_of_impl { struct is_template_base_of_impl {
template <typename... Us> static std::true_type check(Base<Us...> *); template <typename... Us> static std::true_type check(Base<Us...> *);
...@@ -708,13 +701,9 @@ template <typename T> struct format_descriptor<T, detail::enable_if_t<std::is_ar ...@@ -708,13 +701,9 @@ template <typename T> struct format_descriptor<T, detail::enable_if_t<std::is_ar
static std::string format() { return std::string(1, c); } static std::string format() { return std::string(1, c); }
}; };
#if !defined(PYBIND11_CPP17)
template <typename T> constexpr const char format_descriptor< template <typename T> constexpr const char format_descriptor<
T, detail::enable_if_t<std::is_arithmetic<T>::value>>::value[2]; T, detail::enable_if_t<std::is_arithmetic<T>::value>>::value[2];
#endif
/// RAII wrapper that temporarily clears any Python error state /// RAII wrapper that temporarily clears any Python error state
struct error_scope { struct error_scope {
PyObject *type, *value, *trace; PyObject *type, *value, *trace;
......
/* /*
pybind11/detail/descr.h: Helper type for concatenating type signatures at compile time pybind11/detail/descr.h: Helper type for concatenating type signatures
either at runtime (C++11) or compile time (C++14)
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch> Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
...@@ -14,87 +15,171 @@ ...@@ -14,87 +15,171 @@
NAMESPACE_BEGIN(PYBIND11_NAMESPACE) NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
NAMESPACE_BEGIN(detail) NAMESPACE_BEGIN(detail)
#if !defined(_MSC_VER) /* Concatenate type signatures at compile time using C++14 */
# define PYBIND11_DESCR_CONSTEXPR static constexpr #if defined(PYBIND11_CPP14) && !defined(_MSC_VER)
#else #define PYBIND11_CONSTEXPR_DESCR
# define PYBIND11_DESCR_CONSTEXPR const
#endif template <size_t Size1, size_t Size2> class descr {
template <size_t Size1_, size_t Size2_> friend class descr;
/* Concatenate type signatures at compile time */ public:
template <size_t N, typename... Ts> constexpr descr(char const (&text) [Size1+1], const std::type_info * const (&types)[Size2+1])
struct descr { : descr(text, types,
char text[N + 1]; make_index_sequence<Size1>(),
make_index_sequence<Size2>()) { }
constexpr descr() : text{'\0'} { }
constexpr descr(char const (&s)[N+1]) : descr(s, make_index_sequence<N>()) { } constexpr const char *text() const { return m_text; }
constexpr const std::type_info * const * types() const { return m_types; }
template <size_t... Is>
constexpr descr(char const (&s)[N+1], index_sequence<Is...>) : text{s[Is]..., '\0'} { } template <size_t OtherSize1, size_t OtherSize2>
constexpr descr<Size1 + OtherSize1, Size2 + OtherSize2> operator+(const descr<OtherSize1, OtherSize2> &other) const {
template <typename... Chars> return concat(other,
constexpr descr(char c, Chars... cs) : text{c, static_cast<char>(cs)..., '\0'} { } make_index_sequence<Size1>(),
make_index_sequence<Size2>(),
make_index_sequence<OtherSize1>(),
make_index_sequence<OtherSize2>());
}
static constexpr std::array<const std::type_info *, sizeof...(Ts) + 1> types() { protected:
return {{&typeid(Ts)..., nullptr}}; template <size_t... Indices1, size_t... Indices2>
constexpr descr(
char const (&text) [Size1+1],
const std::type_info * const (&types) [Size2+1],
index_sequence<Indices1...>, index_sequence<Indices2...>)
: m_text{text[Indices1]..., '\0'},
m_types{types[Indices2]..., nullptr } {}
template <size_t OtherSize1, size_t OtherSize2, size_t... Indices1,
size_t... Indices2, size_t... OtherIndices1, size_t... OtherIndices2>
constexpr descr<Size1 + OtherSize1, Size2 + OtherSize2>
concat(const descr<OtherSize1, OtherSize2> &other,
index_sequence<Indices1...>, index_sequence<Indices2...>,
index_sequence<OtherIndices1...>, index_sequence<OtherIndices2...>) const {
return descr<Size1 + OtherSize1, Size2 + OtherSize2>(
{ m_text[Indices1]..., other.m_text[OtherIndices1]..., '\0' },
{ m_types[Indices2]..., other.m_types[OtherIndices2]..., nullptr }
);
} }
};
template <size_t N1, size_t N2, typename... Ts1, typename... Ts2, size_t... Is1, size_t... Is2> protected:
constexpr descr<N1 + N2, Ts1..., Ts2...> plus_impl(const descr<N1, Ts1...> &a, const descr<N2, Ts2...> &b, char m_text[Size1 + 1];
index_sequence<Is1...>, index_sequence<Is2...>) { const std::type_info * m_types[Size2 + 1];
return {a.text[Is1]..., b.text[Is2]...}; };
}
template <size_t N1, size_t N2, typename... Ts1, typename... Ts2> template <size_t Size> constexpr descr<Size - 1, 0> _(char const(&text)[Size]) {
constexpr descr<N1 + N2, Ts1..., Ts2...> operator+(const descr<N1, Ts1...> &a, const descr<N2, Ts2...> &b) { return descr<Size - 1, 0>(text, { nullptr });
return plus_impl(a, b, make_index_sequence<N1>(), make_index_sequence<N2>());
} }
template <size_t N>
constexpr descr<N - 1> _(char const(&text)[N]) { return descr<N - 1>(text); }
constexpr descr<0> _(char const(&)[1]) { return {}; }
template <size_t Rem, size_t... Digits> struct int_to_str : int_to_str<Rem/10, Rem%10, Digits...> { }; template <size_t Rem, size_t... Digits> struct int_to_str : int_to_str<Rem/10, Rem%10, Digits...> { };
template <size_t...Digits> struct int_to_str<0, Digits...> { template <size_t...Digits> struct int_to_str<0, Digits...> {
static constexpr auto digits = descr<sizeof...(Digits)>(('0' + Digits)...); static constexpr auto digits = descr<sizeof...(Digits), 0>({ ('0' + Digits)..., '\0' }, { nullptr });
}; };
// Ternary description (like std::conditional) // Ternary description (like std::conditional)
template <bool B, size_t N1, size_t N2> template <bool B, size_t Size1, size_t Size2>
constexpr enable_if_t<B, descr<N1 - 1>> _(char const(&text1)[N1], char const(&)[N2]) { constexpr enable_if_t<B, descr<Size1 - 1, 0>> _(char const(&text1)[Size1], char const(&)[Size2]) {
return _(text1); return _(text1);
} }
template <bool B, size_t N1, size_t N2> template <bool B, size_t Size1, size_t Size2>
constexpr enable_if_t<!B, descr<N2 - 1>> _(char const(&)[N1], char const(&text2)[N2]) { constexpr enable_if_t<!B, descr<Size2 - 1, 0>> _(char const(&)[Size1], char const(&text2)[Size2]) {
return _(text2); return _(text2);
} }
template <bool B, size_t SizeA1, size_t SizeA2, size_t SizeB1, size_t SizeB2>
template <bool B, typename T1, typename T2> constexpr enable_if_t<B, descr<SizeA1, SizeA2>> _(descr<SizeA1, SizeA2> d, descr<SizeB1, SizeB2>) { return d; }
constexpr enable_if_t<B, T1> _(const T1 &d, const T2 &) { return d; } template <bool B, size_t SizeA1, size_t SizeA2, size_t SizeB1, size_t SizeB2>
template <bool B, typename T1, typename T2> constexpr enable_if_t<!B, descr<SizeB1, SizeB2>> _(descr<SizeA1, SizeA2>, descr<SizeB1, SizeB2> d) { return d; }
constexpr enable_if_t<!B, T2> _(const T1 &, const T2 &d) { return d; }
template <size_t Size> auto constexpr _() -> decltype(int_to_str<Size / 10, Size % 10>::digits) { template <size_t Size> auto constexpr _() -> decltype(int_to_str<Size / 10, Size % 10>::digits) {
return int_to_str<Size / 10, Size % 10>::digits; return int_to_str<Size / 10, Size % 10>::digits;
} }
template <typename Type> constexpr descr<1, Type> _() { return {'%'}; } template <typename Type> constexpr descr<1, 1> _() {
return descr<1, 1>({ '%', '\0' }, { &typeid(Type), nullptr });
}
inline constexpr descr<0, 0> concat() { return _(""); }
template <size_t Size1, size_t Size2, typename... Args> auto constexpr concat(descr<Size1, Size2> descr) { return descr; }
template <size_t Size1, size_t Size2, typename... Args> auto constexpr concat(descr<Size1, Size2> descr, Args&&... args) { return descr + _(", ") + concat(args...); }
template <size_t Size1, size_t Size2> auto constexpr type_descr(descr<Size1, Size2> descr) { return _("{") + descr + _("}"); }
#define PYBIND11_DESCR constexpr auto
#else /* Simpler C++11 implementation based on run-time memory allocation and copying */
class descr {
public:
PYBIND11_NOINLINE descr(const char *text, const std::type_info * const * types) {
size_t nChars = len(text), nTypes = len(types);
m_text = new char[nChars];
m_types = new const std::type_info *[nTypes];
memcpy(m_text, text, nChars * sizeof(char));
memcpy(m_types, types, nTypes * sizeof(const std::type_info *));
}
PYBIND11_NOINLINE descr operator+(descr &&d2) && {
descr r;
size_t nChars1 = len(m_text), nTypes1 = len(m_types);
size_t nChars2 = len(d2.m_text), nTypes2 = len(d2.m_types);
r.m_text = new char[nChars1 + nChars2 - 1];
r.m_types = new const std::type_info *[nTypes1 + nTypes2 - 1];
memcpy(r.m_text, m_text, (nChars1-1) * sizeof(char));
memcpy(r.m_text + nChars1 - 1, d2.m_text, nChars2 * sizeof(char));
memcpy(r.m_types, m_types, (nTypes1-1) * sizeof(std::type_info *));
memcpy(r.m_types + nTypes1 - 1, d2.m_types, nTypes2 * sizeof(std::type_info *));
constexpr descr<0> concat() { return {}; } delete[] m_text; delete[] m_types;
delete[] d2.m_text; delete[] d2.m_types;
return r;
}
template <size_t N, typename... Ts> char *text() { return m_text; }
constexpr descr<N, Ts...> concat(const descr<N, Ts...> &descr) { return descr; } const std::type_info * * types() { return m_types; }
template <size_t N, typename... Ts, typename... Args> protected:
constexpr auto concat(const descr<N, Ts...> &d, const Args &...args) PYBIND11_NOINLINE descr() { }
-> decltype(std::declval<descr<N + 2, Ts...>>() + concat(args...)) {
return d + _(", ") + concat(args...); template <typename T> static size_t len(const T *ptr) { // return length including null termination
const T *it = ptr;
while (*it++ != (T) 0)
;
return static_cast<size_t>(it - ptr);
}
const std::type_info **m_types = nullptr;
char *m_text = nullptr;
};
/* The 'PYBIND11_NOINLINE inline' combinations below are intentional to get the desired linkage while producing as little object code as possible */
PYBIND11_NOINLINE inline descr _(const char *text) {
const std::type_info *types[1] = { nullptr };
return descr(text, types);
}
template <bool B> PYBIND11_NOINLINE enable_if_t<B, descr> _(const char *text1, const char *) { return _(text1); }
template <bool B> PYBIND11_NOINLINE enable_if_t<!B, descr> _(char const *, const char *text2) { return _(text2); }
template <bool B> PYBIND11_NOINLINE enable_if_t<B, descr> _(descr d, descr) { return d; }
template <bool B> PYBIND11_NOINLINE enable_if_t<!B, descr> _(descr, descr d) { return d; }
template <typename Type> PYBIND11_NOINLINE descr _() {
const std::type_info *types[2] = { &typeid(Type), nullptr };
return descr("%", types);
} }
template <size_t N, typename... Ts> template <size_t Size> PYBIND11_NOINLINE descr _() {
constexpr descr<N + 2, Ts...> type_descr(const descr<N, Ts...> &descr) { const std::type_info *types[1] = { nullptr };
return _("{") + descr + _("}"); return descr(std::to_string(Size).c_str(), types);
} }
PYBIND11_NOINLINE inline descr concat() { return _(""); }
PYBIND11_NOINLINE inline descr concat(descr &&d) { return d; }
template <typename... Args> PYBIND11_NOINLINE descr concat(descr &&d, Args&&... args) { return std::move(d) + _(", ") + concat(std::forward<Args>(args)...); }
PYBIND11_NOINLINE inline descr type_descr(descr&& d) { return _("{") + std::move(d) + _("}"); }
#define PYBIND11_DESCR ::pybind11::detail::descr
#endif
NAMESPACE_END(detail) NAMESPACE_END(detail)
NAMESPACE_END(PYBIND11_NAMESPACE) NAMESPACE_END(PYBIND11_NAMESPACE)
...@@ -24,7 +24,7 @@ public: ...@@ -24,7 +24,7 @@ public:
template <typename> using cast_op_type = value_and_holder &; template <typename> using cast_op_type = value_and_holder &;
operator value_and_holder &() { return *value; } operator value_and_holder &() { return *value; }
static constexpr auto name = _<value_and_holder>(); static PYBIND11_DESCR name() { return type_descr(_<value_and_holder>()); }
private: private:
value_and_holder *value = nullptr; value_and_holder *value = nullptr;
...@@ -52,6 +52,16 @@ bool is_alias(Cpp<Class> *ptr) { ...@@ -52,6 +52,16 @@ bool is_alias(Cpp<Class> *ptr) {
template <typename /*Class*/> template <typename /*Class*/>
constexpr bool is_alias(void *) { return false; } constexpr bool is_alias(void *) { return false; }
// Constructs and returns a new object; if the given arguments don't map to a constructor, we fall
// back to brace aggregate initiailization so that for aggregate initialization can be used with
// py::init, e.g. `py::init<int, int>` to initialize a `struct T { int a; int b; }`. For
// non-aggregate types, we need to use an ordinary T(...) constructor (invoking as `T{...}` usually
// works, but will not do the expected thing when `T` has an `initializer_list<T>` constructor).
template <typename Class, typename... Args, detail::enable_if_t<std::is_constructible<Class, Args...>::value, int> = 0>
inline Class *construct_or_initialize(Args &&...args) { return new Class(std::forward<Args>(args)...); }
template <typename Class, typename... Args, detail::enable_if_t<!std::is_constructible<Class, Args...>::value, int> = 0>
inline Class *construct_or_initialize(Args &&...args) { return new Class{std::forward<Args>(args)...}; }
// Attempts to constructs an alias using a `Alias(Cpp &&)` constructor. This allows types with // Attempts to constructs an alias using a `Alias(Cpp &&)` constructor. This allows types with
// an alias to provide only a single Cpp factory function as long as the Alias can be // an alias to provide only a single Cpp factory function as long as the Alias can be
// constructed from an rvalue reference of the base Cpp type. This means that Alias classes // constructed from an rvalue reference of the base Cpp type. This means that Alias classes
...@@ -161,7 +171,7 @@ struct constructor { ...@@ -161,7 +171,7 @@ struct constructor {
template <typename Class, typename... Extra, enable_if_t<!Class::has_alias, int> = 0> template <typename Class, typename... Extra, enable_if_t<!Class::has_alias, int> = 0>
static void execute(Class &cl, const Extra&... extra) { static void execute(Class &cl, const Extra&... extra) {
cl.def("__init__", [](value_and_holder &v_h, Args... args) { cl.def("__init__", [](value_and_holder &v_h, Args... args) {
v_h.value_ptr() = new Cpp<Class>{std::forward<Args>(args)...}; v_h.value_ptr() = construct_or_initialize<Cpp<Class>>(std::forward<Args>(args)...);
}, is_new_style_constructor(), extra...); }, is_new_style_constructor(), extra...);
} }
...@@ -171,9 +181,9 @@ struct constructor { ...@@ -171,9 +181,9 @@ struct constructor {
static void execute(Class &cl, const Extra&... extra) { static void execute(Class &cl, const Extra&... extra) {
cl.def("__init__", [](value_and_holder &v_h, Args... args) { cl.def("__init__", [](value_and_holder &v_h, Args... args) {
if (Py_TYPE(v_h.inst) == v_h.type->type) if (Py_TYPE(v_h.inst) == v_h.type->type)
v_h.value_ptr() = new Cpp<Class>{std::forward<Args>(args)...}; v_h.value_ptr() = construct_or_initialize<Cpp<Class>>(std::forward<Args>(args)...);
else else
v_h.value_ptr() = new Alias<Class>{std::forward<Args>(args)...}; v_h.value_ptr() = construct_or_initialize<Alias<Class>>(std::forward<Args>(args)...);
}, is_new_style_constructor(), extra...); }, is_new_style_constructor(), extra...);
} }
...@@ -182,7 +192,7 @@ struct constructor { ...@@ -182,7 +192,7 @@ struct constructor {
!std::is_constructible<Cpp<Class>, Args...>::value, int> = 0> !std::is_constructible<Cpp<Class>, Args...>::value, int> = 0>
static void execute(Class &cl, const Extra&... extra) { static void execute(Class &cl, const Extra&... extra) {
cl.def("__init__", [](value_and_holder &v_h, Args... args) { cl.def("__init__", [](value_and_holder &v_h, Args... args) {
v_h.value_ptr() = new Alias<Class>{std::forward<Args>(args)...}; v_h.value_ptr() = construct_or_initialize<Alias<Class>>(std::forward<Args>(args)...);
}, is_new_style_constructor(), extra...); }, is_new_style_constructor(), extra...);
} }
}; };
...@@ -193,7 +203,7 @@ template <typename... Args> struct alias_constructor { ...@@ -193,7 +203,7 @@ template <typename... Args> struct alias_constructor {
enable_if_t<Class::has_alias && std::is_constructible<Alias<Class>, Args...>::value, int> = 0> enable_if_t<Class::has_alias && std::is_constructible<Alias<Class>, Args...>::value, int> = 0>
static void execute(Class &cl, const Extra&... extra) { static void execute(Class &cl, const Extra&... extra) {
cl.def("__init__", [](value_and_holder &v_h, Args... args) { cl.def("__init__", [](value_and_holder &v_h, Args... args) {
v_h.value_ptr() = new Alias<Class>{std::forward<Args>(args)...}; v_h.value_ptr() = construct_or_initialize<Alias<Class>>(std::forward<Args>(args)...);
}, is_new_style_constructor(), extra...); }, is_new_style_constructor(), extra...);
} }
}; };
......
...@@ -127,21 +127,21 @@ struct type_info { ...@@ -127,21 +127,21 @@ struct type_info {
/// Each module locally stores a pointer to the `internals` data. The data /// Each module locally stores a pointer to the `internals` data. The data
/// itself is shared among modules with the same `PYBIND11_INTERNALS_ID`. /// itself is shared among modules with the same `PYBIND11_INTERNALS_ID`.
inline internals *&get_internals_ptr() { inline internals **&get_internals_pp() {
static internals *internals_ptr = nullptr; static internals **internals_pp = nullptr;
return internals_ptr; return internals_pp;
} }
/// Return a reference to the current `internals` data /// Return a reference to the current `internals` data
PYBIND11_NOINLINE inline internals &get_internals() { PYBIND11_NOINLINE inline internals &get_internals() {
auto *&internals_ptr = get_internals_ptr(); auto **&internals_pp = get_internals_pp();
if (internals_ptr) if (internals_pp && *internals_pp)
return *internals_ptr; return **internals_pp;
constexpr auto *id = PYBIND11_INTERNALS_ID; constexpr auto *id = PYBIND11_INTERNALS_ID;
auto builtins = handle(PyEval_GetBuiltins()); auto builtins = handle(PyEval_GetBuiltins());
if (builtins.contains(id) && isinstance<capsule>(builtins[id])) { if (builtins.contains(id) && isinstance<capsule>(builtins[id])) {
internals_ptr = *static_cast<internals **>(capsule(builtins[id])); internals_pp = static_cast<internals **>(capsule(builtins[id]));
// We loaded builtins through python's builtins, which means that our `error_already_set` // We loaded builtins through python's builtins, which means that our `error_already_set`
// and `builtin_exception` may be different local classes than the ones set up in the // and `builtin_exception` may be different local classes than the ones set up in the
...@@ -149,7 +149,7 @@ PYBIND11_NOINLINE inline internals &get_internals() { ...@@ -149,7 +149,7 @@ PYBIND11_NOINLINE inline internals &get_internals() {
// //
// libstdc++ doesn't require this (types there are identified only by name) // libstdc++ doesn't require this (types there are identified only by name)
#if !defined(__GLIBCXX__) #if !defined(__GLIBCXX__)
internals_ptr->registered_exception_translators.push_front( (*internals_pp)->registered_exception_translators.push_front(
[](std::exception_ptr p) -> void { [](std::exception_ptr p) -> void {
try { try {
if (p) std::rethrow_exception(p); if (p) std::rethrow_exception(p);
...@@ -160,6 +160,8 @@ PYBIND11_NOINLINE inline internals &get_internals() { ...@@ -160,6 +160,8 @@ PYBIND11_NOINLINE inline internals &get_internals() {
); );
#endif #endif
} else { } else {
if (!internals_pp) internals_pp = new internals*();
auto *&internals_ptr = *internals_pp;
internals_ptr = new internals(); internals_ptr = new internals();
#if defined(WITH_THREAD) #if defined(WITH_THREAD)
PyEval_InitThreads(); PyEval_InitThreads();
...@@ -168,7 +170,7 @@ PYBIND11_NOINLINE inline internals &get_internals() { ...@@ -168,7 +170,7 @@ PYBIND11_NOINLINE inline internals &get_internals() {
PyThread_set_key_value(internals_ptr->tstate, tstate); PyThread_set_key_value(internals_ptr->tstate, tstate);
internals_ptr->istate = tstate->interp; internals_ptr->istate = tstate->interp;
#endif #endif
builtins[id] = capsule(&internals_ptr); builtins[id] = capsule(internals_pp);
internals_ptr->registered_exception_translators.push_front( internals_ptr->registered_exception_translators.push_front(
[](std::exception_ptr p) -> void { [](std::exception_ptr p) -> void {
try { try {
...@@ -192,7 +194,7 @@ PYBIND11_NOINLINE inline internals &get_internals() { ...@@ -192,7 +194,7 @@ PYBIND11_NOINLINE inline internals &get_internals() {
internals_ptr->default_metaclass = make_default_metaclass(); internals_ptr->default_metaclass = make_default_metaclass();
internals_ptr->instance_base = make_object_base_type(internals_ptr->default_metaclass); internals_ptr->instance_base = make_object_base_type(internals_ptr->default_metaclass);
} }
return *internals_ptr; return **internals_pp;
} }
/// Works like `internals.registered_types_cpp`, but for module-local registered types: /// Works like `internals.registered_types_cpp`, but for module-local registered types:
......
...@@ -17,24 +17,20 @@ ...@@ -17,24 +17,20 @@
# pragma GCC diagnostic push # pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wconversion" # pragma GCC diagnostic ignored "-Wconversion"
# pragma GCC diagnostic ignored "-Wdeprecated-declarations" # pragma GCC diagnostic ignored "-Wdeprecated-declarations"
# ifdef __clang__
// Eigen generates a bunch of implicit-copy-constructor-is-deprecated warnings with -Wdeprecated
// under Clang, so disable that warning here:
# pragma GCC diagnostic ignored "-Wdeprecated"
# endif
# if __GNUC__ >= 7 # if __GNUC__ >= 7
# pragma GCC diagnostic ignored "-Wint-in-bool-context" # pragma GCC diagnostic ignored "-Wint-in-bool-context"
# endif # endif
#endif #endif
#include <Eigen/Core>
#include <Eigen/SparseCore>
#if defined(_MSC_VER) #if defined(_MSC_VER)
# pragma warning(push) # pragma warning(push)
# pragma warning(disable: 4127) // warning C4127: Conditional expression is constant # pragma warning(disable: 4127) // warning C4127: Conditional expression is constant
# pragma warning(disable: 4996) // warning C4996: std::unary_negate is deprecated in C++17
#endif #endif
#include <Eigen/Core>
#include <Eigen/SparseCore>
// Eigen prior to 3.2.7 doesn't have proper move constructors--but worse, some classes get implicit // 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 // move constructors that break things. We could detect this an explicitly copy, but an extra copy
// of matrices seems highly undesirable. // of matrices seems highly undesirable.
...@@ -185,26 +181,28 @@ template <typename Type_> struct EigenProps { ...@@ -185,26 +181,28 @@ template <typename Type_> struct EigenProps {
} }
} }
static constexpr bool show_writeable = is_eigen_dense_map<Type>::value && is_eigen_mutable_map<Type>::value; static PYBIND11_DESCR descriptor() {
static constexpr bool show_order = is_eigen_dense_map<Type>::value; constexpr bool show_writeable = is_eigen_dense_map<Type>::value && is_eigen_mutable_map<Type>::value;
static constexpr bool show_c_contiguous = show_order && requires_row_major; constexpr bool show_order = is_eigen_dense_map<Type>::value;
static constexpr bool show_f_contiguous = !show_c_contiguous && show_order && requires_col_major; constexpr bool show_c_contiguous = show_order && requires_row_major;
constexpr bool show_f_contiguous = !show_c_contiguous && show_order && requires_col_major;
static constexpr auto descriptor =
_("numpy.ndarray[") + npy_format_descriptor<Scalar>::name + return type_descr(_("numpy.ndarray[") + npy_format_descriptor<Scalar>::name() +
_("[") + _<fixed_rows>(_<(size_t) rows>(), _("m")) + _("[") + _<fixed_rows>(_<(size_t) rows>(), _("m")) +
_(", ") + _<fixed_cols>(_<(size_t) cols>(), _("n")) + _(", ") + _<fixed_cols>(_<(size_t) cols>(), _("n")) +
_("]") + _("]") +
// For a reference type (e.g. Ref<MatrixXd>) we have other constraints that might need to be // 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 // 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 // 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 // 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 // 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. // *gave* a numpy.ndarray of the right type and dimensions.
_<show_writeable>(", flags.writeable", "") + _<show_writeable>(", flags.writeable", "") +
_<show_c_contiguous>(", flags.c_contiguous", "") + _<show_c_contiguous>(", flags.c_contiguous", "") +
_<show_f_contiguous>(", flags.f_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, // Casts an Eigen type to numpy array. If given a base, the numpy array references the src data,
...@@ -341,7 +339,7 @@ public: ...@@ -341,7 +339,7 @@ public:
return cast_impl(src, policy, parent); return cast_impl(src, policy, parent);
} }
static constexpr auto name = props::descriptor; static PYBIND11_DESCR name() { return props::descriptor(); }
operator Type*() { return &value; } operator Type*() { return &value; }
operator Type&() { return value; } operator Type&() { return value; }
...@@ -389,7 +387,7 @@ public: ...@@ -389,7 +387,7 @@ public:
} }
} }
static constexpr auto name = props::descriptor; static PYBIND11_DESCR name() { return props::descriptor(); }
// Explicitly delete these: support python -> C++ conversion on these (i.e. these can be return // 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 // types but not bound arguments). We still provide them (with an explicitly delete) so that
...@@ -534,7 +532,7 @@ public: ...@@ -534,7 +532,7 @@ public:
} }
static handle cast(const Type *src, return_value_policy policy, handle parent) { return cast(*src, policy, parent); } static handle cast(const Type *src, return_value_policy policy, handle parent) { return cast(*src, policy, parent); }
static constexpr auto name = props::descriptor; static PYBIND11_DESCR name() { return props::descriptor(); }
// Explicitly delete these: support python -> C++ conversion on these (i.e. these can be return // 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 // types but not bound arguments). We still provide them (with an explicitly delete) so that
...@@ -601,7 +599,7 @@ struct type_caster<Type, enable_if_t<is_eigen_sparse<Type>::value>> { ...@@ -601,7 +599,7 @@ struct type_caster<Type, enable_if_t<is_eigen_sparse<Type>::value>> {
} }
PYBIND11_TYPE_CASTER(Type, _<(Type::IsRowMajor) != 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 + _("]")); + npy_format_descriptor<Scalar>::name() + _("]"));
}; };
NAMESPACE_END(detail) NAMESPACE_END(detail)
......
...@@ -145,7 +145,7 @@ inline void finalize_interpreter() { ...@@ -145,7 +145,7 @@ inline void finalize_interpreter() {
// Get the internals pointer (without creating it if it doesn't exist). It's possible for the // Get the internals pointer (without creating it if it doesn't exist). It's possible for the
// internals to be created during Py_Finalize() (e.g. if a py::capsule calls `get_internals()` // internals to be created during Py_Finalize() (e.g. if a py::capsule calls `get_internals()`
// during destruction), so we get the pointer-pointer here and check it after Py_Finalize(). // during destruction), so we get the pointer-pointer here and check it after Py_Finalize().
detail::internals **internals_ptr_ptr = &detail::get_internals_ptr(); detail::internals **internals_ptr_ptr = detail::get_internals_pp();
// It could also be stashed in builtins, so look there too: // It could also be stashed in builtins, so look there too:
if (builtins.contains(id) && isinstance<capsule>(builtins[id])) if (builtins.contains(id) && isinstance<capsule>(builtins[id]))
internals_ptr_ptr = capsule(builtins[id]); internals_ptr_ptr = capsule(builtins[id]);
......
...@@ -75,8 +75,10 @@ public: ...@@ -75,8 +75,10 @@ public:
return cpp_function(std::forward<Func>(f_), policy).release(); return cpp_function(std::forward<Func>(f_), policy).release();
} }
PYBIND11_TYPE_CASTER(type, _("Callable[[") + concat(make_caster<Args>::name...) + _("], ") PYBIND11_TYPE_CASTER(type, _("Callable[[") +
+ make_caster<retval_type>::name + _("]")); argument_loader<Args...>::arg_names() + _("], ") +
make_caster<retval_type>::name() +
_("]"));
}; };
NAMESPACE_END(detail) NAMESPACE_END(detail)
......
...@@ -250,7 +250,7 @@ template <typename T> struct array_info_scalar { ...@@ -250,7 +250,7 @@ template <typename T> struct array_info_scalar {
typedef T type; typedef T type;
static constexpr bool is_array = false; static constexpr bool is_array = false;
static constexpr bool is_empty = false; static constexpr bool is_empty = false;
static constexpr auto extents = _(""); static PYBIND11_DESCR extents() { return _(""); }
static void append_extents(list& /* shape */) { } static void append_extents(list& /* shape */) { }
}; };
// Computes underlying type and a comma-separated list of extents for array // Computes underlying type and a comma-separated list of extents for array
...@@ -269,9 +269,15 @@ template <typename T, size_t N> struct array_info<std::array<T, N>> { ...@@ -269,9 +269,15 @@ template <typename T, size_t N> struct array_info<std::array<T, N>> {
array_info<T>::append_extents(shape); array_info<T>::append_extents(shape);
} }
static constexpr auto extents = _<array_info<T>::is_array>( template<typename T2 = T, enable_if_t<!array_info<T2>::is_array, int> = 0>
concat(_<N>(), array_info<T>::extents), _<N>() static PYBIND11_DESCR extents() {
); return _<N>();
}
template<typename T2 = T, enable_if_t<array_info<T2>::is_array, int> = 0>
static PYBIND11_DESCR extents() {
return concat(_<N>(), array_info<T>::extents());
}
}; };
// For numpy we have special handling for arrays of characters, so we don't include // For numpy we have special handling for arrays of characters, so we don't include
// the size in the array extents. // the size in the array extents.
...@@ -440,7 +446,7 @@ public: ...@@ -440,7 +446,7 @@ public:
/// This is essentially the same as calling numpy.dtype(args) in Python. /// This is essentially the same as calling numpy.dtype(args) in Python.
static dtype from_args(object args) { static dtype from_args(object args) {
PyObject *ptr = nullptr; PyObject *ptr = nullptr;
if (!detail::npy_api::get().PyArray_DescrConverter_(args.ptr(), &ptr) || !ptr) if (!detail::npy_api::get().PyArray_DescrConverter_(args.release().ptr(), &ptr) || !ptr)
throw error_already_set(); throw error_already_set();
return reinterpret_steal<dtype>(ptr); return reinterpret_steal<dtype>(ptr);
} }
...@@ -940,9 +946,9 @@ struct format_descriptor<T, detail::enable_if_t<std::is_enum<T>::value>> { ...@@ -940,9 +946,9 @@ struct format_descriptor<T, detail::enable_if_t<std::is_enum<T>::value>> {
template <typename T> template <typename T>
struct format_descriptor<T, detail::enable_if_t<detail::array_info<T>::is_array>> { struct format_descriptor<T, detail::enable_if_t<detail::array_info<T>::is_array>> {
static std::string format() { static std::string format() {
using detail::_; using namespace detail;
static constexpr auto extents = _("(") + detail::array_info<T>::extents + _(")"); PYBIND11_DESCR extents = _("(") + array_info<T>::extents() + _(")");
return extents.text + format_descriptor<detail::remove_all_extents_t<T>>::format(); return extents.text() + format_descriptor<remove_all_extents_t<T>>::format();
} }
}; };
...@@ -961,7 +967,7 @@ struct pyobject_caster<array_t<T, ExtraFlags>> { ...@@ -961,7 +967,7 @@ struct pyobject_caster<array_t<T, ExtraFlags>> {
static handle cast(const handle &src, return_value_policy /* policy */, handle /* parent */) { static handle cast(const handle &src, return_value_policy /* policy */, handle /* parent */) {
return src.inc_ref(); return src.inc_ref();
} }
PYBIND11_TYPE_CASTER(type, handle_type_name<type>::name); PYBIND11_TYPE_CASTER(type, handle_type_name<type>::name());
}; };
template <typename T> template <typename T>
...@@ -971,34 +977,7 @@ struct compare_buffer_info<T, detail::enable_if_t<detail::is_pod_struct<T>::valu ...@@ -971,34 +977,7 @@ struct compare_buffer_info<T, detail::enable_if_t<detail::is_pod_struct<T>::valu
} }
}; };
template <typename T, typename = void> template <typename T> struct npy_format_descriptor<T, enable_if_t<satisfies_any_of<T, std::is_arithmetic, is_complex>::value>> {
struct npy_format_descriptor_name;
template <typename T>
struct npy_format_descriptor_name<T, enable_if_t<std::is_integral<T>::value>> {
static constexpr auto name = _<std::is_same<T, bool>::value>(
_("bool"), _<std::is_signed<T>::value>("int", "uint") + _<sizeof(T)*8>()
);
};
template <typename T>
struct npy_format_descriptor_name<T, enable_if_t<std::is_floating_point<T>::value>> {
static constexpr auto name = _<std::is_same<T, float>::value || std::is_same<T, double>::value>(
_("float") + _<sizeof(T)*8>(), _("longdouble")
);
};
template <typename T>
struct npy_format_descriptor_name<T, enable_if_t<is_complex<T>::value>> {
static constexpr auto name = _<std::is_same<typename T::value_type, float>::value
|| std::is_same<typename T::value_type, double>::value>(
_("complex") + _<sizeof(typename T::value_type)*16>(), _("longcomplex")
);
};
template <typename T>
struct npy_format_descriptor<T, enable_if_t<satisfies_any_of<T, std::is_arithmetic, is_complex>::value>>
: npy_format_descriptor_name<T> {
private: private:
// NB: the order here must match the one in common.h // NB: the order here must match the one in common.h
constexpr static const int values[15] = { constexpr static const int values[15] = {
...@@ -1017,10 +996,25 @@ public: ...@@ -1017,10 +996,25 @@ public:
return reinterpret_borrow<pybind11::dtype>(ptr); return reinterpret_borrow<pybind11::dtype>(ptr);
pybind11_fail("Unsupported buffer format!"); pybind11_fail("Unsupported buffer format!");
} }
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"));
}
}; };
#define PYBIND11_DECL_CHAR_FMT \ #define PYBIND11_DECL_CHAR_FMT \
static constexpr auto name = _("S") + _<N>(); \ static PYBIND11_DESCR name() { return _("S") + _<N>(); } \
static pybind11::dtype dtype() { return pybind11::dtype(std::string("S") + std::to_string(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]> { PYBIND11_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 }; template <size_t N> struct npy_format_descriptor<std::array<char, N>> { PYBIND11_DECL_CHAR_FMT };
...@@ -1032,7 +1026,7 @@ private: ...@@ -1032,7 +1026,7 @@ private:
public: public:
static_assert(!array_info<T>::is_empty, "Zero-sized arrays are not supported"); static_assert(!array_info<T>::is_empty, "Zero-sized arrays are not supported");
static constexpr auto name = _("(") + array_info<T>::extents + _(")") + base_descr::name; static PYBIND11_DESCR name() { return _("(") + array_info<T>::extents() + _(")") + base_descr::name(); }
static pybind11::dtype dtype() { static pybind11::dtype dtype() {
list shape; list shape;
array_info<T>::append_extents(shape); array_info<T>::append_extents(shape);
...@@ -1044,7 +1038,7 @@ template<typename T> struct npy_format_descriptor<T, enable_if_t<std::is_enum<T> ...@@ -1044,7 +1038,7 @@ template<typename T> struct npy_format_descriptor<T, enable_if_t<std::is_enum<T>
private: private:
using base_descr = npy_format_descriptor<typename std::underlying_type<T>::type>; using base_descr = npy_format_descriptor<typename std::underlying_type<T>::type>;
public: public:
static constexpr auto name = base_descr::name; static PYBIND11_DESCR name() { return base_descr::name(); }
static pybind11::dtype dtype() { return base_descr::dtype(); } static pybind11::dtype dtype() { return base_descr::dtype(); }
}; };
...@@ -1119,7 +1113,7 @@ inline PYBIND11_NOINLINE void register_structured_dtype( ...@@ -1119,7 +1113,7 @@ inline PYBIND11_NOINLINE void register_structured_dtype(
template <typename T, typename SFINAE> struct npy_format_descriptor { 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_assert(is_pod_struct<T>::value, "Attempt to use a non-POD or unimplemented POD type as a numpy dtype");
static constexpr auto name = make_caster<T>::name; static PYBIND11_DESCR name() { return make_caster<T>::name(); }
static pybind11::dtype dtype() { static pybind11::dtype dtype() {
return reinterpret_borrow<pybind11::dtype>(dtype_ptr()); return reinterpret_borrow<pybind11::dtype>(dtype_ptr());
...@@ -1564,7 +1558,9 @@ vectorize_extractor(const Func &f, Return (*) (Args ...)) { ...@@ -1564,7 +1558,9 @@ vectorize_extractor(const Func &f, Return (*) (Args ...)) {
} }
template <typename T, int Flags> struct handle_type_name<array_t<T, Flags>> { template <typename T, int Flags> struct handle_type_name<array_t<T, Flags>> {
static constexpr auto name = _("numpy.ndarray[") + npy_format_descriptor<T>::name + _("]"); static PYBIND11_DESCR name() {
return _("numpy.ndarray[") + npy_format_descriptor<T>::name() + _("]");
}
}; };
NAMESPACE_END(detail) NAMESPACE_END(detail)
......
...@@ -51,7 +51,6 @@ NAMESPACE_BEGIN(PYBIND11_NAMESPACE) ...@@ -51,7 +51,6 @@ NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
class cpp_function : public function { class cpp_function : public function {
public: public:
cpp_function() { } cpp_function() { }
cpp_function(std::nullptr_t) { }
/// Construct a cpp_function from a vanilla function pointer /// Construct a cpp_function from a vanilla function pointer
template <typename Return, typename... Args, typename... Extra> template <typename Return, typename... Args, typename... Extra>
...@@ -94,7 +93,8 @@ protected: ...@@ -94,7 +93,8 @@ protected:
template <typename Func, typename Return, typename... Args, typename... Extra> template <typename Func, typename Return, typename... Args, typename... Extra>
void initialize(Func &&f, Return (*)(Args...), const Extra&... extra) { void initialize(Func &&f, Return (*)(Args...), const Extra&... extra) {
using namespace detail; using namespace detail;
struct capture { detail::remove_reference_t<Func> f; };
struct capture { remove_reference_t<Func> f; };
/* Store the function including any extra state it might have (e.g. a lambda capture object) */ /* Store the function including any extra state it might have (e.g. a lambda capture object) */
auto rec = make_function_record(); auto rec = make_function_record();
...@@ -113,23 +113,23 @@ protected: ...@@ -113,23 +113,23 @@ protected:
# pragma GCC diagnostic pop # pragma GCC diagnostic pop
#endif #endif
if (!std::is_trivially_destructible<Func>::value) if (!std::is_trivially_destructible<Func>::value)
rec->free_data = [](detail::function_record *r) { ((capture *) &r->data)->~capture(); }; rec->free_data = [](function_record *r) { ((capture *) &r->data)->~capture(); };
} else { } else {
rec->data[0] = new capture { std::forward<Func>(f) }; rec->data[0] = new capture { std::forward<Func>(f) };
rec->free_data = [](detail::function_record *r) { delete ((capture *) r->data[0]); }; rec->free_data = [](function_record *r) { delete ((capture *) r->data[0]); };
} }
/* Type casters for the function arguments and return value */ /* Type casters for the function arguments and return value */
using cast_in = detail::argument_loader<Args...>; using cast_in = argument_loader<Args...>;
using cast_out = detail::make_caster< using cast_out = make_caster<
detail::conditional_t<std::is_void<Return>::value, detail::void_type, Return> conditional_t<std::is_void<Return>::value, void_type, Return>
>; >;
static_assert(detail::expected_num_args<Extra...>(sizeof...(Args), cast_in::has_args, cast_in::has_kwargs), static_assert(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"); "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 */ /* Dispatch code which converts function arguments and performs the actual function call */
rec->impl = [](detail::function_call &call) -> handle { rec->impl = [](function_call &call) -> handle {
cast_in args_converter; cast_in args_converter;
/* Try to cast the function arguments into the C++ domain */ /* Try to cast the function arguments into the C++ domain */
...@@ -137,7 +137,7 @@ protected: ...@@ -137,7 +137,7 @@ protected:
return PYBIND11_TRY_NEXT_OVERLOAD; return PYBIND11_TRY_NEXT_OVERLOAD;
/* Invoke call policy pre-call hook */ /* Invoke call policy pre-call hook */
detail::process_attributes<Extra...>::precall(call); process_attributes<Extra...>::precall(call);
/* Get a pointer to the capture object */ /* Get a pointer to the capture object */
auto data = (sizeof(capture) <= sizeof(call.func.data) auto data = (sizeof(capture) <= sizeof(call.func.data)
...@@ -145,30 +145,29 @@ protected: ...@@ -145,30 +145,29 @@ protected:
capture *cap = const_cast<capture *>(reinterpret_cast<const capture *>(data)); capture *cap = const_cast<capture *>(reinterpret_cast<const capture *>(data));
/* Override policy for rvalues -- usually to enforce rvp::move on an rvalue */ /* 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); const auto policy = return_value_policy_override<Return>::policy(call.func.policy);
/* Function scope guard -- defaults to the compile-to-nothing `void_type` */ /* Function scope guard -- defaults to the compile-to-nothing `void_type` */
using Guard = detail::extract_guard_t<Extra...>; using Guard = extract_guard_t<Extra...>;
/* Perform the function call */ /* Perform the function call */
handle result = cast_out::cast( handle result = cast_out::cast(
std::move(args_converter).template call<Return, Guard>(cap->f), policy, call.parent); std::move(args_converter).template call<Return, Guard>(cap->f), policy, call.parent);
/* Invoke call policy post-call hook */ /* Invoke call policy post-call hook */
detail::process_attributes<Extra...>::postcall(call, result); process_attributes<Extra...>::postcall(call, result);
return result; return result;
}; };
/* Process any user-provided function attributes */ /* Process any user-provided function attributes */
detail::process_attributes<Extra...>::init(extra..., rec); process_attributes<Extra...>::init(extra..., rec);
/* Generate a readable signature describing the function's arguments and return value types */ /* Generate a readable signature describing the function's arguments and return value types */
static constexpr auto signature = _("(") + cast_in::arg_names + _(") -> ") + cast_out::name; PYBIND11_DESCR signature = _("(") + cast_in::arg_names() + _(") -> ") + cast_out::name();
PYBIND11_DESCR_CONSTEXPR auto types = decltype(signature)::types();
/* Register the function with Python from generic (non-templated) code */ /* Register the function with Python from generic (non-templated) code */
initialize_generic(rec, signature.text, types.data(), sizeof...(Args)); initialize_generic(rec, signature.text(), signature.types(), sizeof...(Args));
if (cast_in::has_args) rec->has_args = true; if (cast_in::has_args) rec->has_args = true;
if (cast_in::has_kwargs) rec->has_kwargs = true; if (cast_in::has_kwargs) rec->has_kwargs = true;
...@@ -218,30 +217,34 @@ protected: ...@@ -218,30 +217,34 @@ protected:
/* Generate a proper function signature */ /* Generate a proper function signature */
std::string signature; std::string signature;
size_t type_index = 0, arg_index = 0; size_t type_depth = 0, char_index = 0, type_index = 0, arg_index = 0;
for (auto *pc = text; *pc != '\0'; ++pc) { while (true) {
const auto c = *pc; char c = text[char_index++];
if (c == '\0')
break;
if (c == '{') { if (c == '{') {
// Write arg name for everything except *args and **kwargs. // Write arg name for everything except *args, **kwargs and return type.
if (*(pc + 1) == '*') if (type_depth == 0 && text[char_index] != '*' && arg_index < args) {
continue; if (!rec->args.empty() && rec->args[arg_index].name) {
signature += rec->args[arg_index].name;
if (arg_index < rec->args.size() && rec->args[arg_index].name) { } else if (arg_index == 0 && rec->is_method) {
signature += rec->args[arg_index].name; signature += "self";
} else if (arg_index == 0 && rec->is_method) { } else {
signature += "self"; signature += "arg" + std::to_string(arg_index - (rec->is_method ? 1 : 0));
} else { }
signature += "arg" + std::to_string(arg_index - (rec->is_method ? 1 : 0)); signature += ": ";
} }
signature += ": "; ++type_depth;
} else if (c == '}') { } else if (c == '}') {
// Write default value if available. --type_depth;
if (arg_index < rec->args.size() && rec->args[arg_index].descr) { if (type_depth == 0) {
signature += "="; if (arg_index < rec->args.size() && rec->args[arg_index].descr) {
signature += rec->args[arg_index].descr; signature += "=";
signature += rec->args[arg_index].descr;
}
arg_index++;
} }
arg_index++;
} else if (c == '%') { } else if (c == '%') {
const std::type_info *t = types[type_index++]; const std::type_info *t = types[type_index++];
if (!t) if (!t)
...@@ -266,9 +269,14 @@ protected: ...@@ -266,9 +269,14 @@ protected:
signature += c; signature += c;
} }
} }
if (arg_index != args || types[type_index] != nullptr) if (type_depth != 0 || types[type_index] != nullptr)
pybind11_fail("Internal error while parsing type signature (2)"); pybind11_fail("Internal error while parsing type signature (2)");
#if !defined(PYBIND11_CONSTEXPR_DESCR)
delete[] types;
delete[] text;
#endif
#if PY_MAJOR_VERSION < 3 #if PY_MAJOR_VERSION < 3
if (strcmp(rec->name, "__next__") == 0) { if (strcmp(rec->name, "__next__") == 0) {
std::free(rec->name); std::free(rec->name);
...@@ -568,8 +576,8 @@ protected: ...@@ -568,8 +576,8 @@ protected:
continue; // Unconsumed kwargs, but no py::kwargs argument to accept them 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 // 4a. If we have a py::args argument, create a new tuple with leftovers
tuple extra_args;
if (func.has_args) { if (func.has_args) {
tuple extra_args;
if (args_to_copy == 0) { if (args_to_copy == 0) {
// We didn't copy out any position arguments from the args_in tuple, so we // We didn't copy out any position arguments from the args_in tuple, so we
// can reuse it directly without copying: // can reuse it directly without copying:
...@@ -580,12 +588,12 @@ protected: ...@@ -580,12 +588,12 @@ protected:
size_t args_size = n_args_in - args_copied; size_t args_size = n_args_in - args_copied;
extra_args = tuple(args_size); extra_args = tuple(args_size);
for (size_t i = 0; i < args_size; ++i) { for (size_t i = 0; i < args_size; ++i) {
handle item = PyTuple_GET_ITEM(args_in, args_copied + i); extra_args[i] = PyTuple_GET_ITEM(args_in, args_copied + i);
extra_args[i] = item.inc_ref().ptr();
} }
} }
call.args.push_back(extra_args); call.args.push_back(extra_args);
call.args_convert.push_back(false); call.args_convert.push_back(false);
call.args_ref = std::move(extra_args);
} }
// 4b. If we have a py::kwargs, pass on any remaining kwargs // 4b. If we have a py::kwargs, pass on any remaining kwargs
...@@ -594,6 +602,7 @@ protected: ...@@ -594,6 +602,7 @@ protected:
kwargs = dict(); // If we didn't get one, send an empty one kwargs = dict(); // If we didn't get one, send an empty one
call.args.push_back(kwargs); call.args.push_back(kwargs);
call.args_convert.push_back(false); call.args_convert.push_back(false);
call.kwargs_ref = std::move(kwargs);
} }
// 5. Put everything in a vector. Not technically step 5, we've been building it // 5. Put everything in a vector. Not technically step 5, we've been building it
...@@ -952,18 +961,18 @@ protected: ...@@ -952,18 +961,18 @@ protected:
tinfo->get_buffer_data = get_buffer_data; tinfo->get_buffer_data = get_buffer_data;
} }
// rec_func must be set for either fget or fset.
void def_property_static_impl(const char *name, void def_property_static_impl(const char *name,
handle fget, handle fset, handle fget, handle fset,
detail::function_record *rec_func) { detail::function_record *rec_fget) {
const auto is_static = rec_func && !(rec_func->is_method && rec_func->scope); const auto is_static = !(rec_fget->is_method && rec_fget->scope);
const auto has_doc = rec_func && rec_func->doc && pybind11::options::show_user_defined_docstrings(); const auto has_doc = rec_fget->doc && pybind11::options::show_user_defined_docstrings();
auto property = handle((PyObject *) (is_static ? get_internals().static_property_type auto property = handle((PyObject *) (is_static ? get_internals().static_property_type
: &PyProperty_Type)); : &PyProperty_Type));
attr(name) = property(fget.ptr() ? fget : none(), attr(name) = property(fget.ptr() ? fget : none(),
fset.ptr() ? fset : none(), fset.ptr() ? fset : none(),
/*deleter*/none(), /*deleter*/none(),
pybind11::str(has_doc ? rec_func->doc : "")); pybind11::str(has_doc ? rec_fget->doc : ""));
} }
}; };
...@@ -995,18 +1004,10 @@ template <typename /*Derived*/, typename F> ...@@ -995,18 +1004,10 @@ template <typename /*Derived*/, typename F>
auto method_adaptor(F &&f) -> decltype(std::forward<F>(f)) { return std::forward<F>(f); } auto method_adaptor(F &&f) -> decltype(std::forward<F>(f)) { return std::forward<F>(f); }
template <typename Derived, typename Return, typename Class, typename... Args> template <typename Derived, typename Return, typename Class, typename... Args>
auto method_adaptor(Return (Class::*pmf)(Args...)) -> Return (Derived::*)(Args...) { auto method_adaptor(Return (Class::*pmf)(Args...)) -> Return (Derived::*)(Args...) { return pmf; }
static_assert(detail::is_accessible_base_of<Class, Derived>::value,
"Cannot bind an inaccessible base class method; use a lambda definition instead");
return pmf;
}
template <typename Derived, typename Return, typename Class, typename... Args> template <typename Derived, typename Return, typename Class, typename... Args>
auto method_adaptor(Return (Class::*pmf)(Args...) const) -> Return (Derived::*)(Args...) const { auto method_adaptor(Return (Class::*pmf)(Args...) const) -> Return (Derived::*)(Args...) const { return pmf; }
static_assert(detail::is_accessible_base_of<Class, Derived>::value,
"Cannot bind an inaccessible base class method; use a lambda definition instead");
return pmf;
}
template <typename type_, typename... options> template <typename type_, typename... options>
class class_ : public detail::generic_type { class class_ : public detail::generic_type {
...@@ -1197,7 +1198,7 @@ public: ...@@ -1197,7 +1198,7 @@ public:
/// Uses cpp_function's return_value_policy by default /// Uses cpp_function's return_value_policy by default
template <typename... Extra> template <typename... Extra>
class_ &def_property_readonly(const char *name, const cpp_function &fget, const Extra& ...extra) { class_ &def_property_readonly(const char *name, const cpp_function &fget, const Extra& ...extra) {
return def_property(name, fget, nullptr, extra...); return def_property(name, fget, cpp_function(), extra...);
} }
/// Uses return_value_policy::reference by default /// Uses return_value_policy::reference by default
...@@ -1209,7 +1210,7 @@ public: ...@@ -1209,7 +1210,7 @@ public:
/// Uses cpp_function's return_value_policy by default /// Uses cpp_function's return_value_policy by default
template <typename... Extra> template <typename... Extra>
class_ &def_property_readonly_static(const char *name, const cpp_function &fget, const Extra& ...extra) { class_ &def_property_readonly_static(const char *name, const cpp_function &fget, const Extra& ...extra) {
return def_property_static(name, fget, nullptr, extra...); return def_property_static(name, fget, cpp_function(), extra...);
} }
/// Uses return_value_policy::reference_internal by default /// Uses return_value_policy::reference_internal by default
...@@ -1239,25 +1240,21 @@ public: ...@@ -1239,25 +1240,21 @@ public:
template <typename... Extra> template <typename... Extra>
class_ &def_property_static(const char *name, const cpp_function &fget, const cpp_function &fset, const Extra& ...extra) { class_ &def_property_static(const char *name, const cpp_function &fget, const cpp_function &fset, const Extra& ...extra) {
auto rec_fget = get_function_record(fget), rec_fset = get_function_record(fset); auto rec_fget = get_function_record(fget), rec_fset = get_function_record(fset);
auto *rec_active = rec_fget; char *doc_prev = rec_fget->doc; /* 'extra' field may include a property-specific documentation string */
if (rec_fget) { detail::process_attributes<Extra...>::init(extra..., rec_fget);
char *doc_prev = rec_fget->doc; /* 'extra' field may include a property-specific documentation string */ if (rec_fget->doc && rec_fget->doc != doc_prev) {
detail::process_attributes<Extra...>::init(extra..., rec_fget); free(doc_prev);
if (rec_fget->doc && rec_fget->doc != doc_prev) { rec_fget->doc = strdup(rec_fget->doc);
free(doc_prev);
rec_fget->doc = strdup(rec_fget->doc);
}
} }
if (rec_fset) { if (rec_fset) {
char *doc_prev = rec_fset->doc; doc_prev = rec_fset->doc;
detail::process_attributes<Extra...>::init(extra..., rec_fset); detail::process_attributes<Extra...>::init(extra..., rec_fset);
if (rec_fset->doc && rec_fset->doc != doc_prev) { if (rec_fset->doc && rec_fset->doc != doc_prev) {
free(doc_prev); free(doc_prev);
rec_fset->doc = strdup(rec_fset->doc); rec_fset->doc = strdup(rec_fset->doc);
} }
if (! rec_active) rec_active = rec_fset;
} }
def_property_static_impl(name, fget, fset, rec_active); def_property_static_impl(name, fget, fset, rec_fget);
return *this; return *this;
} }
...@@ -1375,30 +1372,15 @@ public: ...@@ -1375,30 +1372,15 @@ public:
auto m_entries_ptr = m_entries.inc_ref().ptr(); auto m_entries_ptr = m_entries.inc_ref().ptr();
def("__repr__", [name, m_entries_ptr](Type value) -> pybind11::str { def("__repr__", [name, m_entries_ptr](Type value) -> pybind11::str {
for (const auto &kv : reinterpret_borrow<dict>(m_entries_ptr)) { for (const auto &kv : reinterpret_borrow<dict>(m_entries_ptr)) {
if (pybind11::cast<Type>(kv.second[int_(0)]) == value) if (pybind11::cast<Type>(kv.second) == value)
return pybind11::str("{}.{}").format(name, kv.first); return pybind11::str("{}.{}").format(name, kv.first);
} }
return pybind11::str("{}.???").format(name); return pybind11::str("{}.???").format(name);
}); });
def_property_readonly_static("__doc__", [m_entries_ptr](handle self) { def_property_readonly_static("__members__", [m_entries_ptr](object /* self */) {
std::string docstring;
const char *tp_doc = ((PyTypeObject *) self.ptr())->tp_doc;
if (tp_doc)
docstring += std::string(tp_doc) + "\n\n";
docstring += "Members:";
for (const auto &kv : reinterpret_borrow<dict>(m_entries_ptr)) {
auto key = std::string(pybind11::str(kv.first));
auto comment = kv.second[int_(1)];
docstring += "\n\n " + key;
if (!comment.is_none())
docstring += " : " + (std::string) pybind11::str(comment);
}
return docstring;
});
def_property_readonly_static("__members__", [m_entries_ptr](handle /* self */) {
dict m; dict m;
for (const auto &kv : reinterpret_borrow<dict>(m_entries_ptr)) for (const auto &kv : reinterpret_borrow<dict>(m_entries_ptr))
m[kv.first] = kv.second[int_(0)]; m[kv.first] = kv.second;
return m; return m;
}, return_value_policy::copy); }, return_value_policy::copy);
def(init([](Scalar i) { return static_cast<Type>(i); })); def(init([](Scalar i) { return static_cast<Type>(i); }));
...@@ -1446,15 +1428,15 @@ public: ...@@ -1446,15 +1428,15 @@ public:
/// Export enumeration entries into the parent scope /// Export enumeration entries into the parent scope
enum_& export_values() { enum_& export_values() {
for (const auto &kv : m_entries) for (const auto &kv : m_entries)
m_parent.attr(kv.first) = kv.second[int_(0)]; m_parent.attr(kv.first) = kv.second;
return *this; return *this;
} }
/// Add an enumeration entry /// Add an enumeration entry
enum_& value(char const* name, Type value, const char *doc = nullptr) { enum_& value(char const* name, Type value) {
auto v = pybind11::cast(value, return_value_policy::copy); auto v = pybind11::cast(value, return_value_policy::copy);
this->attr(name) = v; this->attr(name) = v;
m_entries[pybind11::str(name)] = std::make_pair(v, doc); m_entries[pybind11::str(name)] = v;
return *this; return *this;
} }
......
...@@ -295,9 +295,6 @@ public: ...@@ -295,9 +295,6 @@ public:
PyErr_Fetch(&type.ptr(), &value.ptr(), &trace.ptr()); PyErr_Fetch(&type.ptr(), &value.ptr(), &trace.ptr());
} }
error_already_set(const error_already_set &) = default;
error_already_set(error_already_set &&) = default;
inline ~error_already_set(); inline ~error_already_set();
/// Give the currently-held error back to Python, if any. If there is currently a Python error /// Give the currently-held error back to Python, if any. If there is currently a Python error
......
...@@ -30,7 +30,8 @@ ...@@ -30,7 +30,8 @@
# define PYBIND11_HAS_OPTIONAL 1 # define PYBIND11_HAS_OPTIONAL 1
# endif # endif
// std::experimental::optional (but not allowed in c++11 mode) // std::experimental::optional (but not allowed in c++11 mode)
# if defined(PYBIND11_CPP14) && __has_include(<experimental/optional>) # if defined(PYBIND11_CPP14) && (__has_include(<experimental/optional>) && \
!__has_include(<optional>))
# include <experimental/optional> # include <experimental/optional>
# define PYBIND11_HAS_EXP_OPTIONAL 1 # define PYBIND11_HAS_EXP_OPTIONAL 1
# endif # endif
...@@ -91,7 +92,7 @@ template <typename Type, typename Key> struct set_caster { ...@@ -91,7 +92,7 @@ template <typename Type, typename Key> struct set_caster {
return s.release(); return s.release();
} }
PYBIND11_TYPE_CASTER(type, _("Set[") + key_conv::name + _("]")); PYBIND11_TYPE_CASTER(type, _("Set[") + key_conv::name() + _("]"));
}; };
template <typename Type, typename Key, typename Value> struct map_caster { template <typename Type, typename Key, typename Value> struct map_caster {
...@@ -127,7 +128,7 @@ template <typename Type, typename Key, typename Value> struct map_caster { ...@@ -127,7 +128,7 @@ template <typename Type, typename Key, typename Value> struct map_caster {
return d.release(); return d.release();
} }
PYBIND11_TYPE_CASTER(Type, _("Dict[") + key_conv::name + _(", ") + value_conv::name + _("]")); PYBIND11_TYPE_CASTER(Type, _("Dict[") + key_conv::name() + _(", ") + value_conv::name() + _("]"));
}; };
template <typename Type, typename Value> struct list_caster { template <typename Type, typename Value> struct list_caster {
...@@ -168,7 +169,7 @@ public: ...@@ -168,7 +169,7 @@ public:
return l.release(); return l.release();
} }
PYBIND11_TYPE_CASTER(Type, _("List[") + value_conv::name + _("]")); PYBIND11_TYPE_CASTER(Type, _("List[") + value_conv::name() + _("]"));
}; };
template <typename Type, typename Alloc> struct type_caster<std::vector<Type, Alloc>> template <typename Type, typename Alloc> struct type_caster<std::vector<Type, Alloc>>
...@@ -222,7 +223,7 @@ public: ...@@ -222,7 +223,7 @@ public:
return l.release(); return l.release();
} }
PYBIND11_TYPE_CASTER(ArrayType, _("List[") + value_conv::name + _<Resizable>(_(""), _("[") + _<Size>() + _("]")) + _("]")); PYBIND11_TYPE_CASTER(ArrayType, _("List[") + value_conv::name() + _<Resizable>(_(""), _("[") + _<Size>() + _("]")) + _("]"));
}; };
template <typename Type, size_t Size> struct type_caster<std::array<Type, Size>> template <typename Type, size_t Size> struct type_caster<std::array<Type, Size>>
...@@ -268,7 +269,7 @@ template<typename T> struct optional_caster { ...@@ -268,7 +269,7 @@ template<typename T> struct optional_caster {
return true; return true;
} }
PYBIND11_TYPE_CASTER(T, _("Optional[") + value_conv::name + _("]")); PYBIND11_TYPE_CASTER(T, _("Optional[") + value_conv::name() + _("]"));
}; };
#if PYBIND11_HAS_OPTIONAL #if PYBIND11_HAS_OPTIONAL
...@@ -348,7 +349,7 @@ struct variant_caster<V<Ts...>> { ...@@ -348,7 +349,7 @@ struct variant_caster<V<Ts...>> {
} }
using Type = V<Ts...>; using Type = V<Ts...>;
PYBIND11_TYPE_CASTER(Type, _("Union[") + detail::concat(make_caster<Ts>::name...) + _("]")); PYBIND11_TYPE_CASTER(Type, _("Union[") + detail::concat(make_caster<Ts>::name()...) + _("]"));
}; };
#if PYBIND11_HAS_VARIANT #if PYBIND11_HAS_VARIANT
......
...@@ -587,7 +587,7 @@ class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args&&. ...@@ -587,7 +587,7 @@ class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args&&.
auto it = m.find(k); auto it = m.find(k);
if (it == m.end()) if (it == m.end())
throw key_error(); throw key_error();
return m.erase(it); m.erase(it);
} }
); );
......
# - Find python libraries # - Find python libraries
# This module finds the libraries corresponding to the Python interpeter # This module finds the libraries corresponding to the Python interpreter
# FindPythonInterp provides. # FindPythonInterp provides.
# This code sets the following variables: # This code sets the following variables:
# #
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment