Unverified Commit ec24786e authored by Ralf W. Grosse-Kunstleve's avatar Ralf W. Grosse-Kunstleve Committed by GitHub
Browse files

Fully-automatic clang-format with include reordering (#3713)

* chore: add clang-format

* Removing check-style (Classic check-style)

Ported from @henryiii's https://github.com/pybind/pybind11/pull/3683/commits/53056b1b0eeb4136b0d7362a8261b6b59658e0a7



* Automatic clang-format changes (NO manual changes).
Co-authored-by: default avatarHenry Schreiner <henryschreineriii@gmail.com>
parent e96221be
......@@ -16,12 +16,50 @@ PYBIND11_NAMESPACE_BEGIN(detail)
/// Enumeration with all supported operator types
enum op_id : int {
op_add, op_sub, op_mul, op_div, op_mod, op_divmod, op_pow, op_lshift,
op_rshift, op_and, op_xor, op_or, op_neg, op_pos, op_abs, op_invert,
op_int, op_long, op_float, op_str, op_cmp, op_gt, op_ge, op_lt, op_le,
op_eq, op_ne, op_iadd, op_isub, op_imul, op_idiv, op_imod, op_ilshift,
op_irshift, op_iand, op_ixor, op_ior, op_complex, op_bool, op_nonzero,
op_repr, op_truediv, op_itruediv, op_hash
op_add,
op_sub,
op_mul,
op_div,
op_mod,
op_divmod,
op_pow,
op_lshift,
op_rshift,
op_and,
op_xor,
op_or,
op_neg,
op_pos,
op_abs,
op_invert,
op_int,
op_long,
op_float,
op_str,
op_cmp,
op_gt,
op_ge,
op_lt,
op_le,
op_eq,
op_ne,
op_iadd,
op_isub,
op_imul,
op_idiv,
op_imod,
op_ilshift,
op_irshift,
op_iand,
op_ixor,
op_ior,
op_complex,
op_bool,
op_nonzero,
op_repr,
op_truediv,
op_itruediv,
op_hash
};
enum op_type : int {
......@@ -30,126 +68,145 @@ enum op_type : int {
op_u /* unary operator */
};
struct self_t { };
struct self_t {};
static const self_t self = self_t();
/// Type for an unused type slot
struct undefined_t { };
struct undefined_t {};
/// Don't warn about an unused variable
inline self_t __self() { return self; }
/// base template of operator implementations
template <op_id, op_type, typename B, typename L, typename R> struct op_impl { };
template <op_id, op_type, typename B, typename L, typename R>
struct op_impl {};
/// Operator implementation generator
template <op_id id, op_type ot, typename L, typename R> struct op_ {
template <typename Class, typename... Extra> void execute(Class &cl, const Extra&... extra) const {
template <op_id id, op_type ot, typename L, typename R>
struct op_ {
template <typename Class, typename... Extra>
void execute(Class &cl, const Extra &...extra) const {
using Base = typename Class::type;
using L_type = conditional_t<std::is_same<L, self_t>::value, Base, L>;
using R_type = conditional_t<std::is_same<R, self_t>::value, Base, R>;
using op = op_impl<id, ot, Base, L_type, R_type>;
cl.def(op::name(), &op::execute, is_operator(), extra...);
#if PY_MAJOR_VERSION < 3
if (PYBIND11_SILENCE_MSVC_C4127(id == op_truediv) ||
PYBIND11_SILENCE_MSVC_C4127(id == op_itruediv))
cl.def(id == op_itruediv ? "__idiv__" : ot == op_l ? "__div__" : "__rdiv__",
&op::execute, is_operator(), extra...);
#endif
#if PY_MAJOR_VERSION < 3
if (PYBIND11_SILENCE_MSVC_C4127(id == op_truediv)
|| PYBIND11_SILENCE_MSVC_C4127(id == op_itruediv))
cl.def(id == op_itruediv ? "__idiv__"
: ot == op_l ? "__div__"
: "__rdiv__",
&op::execute,
is_operator(),
extra...);
#endif
}
template <typename Class, typename... Extra> void execute_cast(Class &cl, const Extra&... extra) const {
template <typename Class, typename... Extra>
void execute_cast(Class &cl, const Extra &...extra) const {
using Base = typename Class::type;
using L_type = conditional_t<std::is_same<L, self_t>::value, Base, L>;
using R_type = conditional_t<std::is_same<R, self_t>::value, Base, R>;
using op = op_impl<id, ot, Base, L_type, R_type>;
cl.def(op::name(), &op::execute_cast, is_operator(), extra...);
#if PY_MAJOR_VERSION < 3
#if PY_MAJOR_VERSION < 3
if (id == op_truediv || id == op_itruediv)
cl.def(id == op_itruediv ? "__idiv__" : ot == op_l ? "__div__" : "__rdiv__",
&op::execute, is_operator(), extra...);
#endif
cl.def(id == op_itruediv ? "__idiv__"
: ot == op_l ? "__div__"
: "__rdiv__",
&op::execute,
is_operator(),
extra...);
#endif
}
};
#define PYBIND11_BINARY_OPERATOR(id, rid, op, expr) \
template <typename B, typename L, typename R> struct op_impl<op_##id, op_l, B, L, R> { \
static char const* name() { return "__" #id "__"; } \
static auto execute(const L &l, const R &r) -> decltype(expr) { return (expr); } \
static B execute_cast(const L &l, const R &r) { return B(expr); } \
}; \
template <typename B, typename L, typename R> struct op_impl<op_##id, op_r, B, L, R> { \
static char const* name() { return "__" #rid "__"; } \
static auto execute(const R &r, const L &l) -> decltype(expr) { return (expr); } \
static B execute_cast(const R &r, const L &l) { return B(expr); } \
}; \
inline op_<op_##id, op_l, self_t, self_t> op(const self_t &, const self_t &) { \
return op_<op_##id, op_l, self_t, self_t>(); \
} \
template <typename T> op_<op_##id, op_l, self_t, T> op(const self_t &, const T &) { \
return op_<op_##id, op_l, self_t, T>(); \
} \
template <typename T> op_<op_##id, op_r, T, self_t> op(const T &, const self_t &) { \
return op_<op_##id, op_r, T, self_t>(); \
}
#define PYBIND11_INPLACE_OPERATOR(id, op, expr) \
template <typename B, typename L, typename R> struct op_impl<op_##id, op_l, B, L, R> { \
static char const* name() { return "__" #id "__"; } \
static auto execute(L &l, const R &r) -> decltype(expr) { return expr; } \
static B execute_cast(L &l, const R &r) { return B(expr); } \
}; \
template <typename T> op_<op_##id, op_l, self_t, T> op(const self_t &, const T &) { \
return op_<op_##id, op_l, self_t, T>(); \
}
#define PYBIND11_UNARY_OPERATOR(id, op, expr) \
template <typename B, typename L> struct op_impl<op_##id, op_u, B, L, undefined_t> { \
static char const* name() { return "__" #id "__"; } \
static auto execute(const L &l) -> decltype(expr) { return expr; } \
static B execute_cast(const L &l) { return B(expr); } \
}; \
inline op_<op_##id, op_u, self_t, undefined_t> op(const self_t &) { \
return op_<op_##id, op_u, self_t, undefined_t>(); \
}
PYBIND11_BINARY_OPERATOR(sub, rsub, operator-, l - r)
PYBIND11_BINARY_OPERATOR(add, radd, operator+, l + r)
PYBIND11_BINARY_OPERATOR(mul, rmul, operator*, l * r)
PYBIND11_BINARY_OPERATOR(truediv, rtruediv, operator/, l / r)
PYBIND11_BINARY_OPERATOR(mod, rmod, operator%, l % r)
PYBIND11_BINARY_OPERATOR(lshift, rlshift, operator<<, l << r)
PYBIND11_BINARY_OPERATOR(rshift, rrshift, operator>>, l >> r)
PYBIND11_BINARY_OPERATOR(and, rand, operator&, l & r)
PYBIND11_BINARY_OPERATOR(xor, rxor, operator^, l ^ r)
PYBIND11_BINARY_OPERATOR(eq, eq, operator==, l == r)
PYBIND11_BINARY_OPERATOR(ne, ne, operator!=, l != r)
PYBIND11_BINARY_OPERATOR(or, ror, operator|, l | r)
PYBIND11_BINARY_OPERATOR(gt, lt, operator>, l > r)
PYBIND11_BINARY_OPERATOR(ge, le, operator>=, l >= r)
PYBIND11_BINARY_OPERATOR(lt, gt, operator<, l < r)
PYBIND11_BINARY_OPERATOR(le, ge, operator<=, l <= r)
//PYBIND11_BINARY_OPERATOR(pow, rpow, pow, std::pow(l, r))
PYBIND11_INPLACE_OPERATOR(iadd, operator+=, l += r)
PYBIND11_INPLACE_OPERATOR(isub, operator-=, l -= r)
PYBIND11_INPLACE_OPERATOR(imul, operator*=, l *= r)
PYBIND11_INPLACE_OPERATOR(itruediv, operator/=, l /= r)
PYBIND11_INPLACE_OPERATOR(imod, operator%=, l %= r)
PYBIND11_INPLACE_OPERATOR(ilshift, operator<<=, l <<= r)
PYBIND11_INPLACE_OPERATOR(irshift, operator>>=, l >>= r)
PYBIND11_INPLACE_OPERATOR(iand, operator&=, l &= r)
PYBIND11_INPLACE_OPERATOR(ixor, operator^=, l ^= r)
PYBIND11_INPLACE_OPERATOR(ior, operator|=, l |= r)
PYBIND11_UNARY_OPERATOR(neg, operator-, -l)
PYBIND11_UNARY_OPERATOR(pos, operator+, +l)
#define PYBIND11_BINARY_OPERATOR(id, rid, op, expr) \
template <typename B, typename L, typename R> \
struct op_impl<op_##id, op_l, B, L, R> { \
static char const *name() { return "__" #id "__"; } \
static auto execute(const L &l, const R &r) -> decltype(expr) { return (expr); } \
static B execute_cast(const L &l, const R &r) { return B(expr); } \
}; \
template <typename B, typename L, typename R> \
struct op_impl<op_##id, op_r, B, L, R> { \
static char const *name() { return "__" #rid "__"; } \
static auto execute(const R &r, const L &l) -> decltype(expr) { return (expr); } \
static B execute_cast(const R &r, const L &l) { return B(expr); } \
}; \
inline op_<op_##id, op_l, self_t, self_t> op(const self_t &, const self_t &) { \
return op_<op_##id, op_l, self_t, self_t>(); \
} \
template <typename T> \
op_<op_##id, op_l, self_t, T> op(const self_t &, const T &) { \
return op_<op_##id, op_l, self_t, T>(); \
} \
template <typename T> \
op_<op_##id, op_r, T, self_t> op(const T &, const self_t &) { \
return op_<op_##id, op_r, T, self_t>(); \
}
#define PYBIND11_INPLACE_OPERATOR(id, op, expr) \
template <typename B, typename L, typename R> \
struct op_impl<op_##id, op_l, B, L, R> { \
static char const *name() { return "__" #id "__"; } \
static auto execute(L &l, const R &r) -> decltype(expr) { return expr; } \
static B execute_cast(L &l, const R &r) { return B(expr); } \
}; \
template <typename T> \
op_<op_##id, op_l, self_t, T> op(const self_t &, const T &) { \
return op_<op_##id, op_l, self_t, T>(); \
}
#define PYBIND11_UNARY_OPERATOR(id, op, expr) \
template <typename B, typename L> \
struct op_impl<op_##id, op_u, B, L, undefined_t> { \
static char const *name() { return "__" #id "__"; } \
static auto execute(const L &l) -> decltype(expr) { return expr; } \
static B execute_cast(const L &l) { return B(expr); } \
}; \
inline op_<op_##id, op_u, self_t, undefined_t> op(const self_t &) { \
return op_<op_##id, op_u, self_t, undefined_t>(); \
}
PYBIND11_BINARY_OPERATOR(sub, rsub, operator-, l - r)
PYBIND11_BINARY_OPERATOR(add, radd, operator+, l + r)
PYBIND11_BINARY_OPERATOR(mul, rmul, operator*, l *r)
PYBIND11_BINARY_OPERATOR(truediv, rtruediv, operator/, l / r)
PYBIND11_BINARY_OPERATOR(mod, rmod, operator%, l % r)
PYBIND11_BINARY_OPERATOR(lshift, rlshift, operator<<, l << r)
PYBIND11_BINARY_OPERATOR(rshift, rrshift, operator>>, l >> r)
PYBIND11_BINARY_OPERATOR(and, rand, operator&, l &r)
PYBIND11_BINARY_OPERATOR(xor, rxor, operator^, l ^ r)
PYBIND11_BINARY_OPERATOR(eq, eq, operator==, l == r)
PYBIND11_BINARY_OPERATOR(ne, ne, operator!=, l != r)
PYBIND11_BINARY_OPERATOR(or, ror, operator|, l | r)
PYBIND11_BINARY_OPERATOR(gt, lt, operator>, l > r)
PYBIND11_BINARY_OPERATOR(ge, le, operator>=, l >= r)
PYBIND11_BINARY_OPERATOR(lt, gt, operator<, l < r)
PYBIND11_BINARY_OPERATOR(le, ge, operator<=, l <= r)
// PYBIND11_BINARY_OPERATOR(pow, rpow, pow, std::pow(l, r))
PYBIND11_INPLACE_OPERATOR(iadd, operator+=, l += r)
PYBIND11_INPLACE_OPERATOR(isub, operator-=, l -= r)
PYBIND11_INPLACE_OPERATOR(imul, operator*=, l *= r)
PYBIND11_INPLACE_OPERATOR(itruediv, operator/=, l /= r)
PYBIND11_INPLACE_OPERATOR(imod, operator%=, l %= r)
PYBIND11_INPLACE_OPERATOR(ilshift, operator<<=, l <<= r)
PYBIND11_INPLACE_OPERATOR(irshift, operator>>=, l >>= r)
PYBIND11_INPLACE_OPERATOR(iand, operator&=, l &= r)
PYBIND11_INPLACE_OPERATOR(ixor, operator^=, l ^= r)
PYBIND11_INPLACE_OPERATOR(ior, operator|=, l |= r)
PYBIND11_UNARY_OPERATOR(neg, operator-, -l)
PYBIND11_UNARY_OPERATOR(pos, operator+, +l)
// WARNING: This usage of `abs` should only be done for existing STL overloads.
// Adding overloads directly in to the `std::` namespace is advised against:
// https://en.cppreference.com/w/cpp/language/extending_std
PYBIND11_UNARY_OPERATOR(abs, abs, std::abs(l))
PYBIND11_UNARY_OPERATOR(hash, hash, std::hash<L>()(l))
PYBIND11_UNARY_OPERATOR(invert, operator~, (~l))
PYBIND11_UNARY_OPERATOR(bool, operator!, !!l)
PYBIND11_UNARY_OPERATOR(int, int_, (int) l)
PYBIND11_UNARY_OPERATOR(float, float_, (double) l)
PYBIND11_UNARY_OPERATOR(abs, abs, std::abs(l))
PYBIND11_UNARY_OPERATOR(hash, hash, std::hash<L>()(l))
PYBIND11_UNARY_OPERATOR(invert, operator~, (~l))
PYBIND11_UNARY_OPERATOR(bool, operator!, !!l)
PYBIND11_UNARY_OPERATOR(int, int_, (int) l)
PYBIND11_UNARY_OPERATOR(float, float_, (double) l)
#undef PYBIND11_BINARY_OPERATOR
#undef PYBIND11_INPLACE_OPERATOR
......
......@@ -15,44 +15,54 @@ PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
class options {
public:
// Default RAII constructor, which leaves settings as they currently are.
options() : previous_state(global_state()) {}
// Class is non-copyable.
options(const options&) = delete;
options& operator=(const options&) = delete;
options(const options &) = delete;
options &operator=(const options &) = delete;
// Destructor, which restores settings that were in effect before.
~options() {
global_state() = previous_state;
}
~options() { global_state() = previous_state; }
// Setter methods (affect the global state):
options& disable_user_defined_docstrings() & { global_state().show_user_defined_docstrings = false; return *this; }
options &disable_user_defined_docstrings() & {
global_state().show_user_defined_docstrings = false;
return *this;
}
options& enable_user_defined_docstrings() & { global_state().show_user_defined_docstrings = true; return *this; }
options &enable_user_defined_docstrings() & {
global_state().show_user_defined_docstrings = true;
return *this;
}
options& disable_function_signatures() & { global_state().show_function_signatures = false; return *this; }
options &disable_function_signatures() & {
global_state().show_function_signatures = false;
return *this;
}
options& enable_function_signatures() & { global_state().show_function_signatures = true; return *this; }
options &enable_function_signatures() & {
global_state().show_function_signatures = true;
return *this;
}
// Getter methods (return the global state):
static bool show_user_defined_docstrings() { return global_state().show_user_defined_docstrings; }
static bool show_user_defined_docstrings() {
return global_state().show_user_defined_docstrings;
}
static bool show_function_signatures() { return global_state().show_function_signatures; }
// This type is not meant to be allocated on the heap.
void* operator new(size_t) = delete;
void *operator new(size_t) = delete;
private:
struct state {
bool show_user_defined_docstrings = true; //< Include user-supplied texts in docstrings.
bool show_function_signatures = true; //< Include auto-generated function signatures
// in docstrings.
bool show_user_defined_docstrings = true; //< Include user-supplied texts in docstrings.
bool show_function_signatures = true; //< Include auto-generated function signatures
// in docstrings.
};
static state &global_state() {
......
......@@ -10,30 +10,29 @@
#pragma once
#include "detail/class.h"
#include "detail/init.h"
#include "attr.h"
#include "gil.h"
#include "options.h"
#include "detail/class.h"
#include "detail/init.h"
#include <cstdlib>
#include <cstring>
#include <memory>
#include <new>
#include <vector>
#include <string>
#include <utility>
#include <cstring>
#include <vector>
#if defined(__cpp_lib_launder) && !(defined(_MSC_VER) && (_MSC_VER < 1914))
# define PYBIND11_STD_LAUNDER std::launder
# define PYBIND11_HAS_STD_LAUNDER 1
# define PYBIND11_STD_LAUNDER std::launder
# define PYBIND11_HAS_STD_LAUNDER 1
#else
# define PYBIND11_STD_LAUNDER
# define PYBIND11_HAS_STD_LAUNDER 0
# define PYBIND11_STD_LAUNDER
# define PYBIND11_HAS_STD_LAUNDER 0
#endif
#if defined(__GNUG__) && !defined(__clang__)
# include <cxxabi.h>
# include <cxxabi.h>
#endif
/* https://stackoverflow.com/questions/46798456/handling-gccs-noexcept-type-warning
......@@ -56,7 +55,7 @@ PYBIND11_NAMESPACE_BEGIN(detail)
// Return true if one of the translators completed without raising an exception
// itself. Return of false indicates that if there are other translators
// available, they should be tried.
inline bool apply_exception_translators(std::forward_list<ExceptionTranslator>& translators) {
inline bool apply_exception_translators(std::forward_list<ExceptionTranslator> &translators) {
auto last_exception = std::current_exception();
for (auto &translator : translators) {
......@@ -83,30 +82,33 @@ class cpp_function : public function {
public:
cpp_function() = default;
// NOLINTNEXTLINE(google-explicit-constructor)
cpp_function(std::nullptr_t) { }
cpp_function(std::nullptr_t) {}
/// Construct a cpp_function from a vanilla function pointer
template <typename Return, typename... Args, typename... Extra>
// NOLINTNEXTLINE(google-explicit-constructor)
cpp_function(Return (*f)(Args...), const Extra&... extra) {
cpp_function(Return (*f)(Args...), const Extra &...extra) {
initialize(f, f, extra...);
}
/// Construct a cpp_function from a lambda function (possibly with internal state)
template <typename Func, typename... Extra,
template <typename Func,
typename... Extra,
typename = detail::enable_if_t<detail::is_lambda<Func>::value>>
// NOLINTNEXTLINE(google-explicit-constructor)
cpp_function(Func &&f, const Extra&... extra) {
initialize(std::forward<Func>(f),
(detail::function_signature_t<Func> *) nullptr, extra...);
cpp_function(Func &&f, const Extra &...extra) {
initialize(
std::forward<Func>(f), (detail::function_signature_t<Func> *) nullptr, extra...);
}
/// Construct a cpp_function from a class method (non-const, no ref-qualifier)
template <typename Return, typename Class, typename... Arg, typename... Extra>
// NOLINTNEXTLINE(google-explicit-constructor)
cpp_function(Return (Class::*f)(Arg...), const Extra&... extra) {
initialize([f](Class *c, Arg... args) -> Return { return (c->*f)(std::forward<Arg>(args)...); },
(Return (*) (Class *, Arg...)) nullptr, extra...);
cpp_function(Return (Class::*f)(Arg...), const Extra &...extra) {
initialize(
[f](Class *c, Arg... args) -> Return { return (c->*f)(std::forward<Arg>(args)...); },
(Return(*)(Class *, Arg...)) nullptr,
extra...);
}
/// Construct a cpp_function from a class method (non-const, lvalue ref-qualifier)
......@@ -114,17 +116,21 @@ public:
/// but with an added `&`.
template <typename Return, typename Class, typename... Arg, typename... Extra>
// NOLINTNEXTLINE(google-explicit-constructor)
cpp_function(Return (Class::*f)(Arg...)&, const Extra&... extra) {
initialize([f](Class *c, Arg... args) -> Return { return (c->*f)(std::forward<Arg>(args)...); },
(Return (*) (Class *, Arg...)) nullptr, extra...);
cpp_function(Return (Class::*f)(Arg...) &, const Extra &...extra) {
initialize(
[f](Class *c, Arg... args) -> Return { return (c->*f)(std::forward<Arg>(args)...); },
(Return(*)(Class *, Arg...)) nullptr,
extra...);
}
/// Construct a cpp_function from a class method (const, no ref-qualifier)
template <typename Return, typename Class, typename... Arg, typename... Extra>
// NOLINTNEXTLINE(google-explicit-constructor)
cpp_function(Return (Class::*f)(Arg...) const, const Extra&... extra) {
initialize([f](const Class *c, Arg... args) -> Return { return (c->*f)(std::forward<Arg>(args)...); },
(Return (*)(const Class *, Arg ...)) nullptr, extra...);
cpp_function(Return (Class::*f)(Arg...) const, const Extra &...extra) {
initialize([f](const Class *c,
Arg... args) -> Return { return (c->*f)(std::forward<Arg>(args)...); },
(Return(*)(const Class *, Arg...)) nullptr,
extra...);
}
/// Construct a cpp_function from a class method (const, lvalue ref-qualifier)
......@@ -132,9 +138,11 @@ public:
/// but with an added `&`.
template <typename Return, typename Class, typename... Arg, typename... Extra>
// NOLINTNEXTLINE(google-explicit-constructor)
cpp_function(Return (Class::*f)(Arg...) const&, const Extra&... extra) {
initialize([f](const Class *c, Arg... args) -> Return { return (c->*f)(std::forward<Arg>(args)...); },
(Return (*)(const Class *, Arg ...)) nullptr, extra...);
cpp_function(Return (Class::*f)(Arg...) const &, const Extra &...extra) {
initialize([f](const Class *c,
Arg... args) -> Return { return (c->*f)(std::forward<Arg>(args)...); },
(Return(*)(const Class *, Arg...)) nullptr,
extra...);
}
/// Return the function name
......@@ -144,9 +152,10 @@ protected:
struct InitializingFunctionRecordDeleter {
// `destruct(function_record, false)`: `initialize_generic` copies strings and
// takes care of cleaning up in case of exceptions. So pass `false` to `free_strings`.
void operator()(detail::function_record * rec) { destruct(rec, false); }
void operator()(detail::function_record *rec) { destruct(rec, false); }
};
using unique_function_record = std::unique_ptr<detail::function_record, InitializingFunctionRecordDeleter>;
using unique_function_record
= std::unique_ptr<detail::function_record, InitializingFunctionRecordDeleter>;
/// Space optimization: don't inline this frequently instantiated fragment
PYBIND11_NOINLINE unique_function_record make_function_record() {
......@@ -155,11 +164,14 @@ 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) {
void initialize(Func &&f, Return (*)(Args...), const Extra &...extra) {
using namespace detail;
struct capture { 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) */
// The unique_ptr makes sure nothing is leaked in case of an exception.
auto unique_rec = make_function_record();
auto *rec = unique_rec.get();
......@@ -170,16 +182,16 @@ protected:
enough space to use the placement new operator. However, the
'if' statement above ensures that this is the case. */
#if defined(__GNUG__) && __GNUC__ >= 6 && !defined(__clang__) && !defined(__INTEL_COMPILER)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wplacement-new"
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wplacement-new"
#endif
new ((capture *) &rec->data) capture { std::forward<Func>(f) };
new ((capture *) &rec->data) capture{std::forward<Func>(f)};
#if defined(__GNUG__) && __GNUC__ >= 6 && !defined(__clang__) && !defined(__INTEL_COMPILER)
# pragma GCC diagnostic pop
# pragma GCC diagnostic pop
#endif
#if defined(__GNUG__) && !PYBIND11_HAS_STD_LAUNDER && !defined(__INTEL_COMPILER)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wstrict-aliasing"
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wstrict-aliasing"
#endif
// UB without std::launder, but without breaking ABI and/or
// a significant refactoring it's "impossible" to solve.
......@@ -191,21 +203,22 @@ protected:
};
}
#if defined(__GNUG__) && !PYBIND11_HAS_STD_LAUNDER && !defined(__INTEL_COMPILER)
# pragma GCC diagnostic pop
# pragma GCC diagnostic pop
#endif
} else {
rec->data[0] = new capture { std::forward<Func>(f) };
rec->data[0] = new capture{std::forward<Func>(f)};
rec->free_data = [](function_record *r) { delete ((capture *) r->data[0]); };
}
/* Type casters for the function arguments and return value */
using cast_in = argument_loader<Args...>;
using cast_out = make_caster<
conditional_t<std::is_void<Return>::value, void_type, Return>
>;
using cast_out
= make_caster<conditional_t<std::is_void<Return>::value, void_type, Return>>;
static_assert(expected_num_args<Extra...>(sizeof...(Args), cast_in::args_pos >= 0, cast_in::has_kwargs),
"The number of argument annotations does not match the number of function arguments");
static_assert(
expected_num_args<Extra...>(
sizeof...(Args), cast_in::args_pos >= 0, 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 = [](function_call &call) -> handle {
......@@ -225,14 +238,17 @@ protected:
auto *cap = const_cast<capture *>(reinterpret_cast<const capture *>(data));
/* Override policy for rvalues -- usually to enforce rvp::move on an rvalue */
return_value_policy policy = return_value_policy_override<Return>::policy(call.func.policy);
return_value_policy policy
= return_value_policy_override<Return>::policy(call.func.policy);
/* Function scope guard -- defaults to the compile-to-nothing `void_type` */
using Guard = extract_guard_t<Extra...>;
/* Perform the function call */
handle result = cast_out::cast(
std::move(args_converter).template call<Return, Guard>(cap->f), policy, call.parent);
handle result
= cast_out::cast(std::move(args_converter).template call<Return, Guard>(cap->f),
policy,
call.parent);
/* Invoke call policy post-call hook */
process_attributes<Extra...>::postcall(call, result);
......@@ -241,9 +257,9 @@ protected:
};
rec->nargs_pos = cast_in::args_pos >= 0
? static_cast<std::uint16_t>(cast_in::args_pos)
: sizeof...(Args) - cast_in::has_kwargs; // Will get reduced more if
// we have a kw_only
? static_cast<std::uint16_t>(cast_in::args_pos)
: sizeof...(Args) - cast_in::has_kwargs; // Will get reduced more if
// we have a kw_only
rec->has_args = cast_in::args_pos >= 0;
rec->has_kwargs = cast_in::has_kwargs;
......@@ -254,19 +270,26 @@ protected:
constexpr bool has_kw_only_args = any_of<std::is_same<kw_only, Extra>...>::value,
has_pos_only_args = any_of<std::is_same<pos_only, Extra>...>::value,
has_arg_annotations = any_of<is_keyword<Extra>...>::value;
static_assert(has_arg_annotations || !has_kw_only_args, "py::kw_only requires the use of argument annotations");
static_assert(has_arg_annotations || !has_pos_only_args, "py::pos_only requires the use of argument annotations (for docstrings and aligning the annotations to the argument)");
static_assert(constexpr_sum(is_kw_only<Extra>::value...) <= 1, "py::kw_only may be specified only once");
static_assert(constexpr_sum(is_pos_only<Extra>::value...) <= 1, "py::pos_only may be specified only once");
static_assert(has_arg_annotations || !has_kw_only_args,
"py::kw_only requires the use of argument annotations");
static_assert(has_arg_annotations || !has_pos_only_args,
"py::pos_only requires the use of argument annotations (for docstrings "
"and aligning the annotations to the argument)");
static_assert(constexpr_sum(is_kw_only<Extra>::value...) <= 1,
"py::kw_only may be specified only once");
static_assert(constexpr_sum(is_pos_only<Extra>::value...) <= 1,
"py::pos_only may be specified only once");
constexpr auto kw_only_pos = constexpr_first<is_kw_only, Extra...>();
constexpr auto pos_only_pos = constexpr_first<is_pos_only, Extra...>();
static_assert(!(has_kw_only_args && has_pos_only_args) || pos_only_pos < kw_only_pos, "py::pos_only must come before py::kw_only");
static_assert(!(has_kw_only_args && has_pos_only_args) || pos_only_pos < kw_only_pos,
"py::pos_only must come before py::kw_only");
}
/* Generate a readable signature describing the function's arguments and return
value types */
static constexpr auto signature = const_name("(") + cast_in::arg_names + const_name(") -> ") + cast_out::name;
static constexpr auto signature
= const_name("(") + cast_in::arg_names + const_name(") -> ") + cast_out::name;
PYBIND11_DESCR_CONSTEXPR auto types = decltype(signature)::types();
/* Register the function with Python from generic (non-templated) code */
......@@ -275,17 +298,18 @@ protected:
/* Stash some additional information used by an important optimization in 'functional.h' */
using FunctionType = Return (*)(Args...);
constexpr bool is_function_ptr =
std::is_convertible<Func, FunctionType>::value &&
sizeof(capture) == sizeof(void *);
constexpr bool is_function_ptr
= std::is_convertible<Func, FunctionType>::value && sizeof(capture) == sizeof(void *);
if (is_function_ptr) {
rec->is_stateless = true;
rec->data[1] = const_cast<void *>(reinterpret_cast<const void *>(&typeid(FunctionType)));
rec->data[1]
= const_cast<void *>(reinterpret_cast<const void *>(&typeid(FunctionType)));
}
}
// Utility class that keeps track of all duplicated strings, and cleans them up in its destructor,
// unless they are released. Basically a RAII-solution to deal with exceptions along the way.
// Utility class that keeps track of all duplicated strings, and cleans them up in its
// destructor, unless they are released. Basically a RAII-solution to deal with exceptions
// along the way.
class strdup_guard {
public:
~strdup_guard() {
......@@ -298,26 +322,29 @@ protected:
strings.push_back(t);
return t;
}
void release() {
strings.clear();
}
void release() { strings.clear(); }
private:
std::vector<char *> strings;
};
/// Register a function call with Python (generic non-templated code goes here)
void initialize_generic(unique_function_record &&unique_rec, const char *text,
const std::type_info *const *types, size_t args) {
void initialize_generic(unique_function_record &&unique_rec,
const char *text,
const std::type_info *const *types,
size_t args) {
// Do NOT receive `unique_rec` by value. If this function fails to move out the unique_ptr,
// we do not want this to destuct the pointer. `initialize` (the caller) still relies on the
// pointee being alive after this call. Only move out if a `capsule` is going to keep it alive.
// we do not want this to destuct the pointer. `initialize` (the caller) still relies on
// the pointee being alive after this call. Only move out if a `capsule` is going to keep
// it alive.
auto *rec = unique_rec.get();
// Keep track of strdup'ed strings, and clean them up as long as the function's capsule
// has not taken ownership yet (when `unique_rec.release()` is called).
// Note: This cannot easily be fixed by a `unique_ptr` with custom deleter, because the strings
// are only referenced before strdup'ing. So only *after* the following block could `destruct`
// safely be called, but even then, `repr` could still throw in the middle of copying all strings.
// Note: This cannot easily be fixed by a `unique_ptr` with custom deleter, because the
// strings are only referenced before strdup'ing. So only *after* the following block could
// `destruct` safely be called, but even then, `repr` could still throw in the middle of
// copying all strings.
strdup_guard guarded_strdup;
/* Create copies of all referenced C-style strings */
......@@ -325,7 +352,7 @@ protected:
if (rec->doc) {
rec->doc = guarded_strdup(rec->doc);
}
for (auto &a: rec->args) {
for (auto &a : rec->args) {
if (a.name) {
a.name = guarded_strdup(a.name);
}
......@@ -341,15 +368,19 @@ protected:
#if !defined(NDEBUG) && !defined(PYBIND11_DISABLE_NEW_STYLE_INIT_WARNING)
if (rec->is_constructor && !rec->is_new_style_constructor) {
const auto class_name = detail::get_fully_qualified_tp_name((PyTypeObject *) rec->scope.ptr());
const auto class_name
= detail::get_fully_qualified_tp_name((PyTypeObject *) rec->scope.ptr());
const auto func_name = std::string(rec->name);
PyErr_WarnEx(
PyExc_FutureWarning,
("pybind11-bound class '" + class_name + "' is using an old-style "
"placement-new '" + func_name + "' which has been deprecated. See "
"the upgrade guide in pybind11's docs. This message is only visible "
"when compiled in debug mode.").c_str(), 0
);
PyErr_WarnEx(PyExc_FutureWarning,
("pybind11-bound class '" + class_name
+ "' is using an old-style "
"placement-new '"
+ func_name
+ "' which has been deprecated. See "
"the upgrade guide in pybind11's docs. This message is only visible "
"when compiled in debug mode.")
.c_str(),
0);
}
#endif
......@@ -400,16 +431,14 @@ protected:
}
if (auto *tinfo = detail::get_type_info(*t)) {
handle th((PyObject *) tinfo->type);
signature +=
th.attr("__module__").cast<std::string>() + "." +
// Python 3.3+, but we backport it to earlier versions
th.attr("__qualname__").cast<std::string>();
signature += th.attr("__module__").cast<std::string>() + "." +
// Python 3.3+, but we backport it to earlier versions
th.attr("__qualname__").cast<std::string>();
} else if (rec->is_new_style_constructor && arg_index == 0) {
// A new-style `__init__` takes `self` as `value_and_holder`.
// Rewrite it to the proper class type.
signature +=
rec->scope.attr("__module__").cast<std::string>() + "." +
rec->scope.attr("__qualname__").cast<std::string>();
signature += rec->scope.attr("__module__").cast<std::string>() + "."
+ rec->scope.attr("__qualname__").cast<std::string>();
} else {
std::string tname(t->name());
detail::clean_type_id(tname);
......@@ -445,7 +474,8 @@ protected:
if (rec->sibling) {
if (PyCFunction_Check(rec->sibling.ptr())) {
auto *self = PyCFunction_GET_SELF(rec->sibling.ptr());
capsule rec_capsule = isinstance<capsule>(self) ? reinterpret_borrow<capsule>(self) : capsule(self);
capsule rec_capsule = isinstance<capsule>(self) ? reinterpret_borrow<capsule>(self)
: capsule(self);
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 */
......@@ -470,9 +500,8 @@ protected:
= reinterpret_cast<PyCFunction>(reinterpret_cast<void (*)()>(dispatcher));
rec->def->ml_flags = METH_VARARGS | METH_KEYWORDS;
capsule rec_capsule(unique_rec.release(), [](void *ptr) {
destruct((detail::function_record *) ptr);
});
capsule rec_capsule(unique_rec.release(),
[](void *ptr) { destruct((detail::function_record *) ptr); });
guarded_strdup.release();
object scope_module;
......@@ -497,12 +526,12 @@ protected:
"overloading a method with both static and instance methods is not supported; "
#if defined(NDEBUG)
"compile in debug mode for more details"
#else
#else
"error while attempting to bind "
+ std::string(rec->is_method ? "instance" : "static") + " method "
+ std::string(pybind11::str(rec->scope.attr("__name__"))) + "."
+ std::string(rec->name) + signature
#endif
#endif
);
}
......@@ -512,7 +541,8 @@ protected:
// chain.
chain_start = rec;
rec->next = chain;
auto rec_capsule = reinterpret_borrow<capsule>(((PyCFunctionObject *) m_ptr)->m_self);
auto rec_capsule
= reinterpret_borrow<capsule>(((PyCFunctionObject *) m_ptr)->m_self);
rec_capsule.set_pointer(unique_rec.release());
guarded_strdup.release();
} else {
......@@ -551,8 +581,8 @@ protected:
signatures += "\n";
}
if (it->doc && it->doc[0] != '\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 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;
......@@ -589,11 +619,11 @@ protected:
/// When a cpp_function is GCed, release any memory allocated by pybind11
static void destruct(detail::function_record *rec, bool free_strings = true) {
// If on Python 3.9, check the interpreter "MICRO" (patch) version.
// If this is running on 3.9.0, we have to work around a bug.
#if !defined(PYPY_VERSION) && PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION == 9
static bool is_zero = Py_GetVersion()[4] == '0';
#endif
// If on Python 3.9, check the interpreter "MICRO" (patch) version.
// If this is running on 3.9.0, we have to work around a bug.
#if !defined(PYPY_VERSION) && PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION == 9
static bool is_zero = Py_GetVersion()[4] == '0';
#endif
while (rec) {
detail::function_record *next = rec->next;
......@@ -607,7 +637,7 @@ protected:
std::free((char *) rec->name);
std::free((char *) rec->doc);
std::free((char *) rec->signature);
for (auto &arg: rec->args) {
for (auto &arg : rec->args) {
std::free(const_cast<char *>(arg.name));
std::free(const_cast<char *>(arg.descr));
}
......@@ -617,23 +647,22 @@ protected:
}
if (rec->def) {
std::free(const_cast<char *>(rec->def->ml_doc));
// Python 3.9.0 decref's these in the wrong order; rec->def
// If loaded on 3.9.0, let these leak (use Python 3.9.1 at runtime to fix)
// See https://github.com/python/cpython/pull/22670
#if !defined(PYPY_VERSION) && PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION == 9
// Python 3.9.0 decref's these in the wrong order; rec->def
// If loaded on 3.9.0, let these leak (use Python 3.9.1 at runtime to fix)
// See https://github.com/python/cpython/pull/22670
#if !defined(PYPY_VERSION) && PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION == 9
if (!is_zero) {
delete rec->def;
}
#else
delete rec->def;
#endif
delete rec->def;
#endif
}
delete rec;
rec = next;
}
}
/// Main dispatch logic for calls to functions bound using pybind11
static PyObject *dispatcher(PyObject *self, PyObject *args_in, PyObject *kwargs_in) {
using namespace detail;
......@@ -651,8 +680,11 @@ protected:
auto self_value_and_holder = value_and_holder();
if (overloads->is_constructor) {
if (!parent || !PyObject_TypeCheck(parent.ptr(), (PyTypeObject *) overloads->scope.ptr())) {
PyErr_SetString(PyExc_TypeError, "__init__(self, ...) called with invalid or missing `self` argument");
if (!parent
|| !PyObject_TypeCheck(parent.ptr(), (PyTypeObject *) overloads->scope.ptr())) {
PyErr_SetString(
PyExc_TypeError,
"__init__(self, ...) called with invalid or missing `self` argument");
return nullptr;
}
......@@ -683,23 +715,23 @@ protected:
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
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.
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.
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.
*/
const function_record &func = *it;
size_t num_args = func.nargs; // Number of positional arguments that we need
size_t num_args = func.nargs; // Number of positional arguments that we need
if (func.has_args) {
--num_args; // (but don't count py::args
}
......@@ -740,8 +772,10 @@ protected:
// 1. Copy any position arguments given.
bool bad_arg = false;
for (; args_copied < args_to_copy; ++args_copied) {
const argument_record *arg_rec = args_copied < func.args.size() ? &func.args[args_copied] : nullptr;
if (kwargs_in && arg_rec && arg_rec->name && dict_getitemstring(kwargs_in, arg_rec->name)) {
const argument_record *arg_rec
= args_copied < func.args.size() ? &func.args[args_copied] : nullptr;
if (kwargs_in && arg_rec && arg_rec->name
&& dict_getitemstring(kwargs_in, arg_rec->name)) {
bad_arg = true;
break;
}
......@@ -817,7 +851,8 @@ protected:
}
if (value) {
// If we're at the py::args index then first insert a stub for it to be replaced later
// If we're at the py::args index then first insert a stub for it to be
// replaced later
if (func.has_args && call.args.size() == func.nargs_pos) {
call.args.push_back(none());
}
......@@ -875,11 +910,12 @@ protected:
call.kwargs_ref = std::move(kwargs);
}
// 5. Put everything in a vector. Not technically step 5, we've been building it
// in `call.args` all along.
#if !defined(NDEBUG)
// 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!");
pybind11_fail("Internal error: function call dispatcher inserted wrong number "
"of arguments!");
}
#endif
......@@ -921,7 +957,8 @@ protected:
}
if (overloaded && !second_pass.empty() && result.ptr() == PYBIND11_TRY_NEXT_OVERLOAD) {
// The no-conversion pass finished without success, try again with conversion allowed
// The no-conversion pass finished without success, try again with conversion
// allowed
for (auto &call : second_pass) {
try {
loader_life_support guard{};
......@@ -944,7 +981,7 @@ protected:
e.restore();
return nullptr;
#ifdef __GLIBCXX__
} catch ( abi::__forced_unwind& ) {
} catch (abi::__forced_unwind &) {
throw;
#endif
} catch (...) {
......@@ -964,7 +1001,8 @@ protected:
- delegate translation to the next translator by throwing a new type of exception.
*/
auto &local_exception_translators = get_local_internals().registered_exception_translators;
auto &local_exception_translators
= get_local_internals().registered_exception_translators;
if (detail::apply_exception_translators(local_exception_translators)) {
return nullptr;
}
......@@ -973,7 +1011,8 @@ protected:
return nullptr;
}
PyErr_SetString(PyExc_SystemError, "Exception escaped from default exception translator!");
PyErr_SetString(PyExc_SystemError,
"Exception escaped from default exception translator!");
return nullptr;
}
......@@ -992,17 +1031,18 @@ protected:
return handle(Py_NotImplemented).inc_ref().ptr();
}
std::string msg = std::string(overloads->name) + "(): incompatible " +
std::string(overloads->is_constructor ? "constructor" : "function") +
" arguments. The following argument types are supported:\n";
std::string msg = std::string(overloads->name) + "(): incompatible "
+ std::string(overloads->is_constructor ? "constructor" : "function")
+ " arguments. The following argument types are supported:\n";
int ctr = 0;
for (const function_record *it2 = overloads; it2 != nullptr; it2 = it2->next) {
msg += " "+ std::to_string(++ctr) + ". ";
msg += " " + std::to_string(++ctr) + ". ";
bool wrote_sig = false;
if (overloads->is_constructor) {
// For a constructor, rewrite `(self: Object, arg0, ...) -> NoneType` as `Object(arg0, ...)`
// For a constructor, rewrite `(self: Object, arg0, ...) -> NoneType` as
// `Object(arg0, ...)`
std::string sig = it2->signature;
size_t start = sig.find('(') + 7; // skip "(self: "
if (start < sig.size()) {
......@@ -1038,7 +1078,7 @@ protected:
}
try {
msg += pybind11::repr(args_[ti]);
} catch (const error_already_set&) {
} catch (const error_already_set &) {
msg += "<repr raised Error>";
}
}
......@@ -1059,7 +1099,7 @@ protected:
msg += pybind11::str("{}=").format(kwarg.first);
try {
msg += pybind11::repr(kwarg.second);
} catch (const error_already_set&) {
} catch (const error_already_set &) {
msg += "<repr raised Error>";
}
}
......@@ -1101,7 +1141,6 @@ protected:
}
};
/// Wrapper for Python extension modules
class module_ : public object {
public:
......@@ -1123,11 +1162,15 @@ public:
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),
sibling(getattr(*this, name_, none())), extra...);
module_ &def(const char *name_, Func &&f, const Extra &...extra) {
cpp_function func(std::forward<Func>(f),
name(name_),
scope(*this),
sibling(getattr(*this, name_, none())),
extra...);
// NB: allow overwriting here because cpp_function sets up a chain with the intention of
// overwriting (and has already checked internally that it isn't overwriting non-functions).
// overwriting (and has already checked internally that it isn't overwriting
// non-functions).
add_object(name_, func, true /* overwrite */);
return *this;
}
......@@ -1143,8 +1186,8 @@ public:
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);
std::string full_name
= std::string(PyModule_GetName(m_ptr)) + std::string(".") + std::string(name);
auto result = reinterpret_borrow<module_>(PyImport_AddModule(full_name.c_str()));
if (doc && options::show_user_defined_docstrings()) {
result.attr("__doc__") = pybind11::str(doc);
......@@ -1204,22 +1247,22 @@ public:
#if PY_MAJOR_VERSION >= 3
// module_def is PyModuleDef
// Placement new (not an allocation).
def = new (def) PyModuleDef {
/* m_base */ PyModuleDef_HEAD_INIT,
/* m_name */ name,
/* m_doc */ options::show_user_defined_docstrings() ? doc : nullptr,
/* m_size */ -1,
/* m_methods */ nullptr,
/* m_slots */ nullptr,
/* m_traverse */ nullptr,
/* m_clear */ nullptr,
/* m_free */ nullptr
};
def = new (def)
PyModuleDef{/* m_base */ PyModuleDef_HEAD_INIT,
/* m_name */ name,
/* m_doc */ options::show_user_defined_docstrings() ? doc : nullptr,
/* m_size */ -1,
/* m_methods */ nullptr,
/* m_slots */ nullptr,
/* m_traverse */ nullptr,
/* m_clear */ nullptr,
/* m_free */ nullptr};
auto *m = PyModule_Create(def);
#else
// Ignore module_def *def; only necessary for Python 3
(void) def;
auto m = Py_InitModule3(name, nullptr, options::show_user_defined_docstrings() ? doc : nullptr);
auto m = Py_InitModule3(
name, nullptr, options::show_user_defined_docstrings() ? doc : nullptr);
#endif
if (m == nullptr) {
if (PyErr_Occurred()) {
......@@ -1227,7 +1270,8 @@ public:
}
pybind11_fail("Internal error in module_::create_extension_module()");
}
// TODO: Should be reinterpret_steal for Python 3, but Python also steals it again when returned from PyInit_...
// TODO: Should be reinterpret_steal for Python 3, but Python also steals it again when
// returned from PyInit_...
// For Python 2, reinterpret_borrow is correct.
return reinterpret_borrow<module_>(m);
}
......@@ -1247,10 +1291,10 @@ inline dict globals() {
}
#if PY_VERSION_HEX >= 0x03030000
template <typename... Args,
typename = detail::enable_if_t<args_are_all_keyword_or_ds<Args...>()>>
PYBIND11_DEPRECATED("make_simple_namespace should be replaced with py::module_::import(\"types\").attr(\"SimpleNamespace\") ")
object make_simple_namespace(Args&&... args_) {
template <typename... Args, typename = detail::enable_if_t<args_are_all_keyword_or_ds<Args...>()>>
PYBIND11_DEPRECATED("make_simple_namespace should be replaced with "
"py::module_::import(\"types\").attr(\"SimpleNamespace\") ")
object make_simple_namespace(Args &&...args_) {
return module_::import("types").attr("SimpleNamespace")(std::forward<Args>(args_)...);
}
#endif
......@@ -1299,13 +1343,12 @@ protected:
} else {
internals.registered_types_cpp[tindex] = tinfo;
}
internals.registered_types_py[(PyTypeObject *) m_ptr] = { tinfo };
internals.registered_types_py[(PyTypeObject *) m_ptr] = {tinfo};
if (rec.bases.size() > 1 || rec.multiple_inheritance) {
mark_parents_nonsimple(tinfo->type);
tinfo->simple_ancestors = false;
}
else if (rec.bases.size() == 1) {
} else if (rec.bases.size() == 1) {
auto *parent_tinfo = get_type_info((PyTypeObject *) rec.bases[0].ptr());
assert(parent_tinfo != nullptr);
bool parent_simple_ancestors = parent_tinfo->simple_ancestors;
......@@ -1333,10 +1376,9 @@ protected:
}
}
void install_buffer_funcs(
buffer_info *(*get_buffer)(PyObject *, void *),
void *get_buffer_data) {
auto *type = (PyHeapTypeObject*) m_ptr;
void install_buffer_funcs(buffer_info *(*get_buffer)(PyObject *, void *),
void *get_buffer_data) {
auto *type = (PyHeapTypeObject *) m_ptr;
auto *tinfo = detail::get_type_info(&type->ht_type);
if (!type->ht_type.tp_as_buffer) {
......@@ -1352,58 +1394,76 @@ protected:
// rec_func must be set for either fget or fset.
void def_property_static_impl(const char *name,
handle fget, handle fset,
handle fget,
handle fset,
detail::function_record *rec_func) {
const auto is_static = (rec_func != nullptr) && !(rec_func->is_method && rec_func->scope);
const auto has_doc = (rec_func != nullptr) && (rec_func->doc != nullptr)
&& pybind11::options::show_user_defined_docstrings();
auto property = handle((PyObject *) (is_static ? get_internals().static_property_type
: &PyProperty_Type));
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(),
/*deleter*/ none(),
pybind11::str(has_doc ? rec_func->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(...) { }
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 T, typename SFINAE = void> struct has_operator_delete : std::false_type { };
template <typename T> struct has_operator_delete<T, void_t<decltype(static_cast<void (*)(void *)>(T::operator delete))>>
: std::true_type { };
template <typename T, typename SFINAE = void> struct has_operator_delete_size : std::false_type { };
template <typename T> struct has_operator_delete_size<T, void_t<decltype(static_cast<void (*)(void *, size_t)>(T::operator delete))>>
: std::true_type { };
template <typename>
void set_operator_new(...) {}
template <typename T, typename SFINAE = void>
struct has_operator_delete : std::false_type {};
template <typename T>
struct has_operator_delete<T, void_t<decltype(static_cast<void (*)(void *)>(T::operator delete))>>
: std::true_type {};
template <typename T, typename SFINAE = void>
struct has_operator_delete_size : std::false_type {};
template <typename T>
struct has_operator_delete_size<
T,
void_t<decltype(static_cast<void (*)(void *, size_t)>(T::operator delete))>> : std::true_type {
};
/// Call class-specific delete if it exists or global otherwise. Can also be an overload set.
template <typename T, enable_if_t<has_operator_delete<T>::value, int> = 0>
void call_operator_delete(T *p, size_t, size_t) { T::operator delete(p); }
template <typename T, enable_if_t<!has_operator_delete<T>::value && has_operator_delete_size<T>::value, int> = 0>
void call_operator_delete(T *p, size_t s, size_t) { T::operator delete(p, s); }
void call_operator_delete(T *p, size_t, size_t) {
T::operator delete(p);
}
template <
typename T,
enable_if_t<!has_operator_delete<T>::value && has_operator_delete_size<T>::value, int> = 0>
void call_operator_delete(T *p, size_t s, size_t) {
T::operator delete(p, s);
}
inline void call_operator_delete(void *p, size_t s, size_t a) {
(void)s; (void)a;
#if defined(__cpp_aligned_new) && (!defined(_MSC_VER) || _MSC_VER >= 1912)
if (a > __STDCPP_DEFAULT_NEW_ALIGNMENT__) {
#ifdef __cpp_sized_deallocation
::operator delete(p, s, std::align_val_t(a));
#else
::operator delete(p, std::align_val_t(a));
#endif
return;
}
#endif
#ifdef __cpp_sized_deallocation
::operator delete(p, s);
#else
::operator delete(p);
#endif
(void) s;
(void) a;
#if defined(__cpp_aligned_new) && (!defined(_MSC_VER) || _MSC_VER >= 1912)
if (a > __STDCPP_DEFAULT_NEW_ALIGNMENT__) {
# ifdef __cpp_sized_deallocation
::operator delete(p, s, std::align_val_t(a));
# else
::operator delete(p, std::align_val_t(a));
# endif
return;
}
#endif
#ifdef __cpp_sized_deallocation
::operator delete(p, s);
#else
::operator delete(p);
#endif
}
inline void add_class_method(object& cls, const char *name_, const cpp_function &cf) {
inline void add_class_method(object &cls, const char *name_, const cpp_function &cf) {
cls.attr(cf.name()) = cf;
if (std::strcmp(name_, "__eq__") == 0 && !cls.attr("__dict__").contains("__hash__")) {
cls.attr("__hash__") = none();
......@@ -1415,30 +1475,37 @@ PYBIND11_NAMESPACE_END(detail)
/// Given a pointer to a member function, cast it to its `Derived` version.
/// Forward everything else unchanged.
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>
auto method_adaptor(Return (Class::*pmf)(Args...)) -> Return (Derived::*)(Args...) {
static_assert(detail::is_accessible_base_of<Class, Derived>::value,
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>
auto method_adaptor(Return (Class::*pmf)(Args...) const) -> Return (Derived::*)(Args...) const {
static_assert(detail::is_accessible_base_of<Class, Derived>::value,
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>
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::is_strict_base_of<type_, T>;
template <typename T> using is_base = detail::is_strict_base_of<T, type_>;
template <typename T>
using is_holder = detail::is_holder_type<type_, T>;
template <typename T>
using is_subtype = detail::is_strict_base_of<type_, T>;
template <typename T>
using is_base = detail::is_strict_base_of<T, type_>;
// 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>> {};
template <typename T>
struct is_valid_class_option : detail::any_of<is_holder<T>, is_subtype<T>, is_base<T>> {};
public:
using type = type_;
......@@ -1447,24 +1514,24 @@ public:
using holder_type = detail::exactly_one_t<is_holder, std::unique_ptr<type>, options...>;
static_assert(detail::all_of<is_valid_class_option<options>...>::value,
"Unknown/invalid class_ template parameters provided");
"Unknown/invalid class_ template parameters provided");
static_assert(!has_alias || std::is_polymorphic<type>::value,
"Cannot use an alias class with a non-polymorphic type");
"Cannot use an alias class with a non-polymorphic type");
PYBIND11_OBJECT(class_, generic_type, PyType_Check)
template <typename... Extra>
class_(handle scope, const char *name, const Extra &... extra) {
class_(handle scope, const char *name, const Extra &...extra) {
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
// no multiple_inheritance attr
none_of<std::is_same<multiple_inheritance, Extra>...>::value),
(constexpr_sum(is_pyobject<Extra>::value...) == 1 && // Exactly one base
constexpr_sum(is_base<options>::value...) == 0 && // no template option bases
// no multiple_inheritance attr
none_of<std::is_same<multiple_inheritance, Extra>...>::value),
"Error: multiple inheritance bases must be specified via class_ template options");
type_record record;
......@@ -1472,7 +1539,7 @@ public:
record.name = name;
record.type = &typeid(type);
record.type_size = sizeof(conditional_t<has_alias, type_alias, type>);
record.type_align = alignof(conditional_t<has_alias, type_alias, type>&);
record.type_align = alignof(conditional_t<has_alias, type_alias, type> &);
record.holder_size = sizeof(holder_type);
record.init_instance = init_instance;
record.dealloc = dealloc;
......@@ -1489,8 +1556,10 @@ public:
generic_type::initialize(record);
if (has_alias) {
auto &instances = record.module_local ? get_local_internals().registered_types_cpp : get_internals().registered_types_cpp;
instances[std::type_index(typeid(type_alias))] = instances[std::type_index(typeid(type))];
auto &instances = record.module_local ? get_local_internals().registered_types_cpp
: get_internals().registered_types_cpp;
instances[std::type_index(typeid(type_alias))]
= instances[std::type_index(typeid(type))];
}
}
......@@ -1502,54 +1571,60 @@ public:
}
template <typename Base, detail::enable_if_t<!is_base<Base>::value, int> = 0>
static void add_base(detail::type_record &) { }
static void add_base(detail::type_record &) {}
template <typename Func, typename... Extra>
class_ &def(const char *name_, Func&& f, const Extra&... extra) {
cpp_function cf(method_adaptor<type>(std::forward<Func>(f)), name(name_), is_method(*this),
sibling(getattr(*this, name_, none())), extra...);
class_ &def(const char *name_, Func &&f, const Extra &...extra) {
cpp_function cf(method_adaptor<type>(std::forward<Func>(f)),
name(name_),
is_method(*this),
sibling(getattr(*this, name_, none())),
extra...);
add_class_method(*this, name_, cf);
return *this;
}
template <typename Func, typename... Extra> class_ &
def_static(const char *name_, Func &&f, const Extra&... extra) {
template <typename Func, typename... Extra>
class_ &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...);
"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()) = staticmethod(cf);
return *this;
}
template <detail::op_id id, detail::op_type ot, typename L, typename R, typename... Extra>
class_ &def(const detail::op_<id, ot, L, R> &op, const Extra&... extra) {
class_ &def(const detail::op_<id, ot, L, R> &op, const Extra &...extra) {
op.execute(*this, extra...);
return *this;
}
template <detail::op_id id, detail::op_type ot, typename L, typename R, typename... Extra>
class_ & def_cast(const detail::op_<id, ot, L, R> &op, const Extra&... extra) {
class_ &def_cast(const detail::op_<id, ot, L, R> &op, const Extra &...extra) {
op.execute_cast(*this, extra...);
return *this;
}
template <typename... Args, typename... Extra>
class_ &def(const detail::initimpl::constructor<Args...> &init, const Extra&... extra) {
class_ &def(const detail::initimpl::constructor<Args...> &init, const Extra &...extra) {
PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(init);
init.execute(*this, extra...);
return *this;
}
template <typename... Args, typename... Extra>
class_ &def(const detail::initimpl::alias_constructor<Args...> &init, const Extra&... extra) {
class_ &def(const detail::initimpl::alias_constructor<Args...> &init, const Extra &...extra) {
PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(init);
init.execute(*this, extra...);
return *this;
}
template <typename... Args, typename... Extra>
class_ &def(detail::initimpl::factory<Args...> &&init, const Extra&... extra) {
class_ &def(detail::initimpl::factory<Args...> &&init, const Extra &...extra) {
std::move(init).execute(*this, extra...);
return *this;
}
......@@ -1561,52 +1636,59 @@ public:
}
template <typename Func>
class_& def_buffer(Func &&func) {
struct capture { Func func; };
auto *ptr = new capture { std::forward<Func>(func) };
install_buffer_funcs([](PyObject *obj, void *ptr) -> buffer_info* {
detail::make_caster<type> caster;
if (!caster.load(obj, false)) {
return nullptr;
}
return new buffer_info(((capture *) ptr)->func(caster));
}, ptr);
class_ &def_buffer(Func &&func) {
struct capture {
Func func;
};
auto *ptr = new capture{std::forward<Func>(func)};
install_buffer_funcs(
[](PyObject *obj, void *ptr) -> buffer_info * {
detail::make_caster<type> caster;
if (!caster.load(obj, false)) {
return nullptr;
}
return new buffer_info(((capture *) ptr)->func(caster));
},
ptr);
weakref(m_ptr, cpp_function([ptr](handle wr) {
delete ptr;
wr.dec_ref();
})).release();
delete ptr;
wr.dec_ref();
}))
.release();
return *this;
}
template <typename Return, typename Class, typename... Args>
class_ &def_buffer(Return (Class::*func)(Args...)) {
return def_buffer([func] (type &obj) { return (obj.*func)(); });
return def_buffer([func](type &obj) { return (obj.*func)(); });
}
template <typename Return, typename Class, typename... Args>
class_ &def_buffer(Return (Class::*func)(Args...) const) {
return def_buffer([func] (const type &obj) { return (obj.*func)(); });
return def_buffer([func](const type &obj) { return (obj.*func)(); });
}
template <typename C, typename D, typename... Extra>
class_ &def_readwrite(const char *name, D C::*pm, const Extra&... extra) {
static_assert(std::is_same<C, type>::value || std::is_base_of<C, type>::value, "def_readwrite() requires a class member (or base class member)");
cpp_function fget([pm](const type &c) -> const D &{ return c.*pm; }, is_method(*this)),
fset([pm](type &c, const D &value) { c.*pm = value; }, is_method(*this));
class_ &def_readwrite(const char *name, D C::*pm, const Extra &...extra) {
static_assert(std::is_same<C, type>::value || std::is_base_of<C, type>::value,
"def_readwrite() requires a class member (or base class member)");
cpp_function fget([pm](const type &c) -> const D & { return c.*pm; }, is_method(*this)),
fset([pm](type &c, const D &value) { c.*pm = value; }, is_method(*this));
def_property(name, fget, fset, return_value_policy::reference_internal, extra...);
return *this;
}
template <typename C, typename D, typename... Extra>
class_ &def_readonly(const char *name, const D C::*pm, const Extra& ...extra) {
static_assert(std::is_same<C, type>::value || std::is_base_of<C, type>::value, "def_readonly() requires a class member (or base class member)");
cpp_function fget([pm](const type &c) -> const D &{ return c.*pm; }, is_method(*this));
class_ &def_readonly(const char *name, const D C::*pm, const Extra &...extra) {
static_assert(std::is_same<C, type>::value || std::is_base_of<C, type>::value,
"def_readonly() requires a class member (or base class member)");
cpp_function fget([pm](const type &c) -> const D & { return c.*pm; }, is_method(*this));
def_property_readonly(name, fget, return_value_policy::reference_internal, extra...);
return *this;
}
template <typename D, typename... Extra>
class_ &def_readwrite_static(const char *name, D *pm, const Extra& ...extra) {
class_ &def_readwrite_static(const char *name, D *pm, const Extra &...extra) {
cpp_function fget([pm](const object &) -> const D & { return *pm; }, scope(*this)),
fset([pm](const object &, const D &value) { *pm = value; }, scope(*this));
def_property_static(name, fget, fset, return_value_policy::reference, extra...);
......@@ -1614,7 +1696,7 @@ public:
}
template <typename D, typename... Extra>
class_ &def_readonly_static(const char *name, const D *pm, const Extra& ...extra) {
class_ &def_readonly_static(const char *name, const D *pm, const Extra &...extra) {
cpp_function fget([pm](const object &) -> const D & { return *pm; }, scope(*this));
def_property_readonly_static(name, fget, return_value_policy::reference, extra...);
return *this;
......@@ -1622,66 +1704,91 @@ public:
/// Uses return_value_policy::reference_internal by default
template <typename Getter, typename... Extra>
class_ &def_property_readonly(const char *name, const Getter &fget, const Extra& ...extra) {
return def_property_readonly(name, cpp_function(method_adaptor<type>(fget)),
return_value_policy::reference_internal, extra...);
class_ &def_property_readonly(const char *name, const Getter &fget, const Extra &...extra) {
return def_property_readonly(name,
cpp_function(method_adaptor<type>(fget)),
return_value_policy::reference_internal,
extra...);
}
/// Uses cpp_function's return_value_policy by default
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...);
}
/// Uses return_value_policy::reference by default
template <typename Getter, typename... Extra>
class_ &def_property_readonly_static(const char *name, const Getter &fget, const Extra& ...extra) {
return def_property_readonly_static(name, cpp_function(fget), return_value_policy::reference, extra...);
class_ &
def_property_readonly_static(const char *name, const Getter &fget, const Extra &...extra) {
return def_property_readonly_static(
name, cpp_function(fget), return_value_policy::reference, extra...);
}
/// Uses cpp_function's return_value_policy by default
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...);
}
/// Uses return_value_policy::reference_internal by default
template <typename Getter, typename Setter, typename... Extra>
class_ &def_property(const char *name, const Getter &fget, const Setter &fset, const Extra& ...extra) {
class_ &
def_property(const char *name, const Getter &fget, const Setter &fset, const Extra &...extra) {
return def_property(name, fget, cpp_function(method_adaptor<type>(fset)), extra...);
}
template <typename Getter, typename... Extra>
class_ &def_property(const char *name, const Getter &fget, const cpp_function &fset, const Extra& ...extra) {
return def_property(name, cpp_function(method_adaptor<type>(fget)), fset,
return_value_policy::reference_internal, extra...);
class_ &def_property(const char *name,
const Getter &fget,
const cpp_function &fset,
const Extra &...extra) {
return def_property(name,
cpp_function(method_adaptor<type>(fget)),
fset,
return_value_policy::reference_internal,
extra...);
}
/// Uses cpp_function's return_value_policy by default
template <typename... Extra>
class_ &def_property(const char *name, const cpp_function &fget, const cpp_function &fset, const Extra& ...extra) {
class_ &def_property(const char *name,
const cpp_function &fget,
const cpp_function &fset,
const Extra &...extra) {
return def_property_static(name, fget, fset, is_method(*this), extra...);
}
/// Uses return_value_policy::reference by default
template <typename Getter, typename... Extra>
class_ &def_property_static(const char *name, const Getter &fget, const cpp_function &fset, const Extra& ...extra) {
return def_property_static(name, cpp_function(fget), fset, return_value_policy::reference, extra...);
class_ &def_property_static(const char *name,
const Getter &fget,
const cpp_function &fset,
const Extra &...extra) {
return def_property_static(
name, cpp_function(fget), fset, return_value_policy::reference, extra...);
}
/// Uses cpp_function's return_value_policy by default
template <typename... Extra>
class_ &def_property_static(const char *name, const cpp_function &fget, const cpp_function &fset, const Extra& ...extra) {
static_assert( 0 == detail::constexpr_sum(std::is_base_of<arg, Extra>::value...),
class_ &def_property_static(const char *name,
const cpp_function &fget,
const cpp_function &fset,
const Extra &...extra) {
static_assert(0 == detail::constexpr_sum(std::is_base_of<arg, Extra>::value...),
"Argument annotations are not allowed for properties");
auto rec_fget = get_function_record(fget), rec_fset = get_function_record(fset);
auto *rec_active = rec_fget;
if (rec_fget) {
char *doc_prev = rec_fget->doc; /* 'extra' field may include a property-specific documentation string */
detail::process_attributes<Extra...>::init(extra..., rec_fget);
if (rec_fget->doc && rec_fget->doc != doc_prev) {
std::free(doc_prev);
rec_fget->doc = PYBIND11_COMPAT_STRDUP(rec_fget->doc);
}
char *doc_prev = rec_fget->doc; /* 'extra' field may include a property-specific
documentation string */
detail::process_attributes<Extra...>::init(extra..., rec_fget);
if (rec_fget->doc && rec_fget->doc != doc_prev) {
std::free(doc_prev);
rec_fget->doc = PYBIND11_COMPAT_STRDUP(rec_fget->doc);
}
}
if (rec_fset) {
char *doc_prev = rec_fset->doc;
......@@ -1701,11 +1808,13 @@ public:
private:
/// Initialize holder object, variant 1: object derives from enable_shared_from_this
template <typename T>
static void init_holder(detail::instance *inst, detail::value_and_holder &v_h,
const holder_type * /* unused */, const std::enable_shared_from_this<T> * /* dummy */) {
static void init_holder(detail::instance *inst,
detail::value_and_holder &v_h,
const holder_type * /* unused */,
const std::enable_shared_from_this<T> * /* dummy */) {
auto sh = std::dynamic_pointer_cast<typename holder_type::element_type>(
detail::try_get_shared_from_this(v_h.value_ptr<type>()));
detail::try_get_shared_from_this(v_h.value_ptr<type>()));
if (sh) {
new (std::addressof(v_h.holder<holder_type>())) holder_type(std::move(sh));
v_h.set_holder_constructed();
......@@ -1718,18 +1827,25 @@ private:
}
static void init_holder_from_existing(const detail::value_and_holder &v_h,
const holder_type *holder_ptr, std::true_type /*is_copy_constructible*/) {
new (std::addressof(v_h.holder<holder_type>())) holder_type(*reinterpret_cast<const holder_type *>(holder_ptr));
const holder_type *holder_ptr,
std::true_type /*is_copy_constructible*/) {
new (std::addressof(v_h.holder<holder_type>()))
holder_type(*reinterpret_cast<const holder_type *>(holder_ptr));
}
static void init_holder_from_existing(const detail::value_and_holder &v_h,
const holder_type *holder_ptr, std::false_type /*is_copy_constructible*/) {
new (std::addressof(v_h.holder<holder_type>())) holder_type(std::move(*const_cast<holder_type *>(holder_ptr)));
}
/// Initialize holder object, variant 2: try to construct from existing holder object, if possible
static void init_holder(detail::instance *inst, detail::value_and_holder &v_h,
const holder_type *holder_ptr, const void * /* dummy -- not enable_shared_from_this<T>) */) {
const holder_type *holder_ptr,
std::false_type /*is_copy_constructible*/) {
new (std::addressof(v_h.holder<holder_type>()))
holder_type(std::move(*const_cast<holder_type *>(holder_ptr)));
}
/// Initialize holder object, variant 2: try to construct from existing holder object, if
/// possible
static void init_holder(detail::instance *inst,
detail::value_and_holder &v_h,
const holder_type *holder_ptr,
const void * /* dummy -- not enable_shared_from_this<T>) */) {
if (holder_ptr) {
init_holder_from_existing(v_h, holder_ptr, std::is_copy_constructible<holder_type>());
v_h.set_holder_constructed();
......@@ -1740,8 +1856,8 @@ private:
}
/// Performs instance initialization including constructing a holder and registering the known
/// instance. Should be called as soon as the `type` value_ptr is set for an instance. Takes an
/// optional pointer to an existing holder to use; if not specified and the instance is
/// instance. Should be called as soon as the `type` value_ptr is set for an instance. Takes
/// an optional pointer to an existing holder to use; if not specified and the instance is
/// `.owned`, a new holder will be constructed to manage the value pointer.
static void init_instance(detail::instance *inst, const void *holder_ptr) {
auto v_h = inst->get_value_and_holder(detail::get_type_info(typeid(type)));
......@@ -1764,35 +1880,42 @@ private:
if (v_h.holder_constructed()) {
v_h.holder<holder_type>().~holder_type();
v_h.set_holder_constructed(false);
}
else {
detail::call_operator_delete(v_h.value_ptr<type>(),
v_h.type->type_size,
v_h.type->type_align
);
} else {
detail::call_operator_delete(
v_h.value_ptr<type>(), v_h.type->type_size, v_h.type->type_align);
}
v_h.value_ptr() = nullptr;
}
static detail::function_record *get_function_record(handle h) {
h = detail::get_function(h);
return h ? (detail::function_record *) reinterpret_borrow<capsule>(PyCFunction_GET_SELF(h.ptr()))
return h ? (detail::function_record *) reinterpret_borrow<capsule>(
PyCFunction_GET_SELF(h.ptr()))
: nullptr;
}
};
/// Binds an existing constructor taking arguments Args...
template <typename... Args> detail::initimpl::constructor<Args...> init() { return {}; }
template <typename... Args>
detail::initimpl::constructor<Args...> init() {
return {};
}
/// Like `init<Args...>()`, but the instance is always constructed through the alias class (even
/// when not inheriting on the Python side).
template <typename... Args> detail::initimpl::alias_constructor<Args...> init_alias() { return {}; }
template <typename... Args>
detail::initimpl::alias_constructor<Args...> init_alias() {
return {};
}
/// Binds a factory function as a constructor
template <typename Func, typename Ret = detail::initimpl::factory<Func>>
Ret init(Func &&f) { return {std::forward<Func>(f)}; }
Ret init(Func &&f) {
return {std::forward<Func>(f)};
}
/// Dual-argument factory function: the first function is called when no alias is needed, the second
/// when an alias is needed (i.e. due to python-side inheritance). Arguments must be identical.
/// Dual-argument factory function: the first function is called when no alias is needed, the
/// second when an alias is needed (i.e. due to python-side inheritance). Arguments must be
/// identical.
template <typename CFunc, typename AFunc, typename Ret = detail::initimpl::factory<CFunc, AFunc>>
Ret init(CFunc &&c, AFunc &&a) {
return {std::forward<CFunc>(c), std::forward<AFunc>(a)};
......@@ -1818,7 +1941,7 @@ inline str enum_name(handle arg) {
}
struct enum_base {
enum_base(const handle &base, const handle &parent) : m_base(base), m_parent(parent) { }
enum_base(const handle &base, const handle &parent) : m_base(base), m_parent(parent) {}
PYBIND11_NOINLINE void init(bool is_arithmetic, bool is_convertible) {
m_base.attr("__entries") = dict();
......@@ -1840,38 +1963,47 @@ struct enum_base {
[](handle arg) -> str {
object type_name = type::handle_of(arg).attr("__name__");
return pybind11::str("{}.{}").format(type_name, enum_name(arg));
}, name("name"), is_method(m_base)
);
},
name("name"),
is_method(m_base));
m_base.attr("__doc__") = static_property(cpp_function(
[](handle arg) -> std::string {
std::string docstring;
dict entries = arg.attr("__entries");
if (((PyTypeObject *) arg.ptr())->tp_doc) {
docstring += std::string(((PyTypeObject *) arg.ptr())->tp_doc) + "\n\n";
}
docstring += "Members:";
for (auto kv : entries) {
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);
m_base.attr("__doc__") = static_property(
cpp_function(
[](handle arg) -> std::string {
std::string docstring;
dict entries = arg.attr("__entries");
if (((PyTypeObject *) arg.ptr())->tp_doc) {
docstring += std::string(((PyTypeObject *) arg.ptr())->tp_doc) + "\n\n";
}
}
return docstring;
}, name("__doc__")
), none(), none(), "");
docstring += "Members:";
for (auto kv : entries) {
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;
},
name("__doc__")),
none(),
none(),
"");
m_base.attr("__members__") = static_property(cpp_function(
[](handle arg) -> dict {
dict entries = arg.attr("__entries"), m;
for (auto kv : entries) {
m[kv.first] = kv.second[int_(0)];
}
return m;
}, name("__members__")), none(), none(), ""
);
[](handle arg) -> dict {
dict entries = arg.attr("__entries"),
m;
for (auto kv : entries) {
m[kv.first] = kv.second[int_(0)];
}
return m;
},
name("__members__")),
none(),
none(),
"");
#define PYBIND11_ENUM_OP_STRICT(op, expr, strict_behavior) \
m_base.attr(op) = cpp_function( \
......@@ -1905,42 +2037,42 @@ struct enum_base {
arg("other"))
if (is_convertible) {
PYBIND11_ENUM_OP_CONV_LHS("__eq__", !b.is_none() && a.equal(b));
PYBIND11_ENUM_OP_CONV_LHS("__ne__", b.is_none() || !a.equal(b));
PYBIND11_ENUM_OP_CONV_LHS("__eq__", !b.is_none() && a.equal(b));
PYBIND11_ENUM_OP_CONV_LHS("__ne__", b.is_none() || !a.equal(b));
if (is_arithmetic) {
PYBIND11_ENUM_OP_CONV("__lt__", a < b);
PYBIND11_ENUM_OP_CONV("__gt__", a > b);
PYBIND11_ENUM_OP_CONV("__le__", a <= b);
PYBIND11_ENUM_OP_CONV("__ge__", a >= b);
PYBIND11_ENUM_OP_CONV("__and__", a & b);
PYBIND11_ENUM_OP_CONV("__rand__", a & b);
PYBIND11_ENUM_OP_CONV("__or__", a | b);
PYBIND11_ENUM_OP_CONV("__ror__", a | b);
PYBIND11_ENUM_OP_CONV("__xor__", a ^ b);
PYBIND11_ENUM_OP_CONV("__rxor__", a ^ b);
PYBIND11_ENUM_OP_CONV("__lt__", a < b);
PYBIND11_ENUM_OP_CONV("__gt__", a > b);
PYBIND11_ENUM_OP_CONV("__le__", a <= b);
PYBIND11_ENUM_OP_CONV("__ge__", a >= b);
PYBIND11_ENUM_OP_CONV("__and__", a & b);
PYBIND11_ENUM_OP_CONV("__rand__", a & b);
PYBIND11_ENUM_OP_CONV("__or__", a | b);
PYBIND11_ENUM_OP_CONV("__ror__", a | b);
PYBIND11_ENUM_OP_CONV("__xor__", a ^ b);
PYBIND11_ENUM_OP_CONV("__rxor__", a ^ b);
m_base.attr("__invert__")
= cpp_function([](const object &arg) { return ~(int_(arg)); },
name("__invert__"),
is_method(m_base));
}
} else {
PYBIND11_ENUM_OP_STRICT("__eq__", int_(a).equal(int_(b)), return false);
PYBIND11_ENUM_OP_STRICT("__eq__", int_(a).equal(int_(b)), return false);
PYBIND11_ENUM_OP_STRICT("__ne__", !int_(a).equal(int_(b)), return true);
if (is_arithmetic) {
#define PYBIND11_THROW throw type_error("Expected an enumeration of matching type!");
PYBIND11_ENUM_OP_STRICT("__lt__", int_(a) < int_(b), PYBIND11_THROW);
PYBIND11_ENUM_OP_STRICT("__gt__", int_(a) > int_(b), PYBIND11_THROW);
#define PYBIND11_THROW throw type_error("Expected an enumeration of matching type!");
PYBIND11_ENUM_OP_STRICT("__lt__", int_(a) < int_(b), PYBIND11_THROW);
PYBIND11_ENUM_OP_STRICT("__gt__", int_(a) > int_(b), PYBIND11_THROW);
PYBIND11_ENUM_OP_STRICT("__le__", int_(a) <= int_(b), PYBIND11_THROW);
PYBIND11_ENUM_OP_STRICT("__ge__", int_(a) >= int_(b), PYBIND11_THROW);
#undef PYBIND11_THROW
#undef PYBIND11_THROW
}
}
#undef PYBIND11_ENUM_OP_CONV_LHS
#undef PYBIND11_ENUM_OP_CONV
#undef PYBIND11_ENUM_OP_STRICT
#undef PYBIND11_ENUM_OP_CONV_LHS
#undef PYBIND11_ENUM_OP_CONV
#undef PYBIND11_ENUM_OP_STRICT
m_base.attr("__getstate__") = cpp_function(
[](const object &arg) { return int_(arg); }, name("__getstate__"), is_method(m_base));
......@@ -1949,12 +2081,13 @@ struct enum_base {
[](const object &arg) { return int_(arg); }, name("__hash__"), is_method(m_base));
}
PYBIND11_NOINLINE void value(char const* name_, object value, const char *doc = nullptr) {
PYBIND11_NOINLINE void value(char const *name_, object value, const char *doc = nullptr) {
dict entries = m_base.attr("__entries");
str name(name_);
if (entries.contains(name)) {
std::string type_name = (std::string) str(m_base.attr("__name__"));
throw value_error(type_name + ": element \"" + std::string(name_) + "\" already exists!");
throw value_error(type_name + ": element \"" + std::string(name_)
+ "\" already exists!");
}
entries[name] = std::make_pair(value, doc);
......@@ -1972,38 +2105,66 @@ struct enum_base {
handle m_parent;
};
template <bool is_signed, size_t length> struct equivalent_integer {};
template <> struct equivalent_integer<true, 1> { using type = int8_t; };
template <> struct equivalent_integer<false, 1> { using type = uint8_t; };
template <> struct equivalent_integer<true, 2> { using type = int16_t; };
template <> struct equivalent_integer<false, 2> { using type = uint16_t; };
template <> struct equivalent_integer<true, 4> { using type = int32_t; };
template <> struct equivalent_integer<false, 4> { using type = uint32_t; };
template <> struct equivalent_integer<true, 8> { using type = int64_t; };
template <> struct equivalent_integer<false, 8> { using type = uint64_t; };
template <bool is_signed, size_t length>
struct equivalent_integer {};
template <>
struct equivalent_integer<true, 1> {
using type = int8_t;
};
template <>
struct equivalent_integer<false, 1> {
using type = uint8_t;
};
template <>
struct equivalent_integer<true, 2> {
using type = int16_t;
};
template <>
struct equivalent_integer<false, 2> {
using type = uint16_t;
};
template <>
struct equivalent_integer<true, 4> {
using type = int32_t;
};
template <>
struct equivalent_integer<false, 4> {
using type = uint32_t;
};
template <>
struct equivalent_integer<true, 8> {
using type = int64_t;
};
template <>
struct equivalent_integer<false, 8> {
using type = uint64_t;
};
template <typename IntLike>
using equivalent_integer_t = typename equivalent_integer<std::is_signed<IntLike>::value, sizeof(IntLike)>::type;
using equivalent_integer_t =
typename equivalent_integer<std::is_signed<IntLike>::value, sizeof(IntLike)>::type;
PYBIND11_NAMESPACE_END(detail)
/// Binds C++ enumerations and enumeration classes to Python
template <typename Type> class enum_ : public class_<Type> {
template <typename Type>
class enum_ : public class_<Type> {
public:
using Base = class_<Type>;
using Base::def;
using Base::attr;
using Base::def;
using Base::def_property_readonly;
using Base::def_property_readonly_static;
using Underlying = typename std::underlying_type<Type>::type;
// Scalar is the integer representation of underlying type
using Scalar = detail::conditional_t<detail::any_of<
detail::is_std_char_type<Underlying>, std::is_same<Underlying, bool>
>::value, detail::equivalent_integer_t<Underlying>, Underlying>;
using Scalar = detail::conditional_t<detail::any_of<detail::is_std_char_type<Underlying>,
std::is_same<Underlying, bool>>::value,
detail::equivalent_integer_t<Underlying>,
Underlying>;
template <typename... Extra>
enum_(const handle &scope, const char *name, const Extra&... extra)
: class_<Type>(scope, name, extra...), m_base(*this, scope) {
enum_(const handle &scope, const char *name, const Extra &...extra)
: class_<Type>(scope, name, extra...), m_base(*this, scope) {
constexpr bool is_arithmetic = detail::any_of<std::is_same<arithmetic, Extra>...>::value;
constexpr bool is_convertible = std::is_convertible<Type, Underlying>::value;
m_base.init(is_arithmetic, is_convertible);
......@@ -2012,25 +2173,28 @@ public:
def_property_readonly("value", [](Type value) { return (Scalar) value; });
def("__int__", [](Type value) { return (Scalar) value; });
def("__index__", [](Type value) { return (Scalar) value; });
#if PY_MAJOR_VERSION < 3
def("__long__", [](Type value) { return (Scalar) value; });
#endif
#if PY_MAJOR_VERSION < 3
def("__long__", [](Type value) { return (Scalar) value; });
#endif
attr("__setstate__") = cpp_function(
[](detail::value_and_holder &v_h, Scalar arg) {
detail::initimpl::setstate<Base>(v_h, static_cast<Type>(arg),
Py_TYPE(v_h.inst) != v_h.type->type); },
detail::initimpl::setstate<Base>(
v_h, static_cast<Type>(arg), Py_TYPE(v_h.inst) != v_h.type->type);
},
detail::is_new_style_constructor(),
pybind11::name("__setstate__"), is_method(*this), arg("state"));
pybind11::name("__setstate__"),
is_method(*this),
arg("state"));
}
/// Export enumeration entries into the parent scope
enum_& export_values() {
enum_ &export_values() {
m_base.export_values();
return *this;
}
/// Add an enumeration entry
enum_& value(char const* name, Type value, const char *doc = nullptr) {
enum_ &value(char const *name, Type value, const char *doc = nullptr) {
m_base.value(name, pybind11::cast(value, return_value_policy::copy), doc);
return *this;
}
......@@ -2041,7 +2205,6 @@ private:
PYBIND11_NAMESPACE_BEGIN(detail)
PYBIND11_NOINLINE void keep_alive_impl(handle nurse, handle patient) {
if (!nurse || !patient) {
pybind11_fail("Could not activate keep_alive!");
......@@ -2056,13 +2219,14 @@ PYBIND11_NOINLINE void keep_alive_impl(handle nurse, handle patient) {
/* It's a pybind-registered type, so we can store the patient in the
* internal list. */
add_patient(nurse.ptr(), patient.ptr());
}
else {
} else {
/* Fall back to clever approach based on weak references taken from
* Boost.Python. This is not used for pybind-registered types because
* the objects can be destroyed out-of-order in a GC pass. */
cpp_function disable_lifesupport(
[patient](handle weakref) { patient.dec_ref(); weakref.dec_ref(); });
cpp_function disable_lifesupport([patient](handle weakref) {
patient.dec_ref();
weakref.dec_ref();
});
weakref wr(nurse, disable_lifesupport);
......@@ -2071,7 +2235,8 @@ PYBIND11_NOINLINE void keep_alive_impl(handle nurse, handle patient) {
}
}
PYBIND11_NOINLINE void keep_alive_impl(size_t Nurse, size_t Patient, function_call &call, handle ret) {
PYBIND11_NOINLINE void
keep_alive_impl(size_t Nurse, size_t Patient, function_call &call, handle ret) {
auto get_arg = [&](size_t n) {
if (n == 0) {
return ret;
......@@ -2088,31 +2253,34 @@ PYBIND11_NOINLINE void keep_alive_impl(size_t Nurse, size_t Patient, function_ca
keep_alive_impl(get_arg(Nurse), get_arg(Patient));
}
inline std::pair<decltype(internals::registered_types_py)::iterator, bool> all_type_info_get_cache(PyTypeObject *type) {
auto res = get_internals().registered_types_py
inline std::pair<decltype(internals::registered_types_py)::iterator, bool>
all_type_info_get_cache(PyTypeObject *type) {
auto res = get_internals()
.registered_types_py
#ifdef __cpp_lib_unordered_map_try_emplace
.try_emplace(type);
.try_emplace(type);
#else
.emplace(type, std::vector<detail::type_info *>());
.emplace(type, std::vector<detail::type_info *>());
#endif
if (res.second) {
// New cache entry created; set up a weak reference to automatically remove it if the type
// gets destroyed:
weakref((PyObject *) type, cpp_function([type](handle wr) {
get_internals().registered_types_py.erase(type);
get_internals().registered_types_py.erase(type);
// TODO consolidate the erasure code in pybind11_meta_dealloc() in class.h
auto &cache = get_internals().inactive_override_cache;
for (auto it = cache.begin(), last = cache.end(); it != last; ) {
if (it->first == reinterpret_cast<PyObject *>(type)) {
it = cache.erase(it);
} else {
++it;
}
}
// TODO consolidate the erasure code in pybind11_meta_dealloc() in class.h
auto &cache = get_internals().inactive_override_cache;
for (auto it = cache.begin(), last = cache.end(); it != last;) {
if (it->first == reinterpret_cast<PyObject *>(type)) {
it = cache.erase(it);
} else {
++it;
}
}
wr.dec_ref();
})).release();
wr.dec_ref();
}))
.release();
}
return res;
......@@ -2121,7 +2289,12 @@ inline std::pair<decltype(internals::registered_types_py)::iterator, bool> all_t
/* There are a large number of apparently unused template arguments because
* each combination requires a separate py::class_ registration.
*/
template <typename Access, return_value_policy Policy, typename Iterator, typename Sentinel, typename ValueType, typename... Extra>
template <typename Access,
return_value_policy Policy,
typename Iterator,
typename Sentinel,
typename ValueType,
typename... Extra>
struct iterator_state {
Iterator it;
Sentinel end;
......@@ -2136,12 +2309,10 @@ template <typename Iterator, typename SFINAE = decltype(*std::declval<Iterator &
struct iterator_access {
using result_type = decltype(*std::declval<Iterator &>());
// NOLINTNEXTLINE(readability-const-return-type) // PR #3263
result_type operator()(Iterator &it) const {
return *it;
}
result_type operator()(Iterator &it) const { return *it; }
};
template <typename Iterator, typename SFINAE = decltype((*std::declval<Iterator &>()).first) >
template <typename Iterator, typename SFINAE = decltype((*std::declval<Iterator &>()).first)>
class iterator_key_access {
private:
using pair_type = decltype(*std::declval<Iterator &>());
......@@ -2156,14 +2327,11 @@ public:
* (it's not used in the first branch because going via decltype and back
* through declval does not perfectly preserve references).
*/
using result_type = conditional_t<
std::is_reference<decltype(*std::declval<Iterator &>())>::value,
decltype(((*std::declval<Iterator &>()).first)),
decltype(std::declval<pair_type>().first)
>;
result_type operator()(Iterator &it) const {
return (*it).first;
}
using result_type
= conditional_t<std::is_reference<decltype(*std::declval<Iterator &>())>::value,
decltype(((*std::declval<Iterator &>()).first)),
decltype(std::declval<pair_type>().first)>;
result_type operator()(Iterator &it) const { return (*it).first; }
};
template <typename Iterator, typename SFINAE = decltype((*std::declval<Iterator &>()).second)>
......@@ -2172,14 +2340,11 @@ private:
using pair_type = decltype(*std::declval<Iterator &>());
public:
using result_type = conditional_t<
std::is_reference<decltype(*std::declval<Iterator &>())>::value,
decltype(((*std::declval<Iterator &>()).second)),
decltype(std::declval<pair_type>().second)
>;
result_type operator()(Iterator &it) const {
return (*it).second;
}
using result_type
= conditional_t<std::is_reference<decltype(*std::declval<Iterator &>())>::value,
decltype(((*std::declval<Iterator &>()).second)),
decltype(std::declval<pair_type>().second)>;
result_type operator()(Iterator &it) const { return (*it).second; }
};
template <typename Access,
......@@ -2188,7 +2353,7 @@ template <typename Access,
typename Sentinel,
typename ValueType,
typename... Extra>
iterator make_iterator_impl(Iterator first, Sentinel last, Extra &&... extra) {
iterator make_iterator_impl(Iterator first, Sentinel last, Extra &&...extra) {
using state = detail::iterator_state<Access, Policy, Iterator, Sentinel, ValueType, Extra...>;
// TODO: state captures only the types of Extra, not the values
......@@ -2225,14 +2390,13 @@ template <return_value_policy Policy = return_value_policy::reference_internal,
typename Sentinel,
typename ValueType = typename detail::iterator_access<Iterator>::result_type,
typename... Extra>
iterator make_iterator(Iterator first, Sentinel last, Extra &&... extra) {
return detail::make_iterator_impl<
detail::iterator_access<Iterator>,
Policy,
Iterator,
Sentinel,
ValueType,
Extra...>(first, last, std::forward<Extra>(extra)...);
iterator make_iterator(Iterator first, Sentinel last, Extra &&...extra) {
return detail::make_iterator_impl<detail::iterator_access<Iterator>,
Policy,
Iterator,
Sentinel,
ValueType,
Extra...>(first, last, std::forward<Extra>(extra)...);
}
/// Makes a python iterator over the keys (`.first`) of a iterator over pairs from a
......@@ -2243,13 +2407,12 @@ template <return_value_policy Policy = return_value_policy::reference_internal,
typename KeyType = typename detail::iterator_key_access<Iterator>::result_type,
typename... Extra>
iterator make_key_iterator(Iterator first, Sentinel last, Extra &&...extra) {
return detail::make_iterator_impl<
detail::iterator_key_access<Iterator>,
Policy,
Iterator,
Sentinel,
KeyType,
Extra...>(first, last, std::forward<Extra>(extra)...);
return detail::make_iterator_impl<detail::iterator_key_access<Iterator>,
Policy,
Iterator,
Sentinel,
KeyType,
Extra...>(first, last, std::forward<Extra>(extra)...);
}
/// Makes a python iterator over the values (`.second`) of a iterator over pairs from a
......@@ -2260,36 +2423,43 @@ template <return_value_policy Policy = return_value_policy::reference_internal,
typename ValueType = typename detail::iterator_value_access<Iterator>::result_type,
typename... Extra>
iterator make_value_iterator(Iterator first, Sentinel last, Extra &&...extra) {
return detail::make_iterator_impl<
detail::iterator_value_access<Iterator>,
Policy, Iterator,
Sentinel,
ValueType,
Extra...>(first, last, std::forward<Extra>(extra)...);
return detail::make_iterator_impl<detail::iterator_value_access<Iterator>,
Policy,
Iterator,
Sentinel,
ValueType,
Extra...>(first, last, std::forward<Extra>(extra)...);
}
/// 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) {
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) {
typename Type,
typename... Extra>
iterator make_key_iterator(Type &value, Extra &&...extra) {
return make_key_iterator<Policy>(std::begin(value), std::end(value), extra...);
}
/// Makes an iterator over the values (`.second`) 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_value_iterator(Type &value, Extra&&... extra) {
typename Type,
typename... Extra>
iterator make_value_iterator(Type &value, Extra &&...extra) {
return make_value_iterator<Policy>(std::begin(value), std::end(value), extra...);
}
template <typename InputType, typename OutputType> void implicitly_convertible() {
template <typename InputType, typename OutputType>
void implicitly_convertible() {
struct set_flag {
bool &flag;
explicit set_flag(bool &flag_) : flag(flag_) { flag_ = true; }
......@@ -2320,19 +2490,17 @@ template <typename InputType, typename OutputType> void implicitly_convertible()
}
}
inline void register_exception_translator(ExceptionTranslator &&translator) {
detail::get_internals().registered_exception_translators.push_front(
std::forward<ExceptionTranslator>(translator));
}
/**
* Add a new module-local exception translator. Locally registered functions
* will be tried before any globally registered exception translators, which
* will only be invoked if the module-local handlers do not deal with
* the exception.
*/
* Add a new module-local exception translator. Locally registered functions
* will be tried before any globally registered exception translators, which
* will only be invoked if the module-local handlers do not deal with
* the exception.
*/
inline void register_local_exception_translator(ExceptionTranslator &&translator) {
detail::get_local_internals().registered_exception_translators.push_front(
std::forward<ExceptionTranslator>(translator));
......@@ -2350,8 +2518,8 @@ class exception : public object {
public:
exception() = default;
exception(handle scope, const char *name, handle base = PyExc_Exception) {
std::string full_name = scope.attr("__name__").cast<std::string>() +
std::string(".") + name;
std::string full_name
= scope.attr("__name__").cast<std::string>() + std::string(".") + name;
m_ptr = PyErr_NewException(const_cast<char *>(full_name.c_str()), base.ptr(), NULL);
if (hasattr(scope, "__dict__") && scope.attr("__dict__").contains(name)) {
pybind11_fail("Error during initialization: multiple incompatible "
......@@ -2362,9 +2530,7 @@ public:
}
// Sets the current python exception to this exception object with the given message
void operator()(const char *message) {
PyErr_SetString(m_ptr, message);
}
void operator()(const char *message) { PyErr_SetString(m_ptr, message); }
};
PYBIND11_NAMESPACE_BEGIN(detail)
......@@ -2372,21 +2538,22 @@ PYBIND11_NAMESPACE_BEGIN(detail)
// register_exception approach below. (It would be simpler to have the static local variable
// directly in register_exception, but that makes clang <3.5 segfault - issue #1349).
template <typename CppException>
exception<CppException> &get_exception_object() { static exception<CppException> ex; return ex; }
exception<CppException> &get_exception_object() {
static exception<CppException> ex;
return ex;
}
// Helper function for register_exception and register_local_exception
template <typename CppException>
exception<CppException> &register_exception_impl(handle scope,
const char *name,
handle base,
bool isLocal) {
exception<CppException> &
register_exception_impl(handle scope, const char *name, handle base, bool isLocal) {
auto &ex = detail::get_exception_object<CppException>();
if (!ex) {
ex = exception<CppException>(scope, name, base);
}
auto register_func = isLocal ? &register_local_exception_translator
: &register_exception_translator;
auto register_func
= isLocal ? &register_local_exception_translator : &register_exception_translator;
register_func([](std::exception_ptr p) {
if (!p) {
......@@ -2410,9 +2577,8 @@ PYBIND11_NAMESPACE_END(detail)
* exception object and translator directly.
*/
template <typename CppException>
exception<CppException> &register_exception(handle scope,
const char *name,
handle base = PyExc_Exception) {
exception<CppException> &
register_exception(handle scope, const char *name, handle base = PyExc_Exception) {
return detail::register_exception_impl<CppException>(scope, name, base, false /* isLocal */);
}
......@@ -2425,9 +2591,8 @@ exception<CppException> &register_exception(handle scope,
* exception object and translator directly.
*/
template <typename CppException>
exception<CppException> &register_local_exception(handle scope,
const char *name,
handle base = PyExc_Exception) {
exception<CppException> &
register_local_exception(handle scope, const char *name, handle base = PyExc_Exception) {
return detail::register_exception_impl<CppException>(scope, name, base, true /* isLocal */);
}
......@@ -2482,7 +2647,8 @@ error_already_set::~error_already_set() {
}
PYBIND11_NAMESPACE_BEGIN(detail)
inline function get_type_override(const void *this_ptr, const type_info *this_type, const char *name) {
inline function
get_type_override(const void *this_ptr, const type_info *this_type, const char *name) {
handle self = get_object_handle(this_ptr, this_type);
if (!self) {
return function();
......@@ -2508,17 +2674,16 @@ inline function get_type_override(const void *this_ptr, const type_info *this_ty
#if !defined(PYPY_VERSION) && PY_VERSION_HEX < 0x030B0000
// TODO: Remove PyPy workaround for Python 3.11.
// Current API fails on 3.11 since co_varnames can be null.
#if PY_VERSION_HEX >= 0x03090000
# if PY_VERSION_HEX >= 0x03090000
PyFrameObject *frame = PyThreadState_GetFrame(PyThreadState_Get());
if (frame != nullptr) {
PyCodeObject *f_code = PyFrame_GetCode(frame);
// f_code is guaranteed to not be NULL
if ((std::string) str(f_code->co_name) == name && f_code->co_argcount > 0) {
PyObject* locals = PyEval_GetLocals();
PyObject *locals = PyEval_GetLocals();
if (locals != nullptr && f_code->co_varnames != nullptr) {
PyObject *self_caller = dict_getitem(
locals, PyTuple_GET_ITEM(f_code->co_varnames, 0)
);
PyObject *self_caller
= dict_getitem(locals, PyTuple_GET_ITEM(f_code->co_varnames, 0));
if (self_caller == self.ptr()) {
Py_DECREF(f_code);
Py_DECREF(frame);
......@@ -2529,35 +2694,39 @@ inline function get_type_override(const void *this_ptr, const type_info *this_ty
Py_DECREF(f_code);
Py_DECREF(frame);
}
#else
# else
PyFrameObject *frame = PyThreadState_Get()->frame;
if (frame != nullptr && (std::string) str(frame->f_code->co_name) == name
&& frame->f_code->co_argcount > 0) {
PyFrame_FastToLocals(frame);
PyObject *self_caller = dict_getitem(
frame->f_locals, PyTuple_GET_ITEM(frame->f_code->co_varnames, 0));
PyObject *self_caller
= dict_getitem(frame->f_locals, PyTuple_GET_ITEM(frame->f_code->co_varnames, 0));
if (self_caller == self.ptr()) {
return function();
}
}
#endif
# endif
#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());
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 (d["self"].is_none())
......@@ -2578,7 +2747,8 @@ PYBIND11_NAMESPACE_END(detail)
:name: The name of the overridden Python method to retrieve.
:return: The Python method by this name from the object or an empty function wrapper.
\endrst */
template <class T> function get_override(const T *this_ptr, const char *name) {
template <class T>
function get_override(const T *this_ptr, const char *name) {
auto *tinfo = detail::get_type_info(typeid(T));
return tinfo ? detail::get_type_override(this_ptr, tinfo, name) : function();
}
......@@ -2616,20 +2786,21 @@ template <class T> function get_override(const T *this_ptr, const char *name) {
);
}
\endrst */
#define PYBIND11_OVERRIDE_NAME(ret_type, cname, name, fn, ...) \
do { \
#define PYBIND11_OVERRIDE_NAME(ret_type, cname, name, fn, ...) \
do { \
PYBIND11_OVERRIDE_IMPL(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), name, __VA_ARGS__); \
return cname::fn(__VA_ARGS__); \
return cname::fn(__VA_ARGS__); \
} while (false)
/** \rst
Macro for pure virtual functions, this function is identical to
:c:macro:`PYBIND11_OVERRIDE_NAME`, except that it throws if no override can be found.
\endrst */
#define PYBIND11_OVERRIDE_PURE_NAME(ret_type, cname, name, fn, ...) \
do { \
#define PYBIND11_OVERRIDE_PURE_NAME(ret_type, cname, name, fn, ...) \
do { \
PYBIND11_OVERRIDE_IMPL(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), name, __VA_ARGS__); \
pybind11::pybind11_fail("Tried to call pure virtual function \"" PYBIND11_STRINGIFY(cname) "::" name "\""); \
pybind11::pybind11_fail( \
"Tried to call pure virtual function \"" PYBIND11_STRINGIFY(cname) "::" name "\""); \
} while (false)
/** \rst
......@@ -2657,21 +2828,22 @@ template <class T> function get_override(const T *this_ptr, const char *name) {
}
};
\endrst */
#define PYBIND11_OVERRIDE(ret_type, cname, fn, ...) \
#define PYBIND11_OVERRIDE(ret_type, cname, fn, ...) \
PYBIND11_OVERRIDE_NAME(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), #fn, fn, __VA_ARGS__)
/** \rst
Macro for pure virtual functions, this function is identical to :c:macro:`PYBIND11_OVERRIDE`,
except that it throws if no override can be found.
\endrst */
#define PYBIND11_OVERRIDE_PURE(ret_type, cname, fn, ...) \
PYBIND11_OVERRIDE_PURE_NAME(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), #fn, fn, __VA_ARGS__)
#define PYBIND11_OVERRIDE_PURE(ret_type, cname, fn, ...) \
PYBIND11_OVERRIDE_PURE_NAME( \
PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), #fn, fn, __VA_ARGS__)
// Deprecated versions
PYBIND11_DEPRECATED("get_type_overload has been deprecated")
inline function get_type_overload(const void *this_ptr, const detail::type_info *this_type, const char *name) {
inline function
get_type_overload(const void *this_ptr, const detail::type_info *this_type, const char *name) {
return detail::get_type_override(this_ptr, this_type, name);
}
......@@ -2680,15 +2852,16 @@ inline function get_overload(const T *this_ptr, const char *name) {
return get_override(this_ptr, name);
}
#define PYBIND11_OVERLOAD_INT(ret_type, cname, name, ...) \
#define PYBIND11_OVERLOAD_INT(ret_type, cname, name, ...) \
PYBIND11_OVERRIDE_IMPL(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), name, __VA_ARGS__)
#define PYBIND11_OVERLOAD_NAME(ret_type, cname, name, fn, ...) \
#define PYBIND11_OVERLOAD_NAME(ret_type, cname, name, fn, ...) \
PYBIND11_OVERRIDE_NAME(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), name, fn, __VA_ARGS__)
#define PYBIND11_OVERLOAD_PURE_NAME(ret_type, cname, name, fn, ...) \
PYBIND11_OVERRIDE_PURE_NAME(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), name, fn, __VA_ARGS__);
#define PYBIND11_OVERLOAD(ret_type, cname, fn, ...) \
#define PYBIND11_OVERLOAD_PURE_NAME(ret_type, cname, name, fn, ...) \
PYBIND11_OVERRIDE_PURE_NAME( \
PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), name, fn, __VA_ARGS__);
#define PYBIND11_OVERLOAD(ret_type, cname, fn, ...) \
PYBIND11_OVERRIDE(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), fn, __VA_ARGS__)
#define PYBIND11_OVERLOAD_PURE(ret_type, cname, fn, ...) \
#define PYBIND11_OVERLOAD_PURE(ret_type, cname, fn, ...) \
PYBIND11_OVERRIDE_PURE(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), fn, __VA_ARGS__);
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
......
......@@ -11,38 +11,43 @@
#include "detail/common.h"
#include "buffer_info.h"
#include <utility>
#include <type_traits>
#include <utility>
#if defined(PYBIND11_HAS_OPTIONAL)
# include <optional>
# include <optional>
#endif
#ifdef PYBIND11_HAS_STRING_VIEW
# include <string_view>
# include <string_view>
#endif
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
/* A few forward declarations */
class handle; class object;
class str; class iterator;
class handle;
class object;
class str;
class iterator;
class type;
struct arg; struct arg_v;
struct arg;
struct arg_v;
PYBIND11_NAMESPACE_BEGIN(detail)
class args_proxy;
bool isinstance_generic(handle obj, const std::type_info &tp);
// Accessor forward declarations
template <typename Policy> class accessor;
template <typename Policy>
class accessor;
namespace accessor_policies {
struct obj_attr;
struct str_attr;
struct generic_item;
struct sequence_item;
struct list_item;
struct tuple_item;
struct obj_attr;
struct str_attr;
struct generic_item;
struct sequence_item;
struct list_item;
struct tuple_item;
} // namespace accessor_policies
using obj_attr_accessor = accessor<accessor_policies::obj_attr>;
using str_attr_accessor = accessor<accessor_policies::str_attr>;
......@@ -52,8 +57,9 @@ using list_accessor = accessor<accessor_policies::list_item>;
using tuple_accessor = accessor<accessor_policies::tuple_item>;
/// Tag and check to identify a class which implements the Python object API
class pyobject_tag { };
template <typename T> using is_pyobject = std::is_base_of<pyobject_tag, remove_reference_t<T>>;
class pyobject_tag {};
template <typename T>
using is_pyobject = std::is_base_of<pyobject_tag, remove_reference_t<T>>;
/** \rst
A mixin class which adds common functions to `handle`, `object` and various accessors.
......@@ -101,7 +107,8 @@ public:
args_proxy operator*() const;
/// Check if the given item is contained within this object, i.e. ``item in obj``.
template <typename T> bool contains(T &&item) const;
template <typename T>
bool contains(T &&item) const;
/** \rst
Assuming the Python object is a function or implements the ``__call__``
......@@ -113,22 +120,24 @@ public:
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>
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>
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;
object call(Args &&...args) const;
/// Equivalent to ``obj is other`` in Python.
bool is(object_api const& other) const { return derived().ptr() == other.derived().ptr(); }
bool is(object_api const &other) const { return derived().ptr() == other.derived().ptr(); }
/// Equivalent to ``obj is None`` in Python.
bool is_none() const { return derived().ptr() == Py_None; }
/// Equivalent to obj == other in Python
bool equal(object_api const &other) const { return rich_compare(other, Py_EQ); }
bool not_equal(object_api const &other) const { return rich_compare(other, Py_NE); }
bool operator<(object_api const &other) const { return rich_compare(other, Py_LT); }
bool equal(object_api const &other) const { return rich_compare(other, Py_EQ); }
bool not_equal(object_api const &other) const { return rich_compare(other, Py_NE); }
bool operator<(object_api const &other) const { return rich_compare(other, Py_LT); }
bool operator<=(object_api const &other) const { return rich_compare(other, Py_LE); }
bool operator>(object_api const &other) const { return rich_compare(other, Py_GT); }
bool operator>(object_api const &other) const { return rich_compare(other, Py_GT); }
bool operator>=(object_api const &other) const { return rich_compare(other, Py_GE); }
object operator-() const;
......@@ -188,7 +197,7 @@ public:
handle() = default;
/// Creates a ``handle`` from the given raw Python object pointer
// NOLINTNEXTLINE(google-explicit-constructor)
handle(PyObject *ptr) : m_ptr(ptr) { } // Allow implicit conversion from PyObject*
handle(PyObject *ptr) : m_ptr(ptr) {} // Allow implicit conversion from PyObject*
/// Return the underlying ``PyObject *`` pointer
PyObject *ptr() const { return m_ptr; }
......@@ -199,20 +208,27 @@ public:
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; }
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; }
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;
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
......@@ -225,6 +241,7 @@ public:
bool operator!=(const handle &h) const { return m_ptr != h.m_ptr; }
PYBIND11_DEPRECATED("Use handle::operator bool() instead")
bool check() const { return m_ptr != nullptr; }
protected:
PyObject *m_ptr = nullptr;
};
......@@ -251,7 +268,10 @@ public:
/// 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; }
object(object &&other) noexcept {
m_ptr = other.m_ptr;
other.m_ptr = nullptr;
}
/// Destructor; automatically calls `handle::dec_ref()`
~object() { dec_ref(); }
......@@ -261,12 +281,12 @@ public:
Python object.
\endrst */
handle release() {
PyObject *tmp = m_ptr;
m_ptr = nullptr;
return handle(tmp);
PyObject *tmp = m_ptr;
m_ptr = nullptr;
return handle(tmp);
}
object& operator=(const object &other) {
object &operator=(const object &other) {
other.inc_ref();
// Use temporary variable to ensure `*this` remains valid while
// `Py_XDECREF` executes, in case `*this` is accessible from Python.
......@@ -276,7 +296,7 @@ public:
return *this;
}
object& operator=(object &&other) noexcept {
object &operator=(object &&other) noexcept {
if (this != &other) {
handle temp(m_ptr);
m_ptr = other.m_ptr;
......@@ -287,24 +307,28 @@ public:
}
// Calling cast() on an object lvalue just copies (via handle::cast)
template <typename T> T cast() const &;
template <typename T>
T cast() const &;
// Calling on an object rvalue does a move, if needed and/or possible
template <typename T> T cast() &&;
template <typename T>
T cast() &&;
protected:
// Tags for choosing constructors from raw PyObject *
struct borrowed_t { };
struct stolen_t { };
struct borrowed_t {};
struct stolen_t {};
/// @cond BROKEN
template <typename T> friend T reinterpret_borrow(handle);
template <typename T> friend T reinterpret_steal(handle);
template <typename T>
friend T reinterpret_borrow(handle);
template <typename T>
friend T reinterpret_steal(handle);
/// @endcond
public:
// Only accessible from derived classes and the reinterpret_* functions
object(handle h, borrowed_t) : handle(h) { inc_ref(); }
object(handle h, stolen_t) : handle(h) { }
object(handle h, stolen_t) : handle(h) {}
};
/** \rst
......@@ -320,7 +344,10 @@ public:
// 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_t{}}; }
template <typename T>
T reinterpret_borrow(handle h) {
return {h, object::borrowed_t{}};
}
/** \rst
Like `reinterpret_borrow`, but steals the reference.
......@@ -330,15 +357,18 @@ template <typename T> T reinterpret_borrow(handle h) { return {h, object::borrow
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_t{}}; }
template <typename T>
T reinterpret_steal(handle h) {
return {h, object::stolen_t{}};
}
PYBIND11_NAMESPACE_BEGIN(detail)
std::string error_string();
PYBIND11_NAMESPACE_END(detail)
#if defined(_MSC_VER)
# pragma warning(push)
# pragma warning(disable: 4275 4251)
# pragma warning(push)
# pragma warning(disable : 4275 4251)
// warning C4275: An exported class was derived from a class that wasn't exported.
// Can be ignored when derived from a STL class.
#endif
......@@ -362,19 +392,22 @@ public:
/// Give the currently-held error back to Python, if any. If there is currently a Python error
/// already set it is cleared first. After this call, the current object no longer stores the
/// error variables (but the `.what()` string is still available).
void restore() { PyErr_Restore(m_type.release().ptr(), m_value.release().ptr(), m_trace.release().ptr()); }
void restore() {
PyErr_Restore(m_type.release().ptr(), m_value.release().ptr(), m_trace.release().ptr());
}
/// If it is impossible to raise the currently-held error, such as in a destructor, we can write
/// it out using Python's unraisable hook (`sys.unraisablehook`). The error context should be
/// some object whose `repr()` helps identify the location of the error. Python already knows the
/// type and value of the error, so there is no need to repeat that. After this call, the current
/// object no longer stores the error variables, and neither does Python.
/// If it is impossible to raise the currently-held error, such as in a destructor, we can
/// write it out using Python's unraisable hook (`sys.unraisablehook`). The error context
/// should be some object whose `repr()` helps identify the location of the error. Python
/// already knows the type and value of the error, so there is no need to repeat that. After
/// this call, the current object no longer stores the error variables, and neither does
/// Python.
void discard_as_unraisable(object err_context) {
restore();
PyErr_WriteUnraisable(err_context.ptr());
}
/// An alternate version of `discard_as_unraisable()`, where a string provides information on the
/// location of the error. For example, `__func__` could be helpful.
/// An alternate version of `discard_as_unraisable()`, where a string provides information on
/// the location of the error. For example, `__func__` could be helpful.
void discard_as_unraisable(const char *err_context) {
discard_as_unraisable(reinterpret_steal<object>(PYBIND11_FROM_STRING(err_context)));
}
......@@ -390,15 +423,15 @@ public:
return (PyErr_GivenExceptionMatches(m_type.ptr(), exc.ptr()) != 0);
}
const object& type() const { return m_type; }
const object& value() const { return m_value; }
const object& trace() const { return m_trace; }
const object &type() const { return m_type; }
const object &value() const { return m_value; }
const object &trace() const { return m_trace; }
private:
object m_type, m_value, m_trace;
};
#if defined(_MSC_VER)
# pragma warning(pop)
# pragma warning(pop)
#endif
#if PY_VERSION_HEX >= 0x03030000
......@@ -435,7 +468,7 @@ inline void raise_from(PyObject *type, const char *message) {
/// from the error contained in error_already_set to indicate that the chosen error was
/// caused by the original error. After this function is called error_already_set will
/// no longer contain an error.
inline void raise_from(error_already_set& err, PyObject *type, const char *message) {
inline void raise_from(error_already_set &err, PyObject *type, const char *message) {
err.restore();
raise_from(type, message);
}
......@@ -453,13 +486,21 @@ inline void raise_from(error_already_set& err, PyObject *type, const char *messa
`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)); }
bool isinstance(handle obj) {
return detail::isinstance_generic(obj, typeid(T));
}
template <> inline bool isinstance<handle>(handle) = delete;
template <> inline bool isinstance<object>(handle obj) { return obj.ptr() != nullptr; }
template <>
inline bool isinstance<handle>(handle) = 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``.
......@@ -482,22 +523,30 @@ inline bool hasattr(handle obj, const char *name) {
}
inline void delattr(handle obj, handle name) {
if (PyObject_DelAttr(obj.ptr(), name.ptr()) != 0) { throw error_already_set(); }
if (PyObject_DelAttr(obj.ptr(), name.ptr()) != 0) {
throw error_already_set();
}
}
inline void delattr(handle obj, const char *name) {
if (PyObject_DelAttrString(obj.ptr(), name) != 0) { throw error_already_set(); }
if (PyObject_DelAttrString(obj.ptr(), name) != 0) {
throw error_already_set();
}
}
inline object getattr(handle obj, handle name) {
PyObject *result = PyObject_GetAttr(obj.ptr(), name.ptr());
if (!result) { throw error_already_set(); }
if (!result) {
throw error_already_set();
}
return reinterpret_steal<object>(result);
}
inline object getattr(handle obj, const char *name) {
PyObject *result = PyObject_GetAttrString(obj.ptr(), name);
if (!result) { throw error_already_set(); }
if (!result) {
throw error_already_set();
}
return reinterpret_steal<object>(result);
}
......@@ -518,16 +567,22 @@ inline object getattr(handle obj, const char *name, handle default_) {
}
inline void setattr(handle obj, handle name, handle value) {
if (PyObject_SetAttr(obj.ptr(), name.ptr(), value.ptr()) != 0) { throw error_already_set(); }
if (PyObject_SetAttr(obj.ptr(), name.ptr(), value.ptr()) != 0) {
throw error_already_set();
}
}
inline void setattr(handle obj, const char *name, handle value) {
if (PyObject_SetAttrString(obj.ptr(), name, value.ptr()) != 0) { throw error_already_set(); }
if (PyObject_SetAttrString(obj.ptr(), name, value.ptr()) != 0) {
throw error_already_set();
}
}
inline ssize_t hash(handle obj) {
auto h = PyObject_Hash(obj.ptr());
if (h == -1) { throw error_already_set(); }
if (h == -1) {
throw error_already_set();
}
return h;
}
......@@ -552,8 +607,7 @@ inline handle get_function(handle value) {
// aren't swallowed (see #2862)
// copied from cpython _PyDict_GetItemStringWithError
inline PyObject * dict_getitemstring(PyObject *v, const char *key)
{
inline PyObject *dict_getitemstring(PyObject *v, const char *key) {
#if PY_MAJOR_VERSION >= 3
PyObject *kv = nullptr, *rv = nullptr;
kv = PyUnicode_FromString(key);
......@@ -572,8 +626,7 @@ inline PyObject * dict_getitemstring(PyObject *v, const char *key)
#endif
}
inline PyObject * dict_getitem(PyObject *v, PyObject *key)
{
inline PyObject *dict_getitem(PyObject *v, PyObject *key) {
#if PY_MAJOR_VERSION >= 3
PyObject *rv = PyDict_GetItemWithError(v, key);
if (rv == NULL && PyErr_Occurred()) {
......@@ -585,11 +638,13 @@ inline PyObject * dict_getitem(PyObject *v, PyObject *key)
#endif
}
// Helper aliases/functions to support implicit casting of values given to python accessors/methods.
// When given a pyobject, this simply returns the pyobject as-is; for other C++ type, the value goes
// through pybind11::cast(obj) to convert it to an `object`.
// Helper aliases/functions to support implicit casting of values given to python
// accessors/methods. When given a pyobject, this simply returns the pyobject as-is; for other C++
// type, the value goes through pybind11::cast(obj) to convert it to an `object`.
template <typename T, enable_if_t<is_pyobject<T>::value, int> = 0>
auto object_or_cast(T &&o) -> decltype(std::forward<T>(o)) { return std::forward<T>(o); }
auto object_or_cast(T &&o) -> decltype(std::forward<T>(o)) {
return std::forward<T>(o);
}
// The following casting version is implemented in cast.h:
template <typename T, enable_if_t<!is_pyobject<T>::value, int> = 0>
object object_or_cast(T &&o);
......@@ -597,50 +652,61 @@ object object_or_cast(T &&o);
inline handle object_or_cast(PyObject *ptr) { return ptr; }
#if defined(_MSC_VER) && _MSC_VER < 1920
# pragma warning(push)
# pragma warning(disable: 4522) // warning C4522: multiple assignment operators specified
# pragma warning(push)
# pragma warning(disable : 4522) // warning C4522: multiple assignment operators specified
#endif
template <typename Policy>
class accessor : public object_api<accessor<Policy>> {
using key_type = typename Policy::key_type;
public:
accessor(handle obj, key_type key) : obj(obj), key(std::move(key)) { }
accessor(handle obj, key_type key) : obj(obj), key(std::move(key)) {}
accessor(const accessor &) = default;
accessor(accessor &&) noexcept = default;
// accessor overload required to override default assignment operator (templates are not allowed
// to replace default compiler-generated assignments).
// accessor overload required to override default assignment operator (templates are not
// allowed to replace default compiler-generated assignments).
void operator=(const accessor &a) && { std::move(*this).operator=(handle(a)); }
void operator=(const accessor &a) & { operator=(handle(a)); }
template <typename T> void operator=(T &&value) && {
template <typename T>
void operator=(T &&value) && {
Policy::set(obj, key, object_or_cast(std::forward<T>(value)));
}
template <typename T> void operator=(T &&value) & {
template <typename T>
void operator=(T &&value) & {
get_cache() = reinterpret_borrow<object>(object_or_cast(std::forward<T>(value)));
}
template <typename T = Policy>
PYBIND11_DEPRECATED("Use of obj.attr(...) as bool is deprecated in favor of pybind11::hasattr(obj, ...)")
explicit operator enable_if_t<std::is_same<T, accessor_policies::str_attr>::value ||
std::is_same<T, accessor_policies::obj_attr>::value, bool>() const {
PYBIND11_DEPRECATED(
"Use of obj.attr(...) as bool is deprecated in favor of pybind11::hasattr(obj, ...)")
explicit
operator enable_if_t<std::is_same<T, accessor_policies::str_attr>::value
|| std::is_same<T, accessor_policies::obj_attr>::value,
bool>() const {
return hasattr(obj, key);
}
template <typename T = Policy>
PYBIND11_DEPRECATED("Use of obj[key] as bool is deprecated in favor of obj.contains(key)")
explicit operator enable_if_t<std::is_same<T, accessor_policies::generic_item>::value, bool>() const {
explicit
operator enable_if_t<std::is_same<T, accessor_policies::generic_item>::value, bool>() const {
return obj.contains(key);
}
// NOLINTNEXTLINE(google-explicit-constructor)
operator object() const { return get_cache(); }
PyObject *ptr() const { return get_cache().ptr(); }
template <typename T> T cast() const { return get_cache().template cast<T>(); }
template <typename T>
T cast() const {
return get_cache().template cast<T>();
}
private:
object &get_cache() const {
if (!cache) { cache = Policy::get(obj, key); }
if (!cache) {
cache = Policy::get(obj, key);
}
return cache;
}
......@@ -650,7 +716,7 @@ private:
mutable object cache;
};
#if defined(_MSC_VER) && _MSC_VER < 1920
# pragma warning(pop)
# pragma warning(pop)
#endif
PYBIND11_NAMESPACE_BEGIN(accessor_policies)
......@@ -671,12 +737,16 @@ struct generic_item {
static object get(handle obj, handle key) {
PyObject *result = PyObject_GetItem(obj.ptr(), key.ptr());
if (!result) { throw error_already_set(); }
if (!result) {
throw error_already_set();
}
return reinterpret_steal<object>(result);
}
static void set(handle obj, handle key, handle val) {
if (PyObject_SetItem(obj.ptr(), key.ptr(), val.ptr()) != 0) { throw error_already_set(); }
if (PyObject_SetItem(obj.ptr(), key.ptr(), val.ptr()) != 0) {
throw error_already_set();
}
}
};
......@@ -686,7 +756,9 @@ struct sequence_item {
template <typename IdxType, detail::enable_if_t<std::is_integral<IdxType>::value, int> = 0>
static object get(handle obj, const IdxType &index) {
PyObject *result = PySequence_GetItem(obj.ptr(), ssize_t_cast(index));
if (!result) { throw error_already_set(); }
if (!result) {
throw error_already_set();
}
return reinterpret_steal<object>(result);
}
......@@ -705,7 +777,9 @@ struct list_item {
template <typename IdxType, detail::enable_if_t<std::is_integral<IdxType>::value, int> = 0>
static object get(handle obj, const IdxType &index) {
PyObject *result = PyList_GetItem(obj.ptr(), ssize_t_cast(index));
if (!result) { throw error_already_set(); }
if (!result) {
throw error_already_set();
}
return reinterpret_borrow<object>(result);
}
......@@ -724,7 +798,9 @@ struct tuple_item {
template <typename IdxType, detail::enable_if_t<std::is_integral<IdxType>::value, int> = 0>
static object get(handle obj, const IdxType &index) {
PyObject *result = PyTuple_GetItem(obj.ptr(), ssize_t_cast(index));
if (!result) { throw error_already_set(); }
if (!result) {
throw error_already_set();
}
return reinterpret_borrow<object>(result);
}
......@@ -751,7 +827,7 @@ public:
using pointer = typename Policy::pointer;
generic_iterator() = default;
generic_iterator(handle seq, ssize_t index) : Policy(seq, index) { }
generic_iterator(handle seq, ssize_t index) : Policy(seq, index) {}
// NOLINTNEXTLINE(readability-const-return-type) // PR #3263
reference operator*() const { return Policy::dereference(); }
......@@ -759,22 +835,48 @@ public:
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; }
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+(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 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 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); }
};
......@@ -786,7 +888,7 @@ struct arrow_proxy {
T value;
// NOLINTNEXTLINE(google-explicit-constructor)
arrow_proxy(T &&value) noexcept : value(std::move(value)) { }
arrow_proxy(T &&value) noexcept : value(std::move(value)) {}
T *operator->() const { return &value; }
};
......@@ -798,7 +900,7 @@ protected:
using reference = const handle; // PR #3263
using pointer = arrow_proxy<const handle>;
sequence_fast_readonly(handle obj, ssize_t n) : ptr(PySequence_Fast_ITEMS(obj.ptr()) + n) { }
sequence_fast_readonly(handle obj, ssize_t n) : ptr(PySequence_Fast_ITEMS(obj.ptr()) + n) {}
// NOLINTNEXTLINE(readability-const-return-type) // PR #3263
reference dereference() const { return *ptr; }
......@@ -820,7 +922,7 @@ protected:
using reference = sequence_accessor;
using pointer = arrow_proxy<const sequence_accessor>;
sequence_slow_readwrite(handle obj, ssize_t index) : obj(obj), index(index) { }
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; }
......@@ -886,33 +988,38 @@ inline bool PyNone_Check(PyObject *o) { return o == Py_None; }
inline bool PyEllipsis_Check(PyObject *o) { return o == Py_Ellipsis; }
#ifdef PYBIND11_STR_LEGACY_PERMISSIVE
inline bool PyUnicode_Check_Permissive(PyObject *o) { return PyUnicode_Check(o) || PYBIND11_BYTES_CHECK(o); }
#define PYBIND11_STR_CHECK_FUN detail::PyUnicode_Check_Permissive
inline bool PyUnicode_Check_Permissive(PyObject *o) {
return PyUnicode_Check(o) || PYBIND11_BYTES_CHECK(o);
}
# define PYBIND11_STR_CHECK_FUN detail::PyUnicode_Check_Permissive
#else
#define PYBIND11_STR_CHECK_FUN PyUnicode_Check
# define PYBIND11_STR_CHECK_FUN PyUnicode_Check
#endif
inline bool PyStaticMethod_Check(PyObject *o) { return o->ob_type == &PyStaticMethod_Type; }
class kwargs_proxy : public handle {
public:
explicit kwargs_proxy(handle h) : handle(h) { }
explicit kwargs_proxy(handle h) : handle(h) {}
};
class args_proxy : public handle {
public:
explicit args_proxy(handle h) : handle(h) { }
explicit args_proxy(handle h) : handle(h) {}
kwargs_proxy operator*() const { return kwargs_proxy(*this); }
};
/// Python argument categories (using PEP 448 terms)
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 = 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>;
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 = 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>
......@@ -926,53 +1033,60 @@ PYBIND11_NAMESPACE_END(detail)
// inheriting ctors: `using Parent::Parent`. It's not an option right now because
// the `using` statement triggers the parent deprecation warning even if the ctor
// isn't even used.
#define PYBIND11_OBJECT_COMMON(Name, Parent, CheckFun) \
public: \
PYBIND11_DEPRECATED("Use reinterpret_borrow<"#Name">() or reinterpret_steal<"#Name">()") \
Name(handle h, bool is_borrowed) : Parent(is_borrowed ? Parent(h, borrowed_t{}) : Parent(h, stolen_t{})) { } \
Name(handle h, borrowed_t) : Parent(h, borrowed_t{}) { } \
Name(handle h, stolen_t) : Parent(h, stolen_t{}) { } \
PYBIND11_DEPRECATED("Use py::isinstance<py::python_type>(obj) instead") \
bool check() const { return m_ptr != nullptr && (CheckFun(m_ptr) != 0); } \
static bool check_(handle h) { return h.ptr() != nullptr && CheckFun(h.ptr()); } \
template <typename Policy_> \
/* NOLINTNEXTLINE(google-explicit-constructor) */ \
Name(const ::pybind11::detail::accessor<Policy_> &a) : Name(object(a)) { }
#define PYBIND11_OBJECT_CVT(Name, Parent, CheckFun, ConvertFun) \
PYBIND11_OBJECT_COMMON(Name, Parent, CheckFun) \
/* This is deliberately not 'explicit' to allow implicit conversion from object: */ \
/* NOLINTNEXTLINE(google-explicit-constructor) */ \
Name(const object &o) \
: Parent(check_(o) ? o.inc_ref().ptr() : ConvertFun(o.ptr()), stolen_t{}) \
{ if (!m_ptr) throw error_already_set(); } \
/* NOLINTNEXTLINE(google-explicit-constructor) */ \
Name(object &&o) \
: Parent(check_(o) ? o.release().ptr() : ConvertFun(o.ptr()), stolen_t{}) \
{ if (!m_ptr) throw error_already_set(); }
#define PYBIND11_OBJECT_CVT_DEFAULT(Name, Parent, CheckFun, ConvertFun) \
PYBIND11_OBJECT_CVT(Name, Parent, CheckFun, ConvertFun) \
Name() : Parent() { }
#define PYBIND11_OBJECT_CHECK_FAILED(Name, o_ptr) \
::pybind11::type_error("Object of type '" + \
::pybind11::detail::get_fully_qualified_tp_name(Py_TYPE(o_ptr)) + \
"' is not an instance of '" #Name "'")
#define PYBIND11_OBJECT(Name, Parent, CheckFun) \
PYBIND11_OBJECT_COMMON(Name, Parent, CheckFun) \
/* This is deliberately not 'explicit' to allow implicit conversion from object: */ \
/* NOLINTNEXTLINE(google-explicit-constructor) */ \
Name(const object &o) : Parent(o) \
{ if (m_ptr && !check_(m_ptr)) throw PYBIND11_OBJECT_CHECK_FAILED(Name, m_ptr); } \
/* NOLINTNEXTLINE(google-explicit-constructor) */ \
Name(object &&o) : Parent(std::move(o)) \
{ if (m_ptr && !check_(m_ptr)) throw PYBIND11_OBJECT_CHECK_FAILED(Name, m_ptr); }
#define PYBIND11_OBJECT_DEFAULT(Name, Parent, CheckFun) \
PYBIND11_OBJECT(Name, Parent, CheckFun) \
Name() : Parent() { }
#define PYBIND11_OBJECT_COMMON(Name, Parent, CheckFun) \
public: \
PYBIND11_DEPRECATED("Use reinterpret_borrow<" #Name ">() or reinterpret_steal<" #Name ">()") \
Name(handle h, bool is_borrowed) \
: Parent(is_borrowed ? Parent(h, borrowed_t{}) : Parent(h, stolen_t{})) {} \
Name(handle h, borrowed_t) : Parent(h, borrowed_t{}) {} \
Name(handle h, stolen_t) : Parent(h, stolen_t{}) {} \
PYBIND11_DEPRECATED("Use py::isinstance<py::python_type>(obj) instead") \
bool check() const { return m_ptr != nullptr && (CheckFun(m_ptr) != 0); } \
static bool check_(handle h) { return h.ptr() != nullptr && CheckFun(h.ptr()); } \
template <typename Policy_> /* NOLINTNEXTLINE(google-explicit-constructor) */ \
Name(const ::pybind11::detail::accessor<Policy_> &a) : Name(object(a)) {}
#define PYBIND11_OBJECT_CVT(Name, Parent, CheckFun, ConvertFun) \
PYBIND11_OBJECT_COMMON(Name, Parent, CheckFun) \
/* This is deliberately not 'explicit' to allow implicit conversion from object: */ \
/* NOLINTNEXTLINE(google-explicit-constructor) */ \
Name(const object &o) \
: Parent(check_(o) ? o.inc_ref().ptr() : ConvertFun(o.ptr()), stolen_t{}) { \
if (!m_ptr) \
throw error_already_set(); \
} \
/* NOLINTNEXTLINE(google-explicit-constructor) */ \
Name(object &&o) : Parent(check_(o) ? o.release().ptr() : ConvertFun(o.ptr()), stolen_t{}) { \
if (!m_ptr) \
throw error_already_set(); \
}
#define PYBIND11_OBJECT_CVT_DEFAULT(Name, Parent, CheckFun, ConvertFun) \
PYBIND11_OBJECT_CVT(Name, Parent, CheckFun, ConvertFun) \
Name() : Parent() {}
#define PYBIND11_OBJECT_CHECK_FAILED(Name, o_ptr) \
::pybind11::type_error("Object of type '" \
+ ::pybind11::detail::get_fully_qualified_tp_name(Py_TYPE(o_ptr)) \
+ "' is not an instance of '" #Name "'")
#define PYBIND11_OBJECT(Name, Parent, CheckFun) \
PYBIND11_OBJECT_COMMON(Name, Parent, CheckFun) \
/* This is deliberately not 'explicit' to allow implicit conversion from object: */ \
/* NOLINTNEXTLINE(google-explicit-constructor) */ \
Name(const object &o) : Parent(o) { \
if (m_ptr && !check_(m_ptr)) \
throw PYBIND11_OBJECT_CHECK_FAILED(Name, m_ptr); \
} \
/* NOLINTNEXTLINE(google-explicit-constructor) */ \
Name(object &&o) : Parent(std::move(o)) { \
if (m_ptr && !check_(m_ptr)) \
throw PYBIND11_OBJECT_CHECK_FAILED(Name, m_ptr); \
}
#define PYBIND11_OBJECT_DEFAULT(Name, Parent, CheckFun) \
PYBIND11_OBJECT(Name, Parent, CheckFun) \
Name() : Parent() {}
/// \addtogroup pytypes
/// @{
......@@ -995,7 +1109,7 @@ public:
PYBIND11_OBJECT_DEFAULT(iterator, object, PyIter_Check)
iterator& operator++() {
iterator &operator++() {
advance();
return *this;
}
......@@ -1009,13 +1123,16 @@ public:
// NOLINTNEXTLINE(readability-const-return-type) // PR #3263
reference operator*() const {
if (m_ptr && !value.ptr()) {
auto& self = const_cast<iterator &>(*this);
auto &self = const_cast<iterator &>(*this);
self.advance();
}
return value;
}
pointer operator->() const { operator*(); return &value; }
pointer operator->() const {
operator*();
return &value;
}
/** \rst
The value which marks the end of the iteration. ``it == iterator::sentinel()``
......@@ -1038,21 +1155,21 @@ public:
private:
void advance() {
value = reinterpret_steal<object>(PyIter_Next(m_ptr));
if (PyErr_Occurred()) { throw error_already_set(); }
if (PyErr_Occurred()) {
throw error_already_set();
}
}
private:
object value = {};
};
class type : public object {
public:
PYBIND11_OBJECT(type, object, PyType_Check)
/// Return a type handle from a handle or an object
static handle handle_of(handle h) { return handle((PyObject*) Py_TYPE(h.ptr())); }
static handle handle_of(handle h) { return handle((PyObject *) Py_TYPE(h.ptr())); }
/// Return a type object from a handle or an object
static type of(handle h) { return type(type::handle_of(h), borrowed_t{}); }
......@@ -1061,14 +1178,16 @@ public:
/// Convert C++ type to handle if previously registered. Does not convert
/// standard types, like int, float. etc. yet.
/// See https://github.com/pybind/pybind11/issues/2486
template<typename T>
template <typename T>
static handle handle_of();
/// Convert C++ type to type if previously registered. Does not convert
/// standard types, like int, float. etc. yet.
/// See https://github.com/pybind/pybind11/issues/2486
template<typename T>
static type of() {return type(type::handle_of<T>(), borrowed_t{}); }
template <typename T>
static type of() {
return type(type::handle_of<T>(), borrowed_t{});
}
};
class iterable : public object {
......@@ -1090,29 +1209,29 @@ public:
}
}
// 'explicit' is explicitly omitted from the following constructors to allow implicit conversion to py::str from C++ string-like objects
// 'explicit' is explicitly omitted from the following constructors to allow implicit
// conversion to py::str from C++ string-like objects
// NOLINTNEXTLINE(google-explicit-constructor)
str(const char *c = "")
: object(PyUnicode_FromString(c), stolen_t{}) {
str(const char *c = "") : object(PyUnicode_FromString(c), stolen_t{}) {
if (!m_ptr) {
pybind11_fail("Could not allocate string object!");
}
}
// NOLINTNEXTLINE(google-explicit-constructor)
str(const std::string &s) : str(s.data(), s.size()) { }
str(const std::string &s) : str(s.data(), s.size()) {}
#ifdef PYBIND11_HAS_STRING_VIEW
// enable_if is needed to avoid "ambiguous conversion" errors (see PR #3521).
template <typename T, detail::enable_if_t<std::is_same<T, std::string_view>::value, int> = 0>
// NOLINTNEXTLINE(google-explicit-constructor)
str(T s) : str(s.data(), s.size()) { }
str(T s) : str(s.data(), s.size()) {}
# ifdef PYBIND11_HAS_U8STRING
# ifdef PYBIND11_HAS_U8STRING
// reinterpret_cast here is safe (C++20 guarantees char8_t has the same size/alignment as char)
// NOLINTNEXTLINE(google-explicit-constructor)
str(std::u8string_view s) : str(reinterpret_cast<const char*>(s.data()), s.size()) { }
# endif
str(std::u8string_view s) : str(reinterpret_cast<const char *>(s.data()), s.size()) {}
# endif
#endif
......@@ -1155,9 +1274,11 @@ private:
static PyObject *raw_str(PyObject *op) {
PyObject *str_value = PyObject_Str(op);
#if PY_MAJOR_VERSION < 3
if (!str_value) throw error_already_set();
if (!str_value)
throw error_already_set();
PyObject *unicode = PyUnicode_FromEncodedObject(str_value, "utf-8", nullptr);
Py_XDECREF(str_value); str_value = unicode;
Py_XDECREF(str_value);
str_value = unicode;
#endif
return str_value;
}
......@@ -1179,8 +1300,7 @@ public:
// Allow implicit conversion:
// NOLINTNEXTLINE(google-explicit-constructor)
bytes(const char *c = "")
: object(PYBIND11_BYTES_FROM_STRING(c), stolen_t{}) {
bytes(const char *c = "") : object(PYBIND11_BYTES_FROM_STRING(c), stolen_t{}) {
if (!m_ptr) {
pybind11_fail("Could not allocate bytes object!");
}
......@@ -1196,7 +1316,7 @@ public:
// Allow implicit conversion:
// NOLINTNEXTLINE(google-explicit-constructor)
bytes(const std::string &s) : bytes(s.data(), s.size()) { }
bytes(const std::string &s) : bytes(s.data(), s.size()) {}
explicit bytes(const pybind11::str &s);
......@@ -1214,7 +1334,7 @@ public:
// enable_if is needed to avoid "ambiguous conversion" errors (see PR #3521).
template <typename T, detail::enable_if_t<std::is_same<T, std::string_view>::value, int> = 0>
// NOLINTNEXTLINE(google-explicit-constructor)
bytes(T s) : bytes(s.data(), s.size()) { }
bytes(T s) : bytes(s.data(), s.size()) {}
// Obtain a string view that views the current `bytes` buffer value. Note that this is only
// valid so long as the `bytes` instance remains alive and so generally should not outlive the
......@@ -1229,7 +1349,6 @@ public:
return {buffer, static_cast<size_t>(length)};
}
#endif
};
// Note: breathe >= 4.17.0 will fail to build docs if the below two constructors
// are included in the doxygen group; close here and reopen after as a workaround
......@@ -1255,7 +1374,7 @@ inline bytes::bytes(const pybind11::str &s) {
m_ptr = obj.release().ptr();
}
inline str::str(const bytes& b) {
inline str::str(const bytes &b) {
char *buffer = nullptr;
ssize_t length = 0;
if (PYBIND11_BYTES_AS_STRING_AND_SIZE(b.ptr(), &buffer, &length)) {
......@@ -1282,10 +1401,9 @@ public:
}
}
bytearray()
: bytearray("", 0) {}
bytearray() : bytearray("", 0) {}
explicit bytearray(const std::string &s) : bytearray(s.data(), s.size()) { }
explicit bytearray(const std::string &s) : bytearray(s.data(), s.size()) {}
size_t size() const { return static_cast<size_t>(PyByteArray_Size(m_ptr)); }
......@@ -1304,22 +1422,22 @@ public:
class none : public object {
public:
PYBIND11_OBJECT(none, object, detail::PyNone_Check)
none() : object(Py_None, borrowed_t{}) { }
none() : object(Py_None, borrowed_t{}) {}
};
class ellipsis : public object {
public:
PYBIND11_OBJECT(ellipsis, object, detail::PyEllipsis_Check)
ellipsis() : object(Py_Ellipsis, borrowed_t{}) { }
ellipsis() : object(Py_Ellipsis, borrowed_t{}) {}
};
class bool_ : public object {
public:
PYBIND11_OBJECT_CVT(bool_, object, PyBool_Check, raw_bool)
bool_() : object(Py_False, borrowed_t{}) { }
bool_() : object(Py_False, borrowed_t{}) {}
// Allow implicit conversion from and to `bool`:
// NOLINTNEXTLINE(google-explicit-constructor)
bool_(bool value) : object(value ? Py_True : Py_False, borrowed_t{}) { }
bool_(bool value) : object(value ? Py_True : Py_False, borrowed_t{}) {}
// NOLINTNEXTLINE(google-explicit-constructor)
operator bool() const { return (m_ptr != nullptr) && PyLong_AsLong(m_ptr) != 0; }
......@@ -1357,10 +1475,9 @@ PYBIND11_NAMESPACE_END(detail)
class int_ : public object {
public:
PYBIND11_OBJECT_CVT(int_, object, PYBIND11_LONG_CHECK, PyNumber_Long)
int_() : object(PyLong_FromLong(0), stolen_t{}) { }
int_() : object(PyLong_FromLong(0), stolen_t{}) {}
// Allow implicit conversion from C++ integral types:
template <typename T,
detail::enable_if_t<std::is_integral<T>::value, int> = 0>
template <typename T, detail::enable_if_t<std::is_integral<T>::value, int> = 0>
// NOLINTNEXTLINE(google-explicit-constructor)
int_(T value) {
if (PYBIND11_SILENCE_MSVC_C4127(sizeof(T) <= sizeof(long))) {
......@@ -1381,15 +1498,12 @@ public:
}
}
template <typename T,
detail::enable_if_t<std::is_integral<T>::value, int> = 0>
template <typename T, detail::enable_if_t<std::is_integral<T>::value, int> = 0>
// NOLINTNEXTLINE(google-explicit-constructor)
operator T() const {
return std::is_unsigned<T>::value
? detail::as_unsigned<T>(m_ptr)
: sizeof(T) <= sizeof(long)
? (T) PyLong_AsLong(m_ptr)
: (T) PYBIND11_LONG_AS_LONGLONG(m_ptr);
return std::is_unsigned<T>::value ? detail::as_unsigned<T>(m_ptr)
: sizeof(T) <= sizeof(long) ? (T) PyLong_AsLong(m_ptr)
: (T) PYBIND11_LONG_AS_LONGLONG(m_ptr);
}
};
......@@ -1426,9 +1540,7 @@ public:
}
private:
static PyObject *raw_weakref(PyObject *o) {
return PyWeakref_NewRef(o, nullptr);
}
static PyObject *raw_weakref(PyObject *o) { return PyWeakref_NewRef(o, nullptr); }
};
class slice : public object {
......@@ -1449,19 +1561,21 @@ public:
: slice(int_(start_), int_(stop_), int_(step_)) {}
#endif
bool compute(size_t length, size_t *start, size_t *stop, size_t *step,
size_t *slicelength) const {
bool
compute(size_t length, size_t *start, size_t *stop, size_t *step, size_t *slicelength) const {
return PySlice_GetIndicesEx((PYBIND11_SLICE_OBJECT *) m_ptr,
(ssize_t) length, (ssize_t *) start,
(ssize_t *) stop, (ssize_t *) step,
(ssize_t *) slicelength) == 0;
(ssize_t) length,
(ssize_t *) start,
(ssize_t *) stop,
(ssize_t *) step,
(ssize_t *) slicelength)
== 0;
}
bool compute(ssize_t length, ssize_t *start, ssize_t *stop, ssize_t *step,
ssize_t *slicelength) const {
return PySlice_GetIndicesEx((PYBIND11_SLICE_OBJECT *) m_ptr,
length, start,
stop, step,
slicelength) == 0;
bool compute(
ssize_t length, ssize_t *start, ssize_t *stop, ssize_t *step, ssize_t *slicelength) const {
return PySlice_GetIndicesEx(
(PYBIND11_SLICE_OBJECT *) m_ptr, length, start, stop, step, slicelength)
== 0;
}
private:
......@@ -1475,9 +1589,12 @@ class capsule : public object {
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_t{}) : object(ptr, stolen_t{})) { }
capsule(PyObject *ptr, bool is_borrowed)
: object(is_borrowed ? object(ptr, borrowed_t{}) : object(ptr, stolen_t{})) {}
explicit capsule(const void *value, const char *name = nullptr, void (*destructor)(PyObject *) = nullptr)
explicit capsule(const void *value,
const char *name = nullptr,
void (*destructor)(PyObject *) = nullptr)
: object(PyCapsule_New(const_cast<void *>(value), name, destructor), stolen_t{}) {
if (!m_ptr) {
pybind11_fail("Could not allocate capsule object!");
......@@ -1486,7 +1603,7 @@ public:
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_t{}) {
: object(PyCapsule_New(const_cast<void *>(value), nullptr, destruct), stolen_t{}) {
if (!m_ptr) {
pybind11_fail("Could not allocate capsule object!");
}
......@@ -1525,8 +1642,8 @@ public:
}
/// Get the pointer the capsule holds.
template<typename T = void>
T* get_pointer() const {
template <typename T = void>
T *get_pointer() const {
const auto *name = this->name();
T *result = static_cast<T *>(PyCapsule_GetPointer(m_ptr, name));
if (!result) {
......@@ -1570,9 +1687,8 @@ public:
// fails to compile enable_if_t<all_of<is_keyword_or_ds<Args>...>::value> part below
// (tested with ICC 2021.1 Beta 20200827).
template <typename... Args>
constexpr bool args_are_all_keyword_or_ds()
{
return detail::all_of<detail::is_keyword_or_ds<Args>...>::value;
constexpr bool args_are_all_keyword_or_ds() {
return detail::all_of<detail::is_keyword_or_ds<Args>...>::value;
}
class dict : public object {
......@@ -1585,16 +1701,18 @@ public:
}
template <typename... Args,
typename = detail::enable_if_t<args_are_all_keyword_or_ds<Args...>()>,
// MSVC workaround: it can't compile an out-of-line definition, so defer the collector
// 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()) { }
explicit dict(Args &&...args) : dict(collector(std::forward<Args>(args)...).kwargs()) {}
size_t size() const { return (size_t) PyDict_Size(m_ptr); }
bool empty() const { return size() == 0; }
detail::dict_iterator begin() const { return {*this, 0}; }
detail::dict_iterator end() const { return {}; }
void clear() /* py-non-const */ { PyDict_Clear(ptr()); }
template <typename T> bool contains(T &&key) const {
template <typename T>
bool contains(T &&key) const {
return PyDict_Contains(m_ptr, detail::object_or_cast(std::forward<T>(key)).ptr()) == 1;
}
......@@ -1642,7 +1760,8 @@ public:
detail::item_accessor operator[](handle h) const { return object::operator[](h); }
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) /* py-non-const */ {
template <typename T>
void append(T &&val) /* py-non-const */ {
PyList_Append(m_ptr, detail::object_or_cast(std::forward<T>(val)).ptr());
}
template <typename IdxType,
......@@ -1654,8 +1773,12 @@ public:
}
};
class args : public tuple { PYBIND11_OBJECT_DEFAULT(args, tuple, PyTuple_Check) };
class kwargs : public dict { PYBIND11_OBJECT_DEFAULT(kwargs, dict, PyDict_Check) };
class args : public tuple {
PYBIND11_OBJECT_DEFAULT(args, tuple, PyTuple_Check)
};
class kwargs : public dict {
PYBIND11_OBJECT_DEFAULT(kwargs, dict, PyDict_Check)
};
class set : public object {
public:
......@@ -1667,11 +1790,13 @@ public:
}
size_t size() const { return (size_t) PySet_Size(m_ptr); }
bool empty() const { return size() == 0; }
template <typename T> bool add(T &&val) /* py-non-const */ {
template <typename T>
bool add(T &&val) /* py-non-const */ {
return PySet_Add(m_ptr, detail::object_or_cast(std::forward<T>(val)).ptr()) == 0;
}
void clear() /* py-non-const */ { PySet_Clear(m_ptr); }
template <typename T> bool contains(T &&val) const {
template <typename T>
bool contains(T &&val) const {
return PySet_Contains(m_ptr, detail::object_or_cast(std::forward<T>(val)).ptr()) == 1;
}
};
......@@ -1725,14 +1850,13 @@ public:
For creating a ``memoryview`` from objects that support buffer protocol,
use ``memoryview(const object& obj)`` instead of this constructor.
\endrst */
explicit memoryview(const buffer_info& info) {
explicit memoryview(const buffer_info &info) {
if (!info.view()) {
pybind11_fail("Prohibited to create memoryview without Py_buffer");
}
// Note: PyMemoryView_FromBuffer never increments obj reference.
m_ptr = (info.view()->obj) ?
PyMemoryView_FromObject(info.view()->obj) :
PyMemoryView_FromBuffer(info.view());
m_ptr = (info.view()->obj) ? PyMemoryView_FromObject(info.view()->obj)
: PyMemoryView_FromBuffer(info.view());
if (!m_ptr) {
pybind11_fail("Unable to create memoryview from buffer descriptor");
}
......@@ -1762,34 +1886,40 @@ public:
:param readonly: Flag to indicate if the underlying storage may be
written to.
\endrst */
static memoryview from_buffer(
void *ptr, ssize_t itemsize, const char *format,
detail::any_container<ssize_t> shape,
detail::any_container<ssize_t> strides, bool readonly = false);
static memoryview from_buffer(
const void *ptr, ssize_t itemsize, const char *format,
detail::any_container<ssize_t> shape,
detail::any_container<ssize_t> strides) {
static memoryview from_buffer(void *ptr,
ssize_t itemsize,
const char *format,
detail::any_container<ssize_t> shape,
detail::any_container<ssize_t> strides,
bool readonly = false);
static memoryview from_buffer(const void *ptr,
ssize_t itemsize,
const char *format,
detail::any_container<ssize_t> shape,
detail::any_container<ssize_t> strides) {
return memoryview::from_buffer(
const_cast<void *>(ptr), itemsize, format, std::move(shape), std::move(strides), true);
}
template<typename T>
static memoryview from_buffer(
T *ptr, detail::any_container<ssize_t> shape,
detail::any_container<ssize_t> strides, bool readonly = false) {
return memoryview::from_buffer(
reinterpret_cast<void*>(ptr), sizeof(T),
format_descriptor<T>::value, shape, strides, readonly);
template <typename T>
static memoryview from_buffer(T *ptr,
detail::any_container<ssize_t> shape,
detail::any_container<ssize_t> strides,
bool readonly = false) {
return memoryview::from_buffer(reinterpret_cast<void *>(ptr),
sizeof(T),
format_descriptor<T>::value,
shape,
strides,
readonly);
}
template<typename T>
static memoryview from_buffer(
const T *ptr, detail::any_container<ssize_t> shape,
detail::any_container<ssize_t> strides) {
return memoryview::from_buffer(
const_cast<T*>(ptr), shape, strides, true);
template <typename T>
static memoryview from_buffer(const T *ptr,
detail::any_container<ssize_t> shape,
detail::any_container<ssize_t> strides) {
return memoryview::from_buffer(const_cast<T *>(ptr), shape, strides, true);
}
#if PY_MAJOR_VERSION >= 3
......@@ -1808,9 +1938,8 @@ public:
https://docs.python.org/c-api/memoryview.html#c.PyMemoryView_FromMemory
\endrst */
static memoryview from_memory(void *mem, ssize_t size, bool readonly = false) {
PyObject* ptr = PyMemoryView_FromMemory(
reinterpret_cast<char*>(mem), size,
(readonly) ? PyBUF_READ : PyBUF_WRITE);
PyObject *ptr = PyMemoryView_FromMemory(
reinterpret_cast<char *>(mem), size, (readonly) ? PyBUF_READ : PyBUF_WRITE);
if (!ptr) {
pybind11_fail("Could not allocate memoryview object!");
}
......@@ -1818,23 +1947,25 @@ public:
}
static memoryview from_memory(const void *mem, ssize_t size) {
return memoryview::from_memory(const_cast<void*>(mem), size, true);
return memoryview::from_memory(const_cast<void *>(mem), size, true);
}
#ifdef PYBIND11_HAS_STRING_VIEW
# ifdef PYBIND11_HAS_STRING_VIEW
static memoryview from_memory(std::string_view mem) {
return from_memory(const_cast<char*>(mem.data()), static_cast<ssize_t>(mem.size()), true);
return from_memory(const_cast<char *>(mem.data()), static_cast<ssize_t>(mem.size()), true);
}
#endif
# endif
#endif
};
/// @cond DUPLICATE
inline memoryview memoryview::from_buffer(
void *ptr, ssize_t itemsize, const char* format,
detail::any_container<ssize_t> shape,
detail::any_container<ssize_t> strides, bool readonly) {
inline memoryview memoryview::from_buffer(void *ptr,
ssize_t itemsize,
const char *format,
detail::any_container<ssize_t> shape,
detail::any_container<ssize_t> strides,
bool readonly) {
size_t ndim = shape->size();
if (ndim != strides->size()) {
pybind11_fail("memoryview: shape length doesn't match strides length");
......@@ -1849,13 +1980,13 @@ inline memoryview memoryview::from_buffer(
view.len = size * itemsize;
view.readonly = static_cast<int>(readonly);
view.itemsize = itemsize;
view.format = const_cast<char*>(format);
view.format = const_cast<char *>(format);
view.ndim = static_cast<int>(ndim);
view.shape = shape->data();
view.strides = strides->data();
view.suboffsets = nullptr;
view.internal = nullptr;
PyObject* obj = PyMemoryView_FromBuffer(&view);
PyObject *obj = PyMemoryView_FromBuffer(&view);
if (!obj) {
throw error_already_set();
}
......@@ -1900,49 +2031,72 @@ inline str repr(handle h) {
}
#if PY_MAJOR_VERSION < 3
PyObject *unicode = PyUnicode_FromEncodedObject(str_value, "utf-8", nullptr);
Py_XDECREF(str_value); str_value = unicode;
if (!str_value) throw error_already_set();
Py_XDECREF(str_value);
str_value = unicode;
if (!str_value)
throw error_already_set();
#endif
return reinterpret_steal<str>(str_value);
}
inline iterator iter(handle obj) {
PyObject *result = PyObject_GetIter(obj.ptr());
if (!result) { throw error_already_set(); }
if (!result) {
throw error_already_set();
}
return reinterpret_steal<iterator>(result);
}
/// @} python_builtins
PYBIND11_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 {
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)};
}
template <typename D> item_accessor object_api<D>::operator[](const char *key) const {
template <typename D>
item_accessor object_api<D>::operator[](const char *key) const {
return {derived(), pybind11::str(key)};
}
template <typename D> obj_attr_accessor object_api<D>::attr(handle key) const {
template <typename D>
obj_attr_accessor object_api<D>::attr(handle key) const {
return {derived(), reinterpret_borrow<object>(key)};
}
template <typename D> str_attr_accessor object_api<D>::attr(const char *key) const {
template <typename D>
str_attr_accessor object_api<D>::attr(const char *key) const {
return {derived(), key};
}
template <typename D> args_proxy object_api<D>::operator*() const {
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 &&item) const {
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>
pybind11::str object_api<D>::str() const { return pybind11::str(derived()); }
pybind11::str object_api<D>::str() const {
return pybind11::str(derived());
}
template <typename D>
str_attr_accessor object_api<D>::doc() const { return attr("__doc__"); }
str_attr_accessor object_api<D>::doc() const {
return attr("__doc__");
}
template <typename D>
handle object_api<D>::get_type() const { return type::handle_of(derived()); }
handle object_api<D>::get_type() const {
return type::handle_of(derived());
}
template <typename D>
bool object_api<D>::rich_compare(object_api const &other, int value) const {
......@@ -1953,43 +2107,43 @@ bool object_api<D>::rich_compare(object_api const &other, int value) const {
return rv == 1;
}
#define PYBIND11_MATH_OPERATOR_UNARY(op, fn) \
template <typename D> object object_api<D>::op() const { \
object result = reinterpret_steal<object>(fn(derived().ptr())); \
if (!result.ptr()) \
throw error_already_set(); \
return result; \
}
#define PYBIND11_MATH_OPERATOR_BINARY(op, fn) \
template <typename D> \
object object_api<D>::op(object_api const &other) const { \
object result = reinterpret_steal<object>( \
fn(derived().ptr(), other.derived().ptr())); \
if (!result.ptr()) \
throw error_already_set(); \
return result; \
}
PYBIND11_MATH_OPERATOR_UNARY (operator~, PyNumber_Invert)
PYBIND11_MATH_OPERATOR_UNARY (operator-, PyNumber_Negative)
PYBIND11_MATH_OPERATOR_BINARY(operator+, PyNumber_Add)
PYBIND11_MATH_OPERATOR_BINARY(operator+=, PyNumber_InPlaceAdd)
PYBIND11_MATH_OPERATOR_BINARY(operator-, PyNumber_Subtract)
PYBIND11_MATH_OPERATOR_BINARY(operator-=, PyNumber_InPlaceSubtract)
PYBIND11_MATH_OPERATOR_BINARY(operator*, PyNumber_Multiply)
PYBIND11_MATH_OPERATOR_BINARY(operator*=, PyNumber_InPlaceMultiply)
PYBIND11_MATH_OPERATOR_BINARY(operator/, PyNumber_TrueDivide)
PYBIND11_MATH_OPERATOR_BINARY(operator/=, PyNumber_InPlaceTrueDivide)
PYBIND11_MATH_OPERATOR_BINARY(operator|, PyNumber_Or)
PYBIND11_MATH_OPERATOR_BINARY(operator|=, PyNumber_InPlaceOr)
PYBIND11_MATH_OPERATOR_BINARY(operator&, PyNumber_And)
PYBIND11_MATH_OPERATOR_BINARY(operator&=, PyNumber_InPlaceAnd)
PYBIND11_MATH_OPERATOR_BINARY(operator^, PyNumber_Xor)
PYBIND11_MATH_OPERATOR_BINARY(operator^=, PyNumber_InPlaceXor)
PYBIND11_MATH_OPERATOR_BINARY(operator<<, PyNumber_Lshift)
#define PYBIND11_MATH_OPERATOR_UNARY(op, fn) \
template <typename D> \
object object_api<D>::op() const { \
object result = reinterpret_steal<object>(fn(derived().ptr())); \
if (!result.ptr()) \
throw error_already_set(); \
return result; \
}
#define PYBIND11_MATH_OPERATOR_BINARY(op, fn) \
template <typename D> \
object object_api<D>::op(object_api const &other) const { \
object result = reinterpret_steal<object>(fn(derived().ptr(), other.derived().ptr())); \
if (!result.ptr()) \
throw error_already_set(); \
return result; \
}
PYBIND11_MATH_OPERATOR_UNARY(operator~, PyNumber_Invert)
PYBIND11_MATH_OPERATOR_UNARY(operator-, PyNumber_Negative)
PYBIND11_MATH_OPERATOR_BINARY(operator+, PyNumber_Add)
PYBIND11_MATH_OPERATOR_BINARY(operator+=, PyNumber_InPlaceAdd)
PYBIND11_MATH_OPERATOR_BINARY(operator-, PyNumber_Subtract)
PYBIND11_MATH_OPERATOR_BINARY(operator-=, PyNumber_InPlaceSubtract)
PYBIND11_MATH_OPERATOR_BINARY(operator*, PyNumber_Multiply)
PYBIND11_MATH_OPERATOR_BINARY(operator*=, PyNumber_InPlaceMultiply)
PYBIND11_MATH_OPERATOR_BINARY(operator/, PyNumber_TrueDivide)
PYBIND11_MATH_OPERATOR_BINARY(operator/=, PyNumber_InPlaceTrueDivide)
PYBIND11_MATH_OPERATOR_BINARY(operator|, PyNumber_Or)
PYBIND11_MATH_OPERATOR_BINARY(operator|=, PyNumber_InPlaceOr)
PYBIND11_MATH_OPERATOR_BINARY(operator&, PyNumber_And)
PYBIND11_MATH_OPERATOR_BINARY(operator&=, PyNumber_InPlaceAnd)
PYBIND11_MATH_OPERATOR_BINARY(operator^, PyNumber_Xor)
PYBIND11_MATH_OPERATOR_BINARY(operator^=, PyNumber_InPlaceXor)
PYBIND11_MATH_OPERATOR_BINARY(operator<<, PyNumber_Lshift)
PYBIND11_MATH_OPERATOR_BINARY(operator<<=, PyNumber_InPlaceLshift)
PYBIND11_MATH_OPERATOR_BINARY(operator>>, PyNumber_Rshift)
PYBIND11_MATH_OPERATOR_BINARY(operator>>, PyNumber_Rshift)
PYBIND11_MATH_OPERATOR_BINARY(operator>>=, PyNumber_InPlaceRshift)
#undef PYBIND11_MATH_OPERATOR_UNARY
......
......@@ -9,26 +9,27 @@
#pragma once
#include "detail/common.h"
#include "pybind11.h"
#include <set>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include "detail/common.h"
#include <deque>
#include <iostream>
#include <list>
#include <deque>
#include <map>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <valarray>
// See `detail/common.h` for implementation of these guards.
#if defined(PYBIND11_HAS_OPTIONAL)
# include <optional>
# include <optional>
#elif defined(PYBIND11_HAS_EXP_OPTIONAL)
# include <experimental/optional>
# include <experimental/optional>
#endif
#if defined(PYBIND11_HAS_VARIANT)
# include <variant>
# include <variant>
#endif
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
......@@ -37,8 +38,9 @@ PYBIND11_NAMESPACE_BEGIN(detail)
/// Extracts an const lvalue reference or rvalue reference for U based on the type of T (e.g. for
/// forwarding a container element). Typically used indirect via forwarded_type(), below.
template <typename T, typename U>
using forwarded_type = conditional_t<
std::is_lvalue_reference<T>::value, remove_reference_t<U> &, remove_reference_t<U> &&>;
using forwarded_type = conditional_t<std::is_lvalue_reference<T>::value,
remove_reference_t<U> &,
remove_reference_t<U> &&>;
/// Forwards a value U as rvalue or lvalue according to whether T is rvalue or lvalue; typically
/// used for forwarding a container's elements.
......@@ -47,7 +49,8 @@ forwarded_type<T, U> forward_like(U &&u) {
return std::forward<detail::forwarded_type<T, U>>(std::forward<U>(u));
}
template <typename Type, typename Key> struct set_caster {
template <typename Type, typename Key>
struct set_caster {
using type = Type;
using key_conv = make_caster<Key>;
......@@ -74,7 +77,8 @@ template <typename Type, typename Key> struct set_caster {
}
pybind11::set s;
for (auto &&value : src) {
auto value_ = reinterpret_steal<object>(key_conv::cast(forward_like<T>(value), policy, parent));
auto value_ = reinterpret_steal<object>(
key_conv::cast(forward_like<T>(value), policy, parent));
if (!value_ || !s.add(value_)) {
return handle();
}
......@@ -85,8 +89,9 @@ template <typename Type, typename Key> struct set_caster {
PYBIND11_TYPE_CASTER(type, const_name("Set[") + key_conv::name + const_name("]"));
};
template <typename Type, typename Key, typename Value> struct map_caster {
using key_conv = make_caster<Key>;
template <typename Type, typename Key, typename Value>
struct map_caster {
using key_conv = make_caster<Key>;
using value_conv = make_caster<Value>;
bool load(handle src, bool convert) {
......@@ -116,8 +121,10 @@ template <typename Type, typename Key, typename Value> struct map_caster {
policy_value = return_value_policy_override<Value>::policy(policy_value);
}
for (auto &&kv : src) {
auto key = reinterpret_steal<object>(key_conv::cast(forward_like<T>(kv.first), policy_key, parent));
auto value = reinterpret_steal<object>(value_conv::cast(forward_like<T>(kv.second), policy_value, parent));
auto key = reinterpret_steal<object>(
key_conv::cast(forward_like<T>(kv.first), policy_key, parent));
auto value = reinterpret_steal<object>(
value_conv::cast(forward_like<T>(kv.second), policy_value, parent));
if (!key || !value) {
return handle();
}
......@@ -126,10 +133,13 @@ template <typename Type, typename Key, typename Value> struct map_caster {
return d.release();
}
PYBIND11_TYPE_CASTER(Type, const_name("Dict[") + key_conv::name + const_name(", ") + value_conv::name + const_name("]"));
PYBIND11_TYPE_CASTER(Type,
const_name("Dict[") + key_conv::name + const_name(", ") + value_conv::name
+ const_name("]"));
};
template <typename Type, typename Value> struct list_caster {
template <typename Type, typename Value>
struct list_caster {
using value_conv = make_caster<Value>;
bool load(handle src, bool convert) {
......@@ -151,7 +161,7 @@ template <typename Type, typename Value> struct list_caster {
private:
template <
typename T = Type,
typename T = Type,
enable_if_t<std::is_same<decltype(std::declval<T>().reserve(0)), void>::value, int> = 0>
void reserve_maybe(const sequence &s, Type *) {
value.reserve(s.size());
......@@ -167,7 +177,8 @@ public:
list l(src.size());
ssize_t index = 0;
for (auto &&value : src) {
auto value_ = reinterpret_steal<object>(value_conv::cast(forward_like<T>(value), policy, parent));
auto value_ = reinterpret_steal<object>(
value_conv::cast(forward_like<T>(value), policy, parent));
if (!value_) {
return handle();
}
......@@ -179,16 +190,17 @@ public:
PYBIND11_TYPE_CASTER(Type, const_name("List[") + value_conv::name + const_name("]"));
};
template <typename Type, typename Alloc> struct type_caster<std::vector<Type, Alloc>>
: list_caster<std::vector<Type, Alloc>, Type> { };
template <typename Type, typename Alloc>
struct type_caster<std::vector<Type, Alloc>> : list_caster<std::vector<Type, Alloc>, Type> {};
template <typename Type, typename Alloc> struct type_caster<std::deque<Type, Alloc>>
: list_caster<std::deque<Type, Alloc>, Type> { };
template <typename Type, typename Alloc>
struct type_caster<std::deque<Type, Alloc>> : list_caster<std::deque<Type, Alloc>, Type> {};
template <typename Type, typename Alloc> struct type_caster<std::list<Type, Alloc>>
: list_caster<std::list<Type, Alloc>, Type> { };
template <typename Type, typename Alloc>
struct type_caster<std::list<Type, Alloc>> : list_caster<std::list<Type, Alloc>, Type> {};
template <typename ArrayType, typename Value, bool Resizable, size_t Size = 0> struct array_caster {
template <typename ArrayType, typename Value, bool Resizable, size_t Size = 0>
struct array_caster {
using value_conv = make_caster<Value>;
private:
......@@ -229,7 +241,8 @@ public:
list l(src.size());
ssize_t index = 0;
for (auto &&value : src) {
auto value_ = reinterpret_steal<object>(value_conv::cast(forward_like<T>(value), policy, parent));
auto value_ = reinterpret_steal<object>(
value_conv::cast(forward_like<T>(value), policy, parent));
if (!value_) {
return handle();
}
......@@ -238,29 +251,40 @@ public:
return l.release();
}
PYBIND11_TYPE_CASTER(ArrayType, const_name("List[") + value_conv::name + const_name<Resizable>(const_name(""), const_name("[") + const_name<Size>() + const_name("]")) + const_name("]"));
PYBIND11_TYPE_CASTER(ArrayType,
const_name("List[") + value_conv::name
+ const_name<Resizable>(const_name(""),
const_name("[") + const_name<Size>()
+ const_name("]"))
+ const_name("]"));
};
template <typename Type, size_t Size> struct type_caster<std::array<Type, Size>>
: array_caster<std::array<Type, Size>, Type, false, Size> { };
template <typename Type, size_t Size>
struct type_caster<std::array<Type, Size>>
: array_caster<std::array<Type, Size>, Type, false, Size> {};
template <typename Type> struct type_caster<std::valarray<Type>>
: array_caster<std::valarray<Type>, Type, true> { };
template <typename Type>
struct type_caster<std::valarray<Type>> : array_caster<std::valarray<Type>, Type, true> {};
template <typename Key, typename Compare, typename Alloc> struct type_caster<std::set<Key, Compare, Alloc>>
: set_caster<std::set<Key, Compare, Alloc>, Key> { };
template <typename Key, typename Compare, typename Alloc>
struct type_caster<std::set<Key, Compare, Alloc>>
: set_caster<std::set<Key, Compare, Alloc>, Key> {};
template <typename Key, typename Hash, typename Equal, typename Alloc> struct type_caster<std::unordered_set<Key, Hash, Equal, Alloc>>
: set_caster<std::unordered_set<Key, Hash, Equal, Alloc>, Key> { };
template <typename Key, typename Hash, typename Equal, typename Alloc>
struct type_caster<std::unordered_set<Key, Hash, Equal, Alloc>>
: set_caster<std::unordered_set<Key, Hash, Equal, Alloc>, Key> {};
template <typename Key, typename Value, typename Compare, typename Alloc> struct type_caster<std::map<Key, Value, Compare, Alloc>>
: map_caster<std::map<Key, Value, Compare, Alloc>, Key, Value> { };
template <typename Key, typename Value, typename Compare, typename Alloc>
struct type_caster<std::map<Key, Value, Compare, Alloc>>
: map_caster<std::map<Key, Value, Compare, Alloc>, Key, Value> {};
template <typename Key, typename Value, typename Hash, typename Equal, typename Alloc> struct type_caster<std::unordered_map<Key, Value, Hash, Equal, Alloc>>
: map_caster<std::unordered_map<Key, Value, Hash, Equal, Alloc>, Key, Value> { };
template <typename Key, typename Value, typename Hash, typename Equal, typename Alloc>
struct type_caster<std::unordered_map<Key, Value, Hash, Equal, Alloc>>
: map_caster<std::unordered_map<Key, Value, Hash, Equal, Alloc>, Key, Value> {};
// This type caster is intended to be used for std::optional and std::experimental::optional
template<typename Type, typename Value = typename Type::value_type> struct optional_caster {
template <typename Type, typename Value = typename Type::value_type>
struct optional_caster {
using value_conv = make_caster<Value>;
template <typename T>
......@@ -279,7 +303,7 @@ template<typename Type, typename Value = typename Type::value_type> struct optio
return false;
}
if (src.is_none()) {
return true; // default-constructed value is already empty
return true; // default-constructed value is already empty
}
value_conv inner_caster;
if (!inner_caster.load(src, convert)) {
......@@ -294,18 +318,20 @@ template<typename Type, typename Value = typename Type::value_type> struct optio
};
#if defined(PYBIND11_HAS_OPTIONAL)
template<typename T> struct type_caster<std::optional<T>>
: public optional_caster<std::optional<T>> {};
template <typename T>
struct type_caster<std::optional<T>> : public optional_caster<std::optional<T>> {};
template<> struct type_caster<std::nullopt_t>
: public void_caster<std::nullopt_t> {};
template <>
struct type_caster<std::nullopt_t> : public void_caster<std::nullopt_t> {};
#endif
#if defined(PYBIND11_HAS_EXP_OPTIONAL)
template<typename T> struct type_caster<std::experimental::optional<T>>
template <typename T>
struct type_caster<std::experimental::optional<T>>
: public optional_caster<std::experimental::optional<T>> {};
template<> struct type_caster<std::experimental::nullopt_t>
template <>
struct type_caster<std::experimental::nullopt_t>
: public void_caster<std::experimental::nullopt_t> {};
#endif
......@@ -326,7 +352,7 @@ struct variant_caster_visitor {
/// `namespace::variant` types which provide a `namespace::visit()` function are handled here
/// automatically using argument-dependent lookup. Users can provide specializations for other
/// variant-like classes, e.g. `boost::variant` and `boost::apply_visitor`.
template <template<typename...> class Variant>
template <template <typename...> class Variant>
struct visit_helper {
template <typename... Args>
static auto call(Args &&...args) -> decltype(visit(std::forward<Args>(args)...)) {
......@@ -335,9 +361,10 @@ struct visit_helper {
};
/// Generic variant caster
template <typename Variant> struct variant_caster;
template <typename Variant>
struct variant_caster;
template <template<typename...> class V, typename... Ts>
template <template <typename...> class V, typename... Ts>
struct variant_caster<V<Ts...>> {
static_assert(sizeof...(Ts) > 0, "Variant must consist of at least one alternative.");
......@@ -371,12 +398,14 @@ struct variant_caster<V<Ts...>> {
}
using Type = V<Ts...>;
PYBIND11_TYPE_CASTER(Type, const_name("Union[") + detail::concat(make_caster<Ts>::name...) + const_name("]"));
PYBIND11_TYPE_CASTER(Type,
const_name("Union[") + detail::concat(make_caster<Ts>::name...)
+ const_name("]"));
};
#if defined(PYBIND11_HAS_VARIANT)
template <typename... Ts>
struct type_caster<std::variant<Ts...>> : variant_caster<std::variant<Ts...>> { };
struct type_caster<std::variant<Ts...>> : variant_caster<std::variant<Ts...>> {};
#endif
PYBIND11_NAMESPACE_END(detail)
......
......@@ -4,21 +4,20 @@
#pragma once
#include "../cast.h"
#include "../pybind11.h"
#include "../pytypes.h"
#include "../detail/common.h"
#include "../detail/descr.h"
#include "../cast.h"
#include "../pytypes.h"
#include <string>
#ifdef __has_include
# if defined(PYBIND11_CPP17) && __has_include(<filesystem>) && \
# if defined(PYBIND11_CPP17) && __has_include(<filesystem>) && \
PY_VERSION_HEX >= 0x03060000
# include <filesystem>
# define PYBIND11_HAS_FILESYSTEM 1
# endif
# include <filesystem>
# define PYBIND11_HAS_FILESYSTEM 1
# endif
#endif
#if !defined(PYBIND11_HAS_FILESYSTEM) && !defined(PYBIND11_HAS_FILESYSTEM_IS_OPTIONAL)
......@@ -30,28 +29,29 @@ PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(detail)
#if defined(PYBIND11_HAS_FILESYSTEM)
template<typename T> struct path_caster {
template <typename T>
struct path_caster {
private:
static PyObject* unicode_from_fs_native(const std::string& w) {
#if !defined(PYPY_VERSION)
static PyObject *unicode_from_fs_native(const std::string &w) {
# if !defined(PYPY_VERSION)
return PyUnicode_DecodeFSDefaultAndSize(w.c_str(), ssize_t(w.size()));
#else
# else
// PyPy mistakenly declares the first parameter as non-const.
return PyUnicode_DecodeFSDefaultAndSize(
const_cast<char*>(w.c_str()), ssize_t(w.size()));
#endif
return PyUnicode_DecodeFSDefaultAndSize(const_cast<char *>(w.c_str()), ssize_t(w.size()));
# endif
}
static PyObject* unicode_from_fs_native(const std::wstring& w) {
static PyObject *unicode_from_fs_native(const std::wstring &w) {
return PyUnicode_FromWideChar(w.c_str(), ssize_t(w.size()));
}
public:
static handle cast(const T& path, return_value_policy, handle) {
static handle cast(const T &path, return_value_policy, handle) {
if (auto py_str = unicode_from_fs_native(path.native())) {
return module_::import("pathlib").attr("Path")(reinterpret_steal<object>(py_str))
.release();
return module_::import("pathlib")
.attr("Path")(reinterpret_steal<object>(py_str))
.release();
}
return nullptr;
}
......@@ -60,12 +60,12 @@ public:
// PyUnicode_FSConverter and PyUnicode_FSDecoder normally take care of
// calling PyOS_FSPath themselves, but that's broken on PyPy (PyPy
// issue #3168) so we do it ourselves instead.
PyObject* buf = PyOS_FSPath(handle.ptr());
PyObject *buf = PyOS_FSPath(handle.ptr());
if (!buf) {
PyErr_Clear();
return false;
}
PyObject* native = nullptr;
PyObject *native = nullptr;
if constexpr (std::is_same_v<typename T::value_type, char>) {
if (PyUnicode_FSConverter(buf, &native) != 0) {
if (auto *c_str = PyBytes_AsString(native)) {
......@@ -78,7 +78,7 @@ public:
if (PyUnicode_FSDecoder(buf, &native) != 0) {
if (auto *c_str = PyUnicode_AsWideCharString(native, nullptr)) {
// AsWideCharString returns a new string that must be free'd.
value = c_str; // Copies the string.
value = c_str; // Copies the string.
PyMem_Free(c_str);
}
}
......@@ -95,8 +95,8 @@ public:
PYBIND11_TYPE_CASTER(T, const_name("os.PathLike"));
};
template<> struct type_caster<std::filesystem::path>
: public path_caster<std::filesystem::path> {};
template <>
struct type_caster<std::filesystem::path> : public path_caster<std::filesystem::path> {};
#endif // PYBIND11_HAS_FILESYSTEM
PYBIND11_NAMESPACE_END(detail)
......
......@@ -19,74 +19,87 @@ PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(detail)
/* SFINAE helper class used by 'is_comparable */
template <typename T> struct container_traits {
template <typename T2> static std::true_type test_comparable(decltype(std::declval<const T2 &>() == std::declval<const T2 &>())*);
template <typename T2> static std::false_type test_comparable(...);
template <typename T2> static std::true_type test_value(typename T2::value_type *);
template <typename T2> static std::false_type test_value(...);
template <typename T2> static std::true_type test_pair(typename T2::first_type *, typename T2::second_type *);
template <typename T2> static std::false_type test_pair(...);
static constexpr const bool is_comparable = std::is_same<std::true_type, decltype(test_comparable<T>(nullptr))>::value;
static constexpr const bool is_pair = std::is_same<std::true_type, decltype(test_pair<T>(nullptr, nullptr))>::value;
static constexpr const bool is_vector = std::is_same<std::true_type, decltype(test_value<T>(nullptr))>::value;
template <typename T>
struct container_traits {
template <typename T2>
static std::true_type
test_comparable(decltype(std::declval<const T2 &>() == std::declval<const T2 &>()) *);
template <typename T2>
static std::false_type test_comparable(...);
template <typename T2>
static std::true_type test_value(typename T2::value_type *);
template <typename T2>
static std::false_type test_value(...);
template <typename T2>
static std::true_type test_pair(typename T2::first_type *, typename T2::second_type *);
template <typename T2>
static std::false_type test_pair(...);
static constexpr const bool is_comparable
= std::is_same<std::true_type, decltype(test_comparable<T>(nullptr))>::value;
static constexpr const bool is_pair
= std::is_same<std::true_type, decltype(test_pair<T>(nullptr, nullptr))>::value;
static constexpr const bool is_vector
= std::is_same<std::true_type, decltype(test_value<T>(nullptr))>::value;
static constexpr const bool is_element = !is_pair && !is_vector;
};
/* Default: is_comparable -> std::false_type */
template <typename T, typename SFINAE = void>
struct is_comparable : std::false_type { };
struct is_comparable : std::false_type {};
/* For non-map data structures, check whether operator== can be instantiated */
template <typename T>
struct is_comparable<
T, enable_if_t<container_traits<T>::is_element &&
container_traits<T>::is_comparable>>
: std::true_type { };
T,
enable_if_t<container_traits<T>::is_element && container_traits<T>::is_comparable>>
: std::true_type {};
/* For a vector/map data structure, recursively check the value type
(which is std::pair for maps) */
template <typename T>
struct is_comparable<T, enable_if_t<container_traits<T>::is_vector>> {
static constexpr const bool value =
is_comparable<typename T::value_type>::value;
static constexpr const bool value = is_comparable<typename T::value_type>::value;
};
/* For pairs, recursively check the two data types */
template <typename T>
struct is_comparable<T, enable_if_t<container_traits<T>::is_pair>> {
static constexpr const bool value =
is_comparable<typename T::first_type>::value &&
is_comparable<typename T::second_type>::value;
static constexpr const bool value = is_comparable<typename T::first_type>::value
&& is_comparable<typename T::second_type>::value;
};
/* Fallback functions */
template <typename, typename, typename... Args> void vector_if_copy_constructible(const Args &...) { }
template <typename, typename, typename... Args> void vector_if_equal_operator(const Args &...) { }
template <typename, typename, typename... Args> void vector_if_insertion_operator(const Args &...) { }
template <typename, typename, typename... Args> void vector_modifiers(const Args &...) { }
template <typename, typename, typename... Args>
void vector_if_copy_constructible(const Args &...) {}
template <typename, typename, typename... Args>
void vector_if_equal_operator(const Args &...) {}
template <typename, typename, typename... Args>
void vector_if_insertion_operator(const Args &...) {}
template <typename, typename, typename... Args>
void vector_modifiers(const Args &...) {}
template<typename Vector, typename Class_>
template <typename Vector, typename Class_>
void vector_if_copy_constructible(enable_if_t<is_copy_constructible<Vector>::value, Class_> &cl) {
cl.def(init<const Vector &>(), "Copy constructor");
}
template<typename Vector, typename Class_>
template <typename Vector, typename Class_>
void vector_if_equal_operator(enable_if_t<is_comparable<Vector>::value, Class_> &cl) {
using T = typename Vector::value_type;
cl.def(self == self);
cl.def(self != self);
cl.def("count",
[](const Vector &v, const T &x) {
return std::count(v.begin(), v.end(), x);
},
cl.def(
"count",
[](const Vector &v, const T &x) { return std::count(v.begin(), v.end(), x); },
arg("x"),
"Return the number of times ``x`` appears in the list"
);
"Return the number of times ``x`` appears in the list");
cl.def("remove", [](Vector &v, const T &x) {
cl.def(
"remove",
[](Vector &v, const T &x) {
auto p = std::find(v.begin(), v.end(), x);
if (p != v.end()) {
v.erase(p);
......@@ -96,23 +109,21 @@ void vector_if_equal_operator(enable_if_t<is_comparable<Vector>::value, Class_>
},
arg("x"),
"Remove the first item from the list whose value is x. "
"It is an error if there is no such item."
);
"It is an error if there is no such item.");
cl.def("__contains__",
[](const Vector &v, const T &x) {
return std::find(v.begin(), v.end(), x) != v.end();
},
cl.def(
"__contains__",
[](const Vector &v, const T &x) { return std::find(v.begin(), v.end(), x) != v.end(); },
arg("x"),
"Return true the container contains ``x``"
);
"Return true the container contains ``x``");
}
// Vector modifiers -- requires a copyable vector_type:
// (Technically, some of these (pop and __delitem__) don't actually require copyability, but it seems
// silly to allow deletion but not insertion, so include them here too.)
// (Technically, some of these (pop and __delitem__) don't actually require copyability, but it
// seems silly to allow deletion but not insertion, so include them here too.)
template <typename Vector, typename Class_>
void vector_modifiers(enable_if_t<is_copy_constructible<typename Vector::value_type>::value, Class_> &cl) {
void vector_modifiers(
enable_if_t<is_copy_constructible<typename Vector::value_type>::value, Class_> &cl) {
using T = typename Vector::value_type;
using SizeType = typename Vector::size_type;
using DiffType = typename Vector::difference_type;
......@@ -127,10 +138,11 @@ void vector_modifiers(enable_if_t<is_copy_constructible<typename Vector::value_t
return i;
};
cl.def("append",
[](Vector &v, const T &value) { v.push_back(value); },
arg("x"),
"Add an item to the end of the list");
cl.def(
"append",
[](Vector &v, const T &value) { v.push_back(value); },
arg("x"),
"Add an item to the end of the list");
cl.def(init([](const iterable &it) {
auto v = std::unique_ptr<Vector>(new Vector());
......@@ -141,20 +153,14 @@ void vector_modifiers(enable_if_t<is_copy_constructible<typename Vector::value_t
return v.release();
}));
cl.def("clear",
[](Vector &v) {
v.clear();
},
"Clear the contents"
);
cl.def(
"clear", [](Vector &v) { v.clear(); }, "Clear the contents");
cl.def("extend",
[](Vector &v, const Vector &src) {
v.insert(v.end(), src.begin(), src.end());
},
arg("L"),
"Extend the list by appending all the items in the given list"
);
cl.def(
"extend",
[](Vector &v, const Vector &src) { v.insert(v.end(), src.begin(), src.end()); },
arg("L"),
"Extend the list by appending all the items in the given list");
cl.def(
"extend",
......@@ -179,7 +185,8 @@ void vector_modifiers(enable_if_t<is_copy_constructible<typename Vector::value_t
arg("L"),
"Extend the list by appending all the items in the given list");
cl.def("insert",
cl.def(
"insert",
[](Vector &v, DiffType i, const T &x) {
// Can't use wrap_i; i == v.size() is OK
if (i < 0) {
......@@ -190,9 +197,9 @@ void vector_modifiers(enable_if_t<is_copy_constructible<typename Vector::value_t
}
v.insert(v.begin() + i, x);
},
arg("i") , arg("x"),
"Insert an item at a given position."
);
arg("i"),
arg("x"),
"Insert an item at a given position.");
cl.def(
"pop",
......@@ -206,7 +213,8 @@ void vector_modifiers(enable_if_t<is_copy_constructible<typename Vector::value_t
},
"Remove and return the last item");
cl.def("pop",
cl.def(
"pop",
[wrap_i](Vector &v, DiffType i) {
i = wrap_i(i, v.size());
T t = std::move(v[(SizeType) i]);
......@@ -214,15 +222,12 @@ void vector_modifiers(enable_if_t<is_copy_constructible<typename Vector::value_t
return t;
},
arg("i"),
"Remove and return the item at index ``i``"
);
"Remove and return the item at index ``i``");
cl.def("__setitem__",
[wrap_i](Vector &v, DiffType i, const T &t) {
i = wrap_i(i, v.size());
v[(SizeType)i] = t;
}
);
cl.def("__setitem__", [wrap_i](Vector &v, DiffType i, const T &t) {
i = wrap_i(i, v.size());
v[(SizeType) i] = t;
});
/// Slicing protocol
cl.def(
......@@ -237,7 +242,7 @@ void vector_modifiers(enable_if_t<is_copy_constructible<typename Vector::value_t
auto *seq = new Vector();
seq->reserve((size_t) slicelength);
for (size_t i=0; i<slicelength; ++i) {
for (size_t i = 0; i < slicelength; ++i) {
seq->push_back(v[start]);
start += step;
}
......@@ -259,20 +264,20 @@ void vector_modifiers(enable_if_t<is_copy_constructible<typename Vector::value_t
"Left and right hand size of slice assignment have different sizes!");
}
for (size_t i=0; i<slicelength; ++i) {
for (size_t i = 0; i < slicelength; ++i) {
v[start] = value[i];
start += step;
}
},
"Assign list elements using a slice object");
cl.def("__delitem__",
cl.def(
"__delitem__",
[wrap_i](Vector &v, DiffType i) {
i = wrap_i(i, v.size());
v.erase(v.begin() + i);
},
"Delete the list elements at index ``i``"
);
"Delete the list elements at index ``i``");
cl.def(
"__delitem__",
......@@ -297,8 +302,10 @@ void vector_modifiers(enable_if_t<is_copy_constructible<typename Vector::value_t
// 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 = negation<
std::is_same<decltype(std::declval<Vector>()[typename Vector::size_type()]), typename Vector::value_type &>>;
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_>
......@@ -306,7 +313,7 @@ void vector_accessor(enable_if_t<!vector_needs_copy<Vector>::value, Class_> &cl)
using T = typename Vector::value_type;
using SizeType = typename Vector::size_type;
using DiffType = typename Vector::difference_type;
using ItType = typename Vector::iterator;
using ItType = typename Vector::iterator;
auto wrap_i = [](DiffType i, SizeType n) {
if (i < 0) {
......@@ -318,21 +325,22 @@ void vector_accessor(enable_if_t<!vector_needs_copy<Vector>::value, Class_> &cl)
return i;
};
cl.def("__getitem__",
cl.def(
"__getitem__",
[wrap_i](Vector &v, DiffType i) -> T & {
i = wrap_i(i, v.size());
return v[(SizeType)i];
return v[(SizeType) i];
},
return_value_policy::reference_internal // ref + keepalive
);
cl.def("__iter__",
[](Vector &v) {
return make_iterator<
return_value_policy::reference_internal, ItType, ItType, T&>(
v.begin(), v.end());
},
keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */
cl.def(
"__iter__",
[](Vector &v) {
return make_iterator<return_value_policy::reference_internal, ItType, ItType, T &>(
v.begin(), v.end());
},
keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */
);
}
......@@ -342,7 +350,7 @@ void vector_accessor(enable_if_t<vector_needs_copy<Vector>::value, Class_> &cl)
using T = typename Vector::value_type;
using SizeType = typename Vector::size_type;
using DiffType = typename Vector::difference_type;
using ItType = typename Vector::iterator;
using ItType = typename Vector::iterator;
cl.def("__getitem__", [](const Vector &v, DiffType i) -> T {
if (i < 0 && (i += v.size()) < 0) {
throw index_error();
......@@ -353,25 +361,27 @@ void vector_accessor(enable_if_t<vector_needs_copy<Vector>::value, Class_> &cl)
return v[(SizeType) i];
});
cl.def("__iter__",
[](Vector &v) {
return make_iterator<
return_value_policy::copy, ItType, ItType, T>(
v.begin(), v.end());
},
keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */
cl.def(
"__iter__",
[](Vector &v) {
return make_iterator<return_value_policy::copy, ItType, ItType, T>(v.begin(), v.end());
},
keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */
);
}
template <typename Vector, typename Class_> auto vector_if_insertion_operator(Class_ &cl, std::string const &name)
-> decltype(std::declval<std::ostream&>() << std::declval<typename Vector::value_type>(), void()) {
template <typename Vector, typename Class_>
auto vector_if_insertion_operator(Class_ &cl, std::string const &name)
-> decltype(std::declval<std::ostream &>() << std::declval<typename Vector::value_type>(),
void()) {
using size_type = typename Vector::size_type;
cl.def("__repr__",
[name](Vector &v) {
cl.def(
"__repr__",
[name](Vector &v) {
std::ostringstream s;
s << name << '[';
for (size_type i=0; i < v.size(); ++i) {
for (size_type i = 0; i < v.size(); ++i) {
s << v[i];
if (i != v.size() - 1) {
s << ", ";
......@@ -380,8 +390,7 @@ template <typename Vector, typename Class_> auto vector_if_insertion_operator(Cl
s << ']';
return s.str();
},
"Return the canonical string representation of this list."
);
"Return the canonical string representation of this list.");
}
// Provide the buffer interface for vectors if we have data() and we have a format for it
......@@ -390,7 +399,11 @@ template <typename Vector, typename Class_> auto vector_if_insertion_operator(Cl
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 {};
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 {};
// [workaround(intel)] Separate function required here
// Workaround as the Intel compiler does not compile the enable_if_t part below
......@@ -405,17 +418,23 @@ constexpr bool args_any_are_buffer() {
// Add the buffer interface to a vector
template <typename Vector, typename Class_, typename... Args>
void vector_buffer_impl(Class_& cl, std::true_type) {
void vector_buffer_impl(Class_ &cl, std::true_type) {
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");
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(), static_cast<ssize_t>(sizeof(T)), format_descriptor<T>::format(), 1, {v.size()}, {sizeof(T)});
cl.def_buffer([](Vector &v) -> buffer_info {
return buffer_info(v.data(),
static_cast<ssize_t>(sizeof(T)),
format_descriptor<T>::format(),
1,
{v.size()},
{sizeof(T)});
});
cl.def(init([](const buffer &buf) {
......@@ -429,7 +448,7 @@ void vector_buffer_impl(Class_& cl, std::true_type) {
+ " C++: " + format_descriptor<T>::format() + ")");
}
T *p = static_cast<T*>(info.ptr);
T *p = static_cast<T *>(info.ptr);
ssize_t step = info.strides[0] / static_cast<ssize_t>(sizeof(T));
T *end = p + info.shape[0] * step;
if (step == 1) {
......@@ -441,18 +460,18 @@ void vector_buffer_impl(Class_& cl, std::true_type) {
vec.push_back(*p);
}
return vec;
}));
return;
}
template <typename Vector, typename Class_, typename... Args>
void vector_buffer_impl(Class_&, std::false_type) {}
void vector_buffer_impl(Class_ &, std::false_type) {}
template <typename Vector, typename Class_, typename... Args>
void vector_buffer(Class_& cl) {
vector_buffer_impl<Vector, Class_, Args...>(cl, detail::any_of<std::is_same<Args, buffer_protocol>...>{});
void vector_buffer(Class_ &cl) {
vector_buffer_impl<Vector, Class_, Args...>(
cl, detail::any_of<std::is_same<Args, buffer_protocol>...>{});
}
PYBIND11_NAMESPACE_END(detail)
......@@ -461,7 +480,7 @@ PYBIND11_NAMESPACE_END(detail)
// std::vector
//
template <typename Vector, typename holder_type = std::unique_ptr<Vector>, typename... Args>
class_<Vector, holder_type> bind_vector(handle scope, std::string const &name, Args&&... args) {
class_<Vector, holder_type> bind_vector(handle scope, std::string const &name, Args &&...args) {
using Class_ = class_<Vector, holder_type>;
// If the value_type is unregistered (e.g. a converting type) or is itself registered
......@@ -492,18 +511,13 @@ class_<Vector, holder_type> bind_vector(handle scope, std::string const &name, A
// Accessor and iterator; return by value if copyable, otherwise we return by ref + keep-alive
detail::vector_accessor<Vector, Class_>(cl);
cl.def("__bool__",
[](const Vector &v) -> bool {
return !v.empty();
},
"Check whether the list is nonempty"
);
cl.def(
"__bool__",
[](const Vector &v) -> bool { return !v.empty(); },
"Check whether the list is nonempty");
cl.def("__len__", &Vector::size);
#if 0
// C++ style functions deprecated, leaving it here as an example
cl.def(init<size_type>());
......@@ -547,8 +561,6 @@ class_<Vector, holder_type> bind_vector(handle scope, std::string const &name, A
return cl;
}
//
// std::map, std::unordered_map
//
......@@ -556,55 +568,58 @@ class_<Vector, holder_type> bind_vector(handle scope, std::string const &name, A
PYBIND11_NAMESPACE_BEGIN(detail)
/* Fallback functions */
template <typename, typename, typename... Args> void map_if_insertion_operator(const Args &...) { }
template <typename, typename, typename... Args> void map_assignment(const Args &...) { }
template <typename, typename, typename... Args>
void map_if_insertion_operator(const Args &...) {}
template <typename, typename, typename... Args>
void map_assignment(const Args &...) {}
// Map assignment when copy-assignable: just copy the value
template <typename Map, typename Class_>
void map_assignment(enable_if_t<is_copy_assignable<typename Map::mapped_type>::value, Class_> &cl) {
void map_assignment(
enable_if_t<is_copy_assignable<typename Map::mapped_type>::value, Class_> &cl) {
using KeyType = typename Map::key_type;
using MappedType = typename Map::mapped_type;
cl.def("__setitem__",
[](Map &m, const KeyType &k, const MappedType &v) {
auto it = m.find(k);
if (it != m.end()) {
it->second = v;
} else {
m.emplace(k, v);
}
}
);
cl.def("__setitem__", [](Map &m, const KeyType &k, const MappedType &v) {
auto it = m.find(k);
if (it != m.end()) {
it->second = v;
} else {
m.emplace(k, v);
}
});
}
// Not copy-assignable, but still copy-constructible: we can update the value by erasing and reinserting
template<typename Map, typename Class_>
void map_assignment(enable_if_t<
!is_copy_assignable<typename Map::mapped_type>::value &&
is_copy_constructible<typename Map::mapped_type>::value,
Class_> &cl) {
// Not copy-assignable, but still copy-constructible: we can update the value by erasing and
// reinserting
template <typename Map, typename Class_>
void map_assignment(enable_if_t<!is_copy_assignable<typename Map::mapped_type>::value
&& is_copy_constructible<typename Map::mapped_type>::value,
Class_> &cl) {
using KeyType = typename Map::key_type;
using MappedType = typename Map::mapped_type;
cl.def("__setitem__",
[](Map &m, const KeyType &k, const MappedType &v) {
// We can't use m[k] = v; because value type might not be default constructable
auto r = m.emplace(k, v);
if (!r.second) {
// value type is not copy assignable so the only way to insert it is to erase it first...
m.erase(r.first);
m.emplace(k, v);
}
}
);
cl.def("__setitem__", [](Map &m, const KeyType &k, const MappedType &v) {
// We can't use m[k] = v; because value type might not be default constructable
auto r = m.emplace(k, v);
if (!r.second) {
// value type is not copy assignable so the only way to insert it is to erase it
// first...
m.erase(r.first);
m.emplace(k, v);
}
});
}
template <typename Map, typename Class_>
auto map_if_insertion_operator(Class_ &cl, std::string const &name)
-> decltype(std::declval<std::ostream &>() << std::declval<typename Map::key_type>()
<< std::declval<typename Map::mapped_type>(),
void()) {
template <typename Map, typename Class_> auto map_if_insertion_operator(Class_ &cl, std::string const &name)
-> decltype(std::declval<std::ostream&>() << std::declval<typename Map::key_type>() << std::declval<typename Map::mapped_type>(), void()) {
cl.def("__repr__",
[name](Map &m) {
cl.def(
"__repr__",
[name](Map &m) {
std::ostringstream s;
s << name << '{';
bool f = false;
......@@ -618,32 +633,28 @@ template <typename Map, typename Class_> auto map_if_insertion_operator(Class_ &
s << '}';
return s.str();
},
"Return the canonical string representation of this map."
);
"Return the canonical string representation of this map.");
}
template<typename Map>
struct keys_view
{
template <typename Map>
struct keys_view {
Map &map;
};
template<typename Map>
struct values_view
{
template <typename Map>
struct values_view {
Map &map;
};
template<typename Map>
struct items_view
{
template <typename Map>
struct items_view {
Map &map;
};
PYBIND11_NAMESPACE_END(detail)
template <typename Map, typename holder_type = std::unique_ptr<Map>, typename... Args>
class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args&&... args) {
class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args &&...args) {
using KeyType = typename Map::key_type;
using MappedType = typename Map::mapped_type;
using KeysView = detail::keys_view<Map>;
......@@ -674,101 +685,97 @@ class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args&&.
// Register stream insertion operator (if possible)
detail::map_if_insertion_operator<Map, Class_>(cl, name);
cl.def("__bool__",
cl.def(
"__bool__",
[](const Map &m) -> bool { return !m.empty(); },
"Check whether the map is nonempty"
);
"Check whether the map is nonempty");
cl.def("__iter__",
[](Map &m) { return make_key_iterator(m.begin(), m.end()); },
keep_alive<0, 1>() /* Essential: keep map alive while iterator exists */
cl.def(
"__iter__",
[](Map &m) { return make_key_iterator(m.begin(), m.end()); },
keep_alive<0, 1>() /* Essential: keep map alive while iterator exists */
);
cl.def("keys",
[](Map &m) { return KeysView{m}; },
keep_alive<0, 1>() /* Essential: keep map alive while view exists */
cl.def(
"keys",
[](Map &m) { return KeysView{m}; },
keep_alive<0, 1>() /* Essential: keep map alive while view exists */
);
cl.def("values",
[](Map &m) { return ValuesView{m}; },
keep_alive<0, 1>() /* Essential: keep map alive while view exists */
cl.def(
"values",
[](Map &m) { return ValuesView{m}; },
keep_alive<0, 1>() /* Essential: keep map alive while view exists */
);
cl.def("items",
[](Map &m) { return ItemsView{m}; },
keep_alive<0, 1>() /* Essential: keep map alive while view exists */
cl.def(
"items",
[](Map &m) { return ItemsView{m}; },
keep_alive<0, 1>() /* Essential: keep map alive while view exists */
);
cl.def("__getitem__",
cl.def(
"__getitem__",
[](Map &m, const KeyType &k) -> MappedType & {
auto it = m.find(k);
if (it == m.end()) {
throw key_error();
}
return it->second;
return it->second;
},
return_value_policy::reference_internal // ref + keepalive
);
cl.def("__contains__",
[](Map &m, const KeyType &k) -> bool {
auto it = m.find(k);
if (it == m.end()) {
return false;
}
return true;
cl.def("__contains__", [](Map &m, const KeyType &k) -> bool {
auto it = m.find(k);
if (it == m.end()) {
return false;
}
);
return true;
});
// Fallback for when the object is not of the key type
cl.def("__contains__", [](Map &, const object &) -> bool { return false; });
// Assignment provided only if the type is copyable
detail::map_assignment<Map, Class_>(cl);
cl.def("__delitem__",
[](Map &m, const KeyType &k) {
auto it = m.find(k);
if (it == m.end()) {
throw key_error();
}
m.erase(it);
}
);
cl.def("__delitem__", [](Map &m, const KeyType &k) {
auto it = m.find(k);
if (it == m.end()) {
throw key_error();
}
m.erase(it);
});
cl.def("__len__", &Map::size);
keys_view.def("__len__", [](KeysView &view) { return view.map.size(); });
keys_view.def("__iter__",
[](KeysView &view) {
return make_key_iterator(view.map.begin(), view.map.end());
},
keys_view.def(
"__iter__",
[](KeysView &view) { return make_key_iterator(view.map.begin(), view.map.end()); },
keep_alive<0, 1>() /* Essential: keep view alive while iterator exists */
);
keys_view.def("__contains__",
[](KeysView &view, const KeyType &k) -> bool {
auto it = view.map.find(k);
if (it == view.map.end()) {
return false;
}
return true;
keys_view.def("__contains__", [](KeysView &view, const KeyType &k) -> bool {
auto it = view.map.find(k);
if (it == view.map.end()) {
return false;
}
);
return true;
});
// Fallback for when the object is not of the key type
keys_view.def("__contains__", [](KeysView &, const object &) -> bool { return false; });
values_view.def("__len__", [](ValuesView &view) { return view.map.size(); });
values_view.def("__iter__",
[](ValuesView &view) {
return make_value_iterator(view.map.begin(), view.map.end());
},
values_view.def(
"__iter__",
[](ValuesView &view) { return make_value_iterator(view.map.begin(), view.map.end()); },
keep_alive<0, 1>() /* Essential: keep view alive while iterator exists */
);
items_view.def("__len__", [](ItemsView &view) { return view.map.size(); });
items_view.def("__iter__",
[](ItemsView &view) {
return make_iterator(view.map.begin(), view.map.end());
},
items_view.def(
"__iter__",
[](ItemsView &view) { return make_iterator(view.map.begin(), view.map.end()); },
keep_alive<0, 1>() /* Essential: keep view alive while iterator exists */
);
......
......@@ -56,7 +56,8 @@ from the ConstructorStats instance `.values()` method.
In some cases, when you need to track instances of a C++ class not registered with pybind11, you
need to add a function returning the ConstructorStats for the C++ class; this can be done with:
m.def("get_special_cstats", &ConstructorStats::get<SpecialClass>, py::return_value_policy::reference)
m.def("get_special_cstats", &ConstructorStats::get<SpecialClass>,
py::return_value_policy::reference)
Finally, you can suppress the output messages, but keep the constructor tracking (for
inspection/testing in python) by using the functions with `print_` replaced with `track_` (e.g.
......@@ -65,17 +66,18 @@ inspection/testing in python) by using the functions with `print_` replaced with
*/
#include "pybind11_tests.h"
#include <unordered_map>
#include <list>
#include <typeindex>
#include <sstream>
#include <typeindex>
#include <unordered_map>
class ConstructorStats {
protected:
std::unordered_map<void*, int> _instances; // Need a map rather than set because members can
// shared address with parents
std::list<std::string> _values; // Used to track values
// (e.g. of value constructors)
std::unordered_map<void *, int> _instances; // Need a map rather than set because members can
// shared address with parents
std::list<std::string> _values; // Used to track values
// (e.g. of value constructors)
public:
int default_constructions = 0;
int copy_constructions = 0;
......@@ -98,9 +100,7 @@ public:
default_constructions++;
}
void created(void *inst) {
++_instances[inst];
}
void created(void *inst) { ++_instances[inst]; }
void destroyed(void *inst) {
if (--_instances[inst] < 0) {
......@@ -114,11 +114,12 @@ public:
// Force garbage collection to ensure any pending destructors are invoked:
#if defined(PYPY_VERSION)
PyObject *globals = PyEval_GetGlobals();
PyObject *result = PyRun_String(
"import gc\n"
"for i in range(2):"
" gc.collect()\n",
Py_file_input, globals, globals);
PyObject *result = PyRun_String("import gc\n"
"for i in range(2):"
" gc.collect()\n",
Py_file_input,
globals,
globals);
if (result == nullptr)
throw py::error_already_set();
Py_DECREF(result);
......@@ -140,7 +141,8 @@ public:
void value() {} // Recursion terminator
// Takes one or more values, converts them to strings, then stores them.
template <typename T, typename... Tmore> void value(const T &v, Tmore &&...args) {
template <typename T, typename... Tmore>
void value(const T &v, Tmore &&...args) {
std::ostringstream oss;
oss << v;
_values.push_back(oss.str());
......@@ -158,13 +160,14 @@ public:
}
// Gets constructor stats from a C++ type index
static ConstructorStats& get(std::type_index type) {
static ConstructorStats &get(std::type_index type) {
static std::unordered_map<std::type_index, ConstructorStats> all_cstats;
return all_cstats[type];
}
// Gets constructor stats from a C++ type
template <typename T> static ConstructorStats& get() {
template <typename T>
static ConstructorStats &get() {
#if defined(PYPY_VERSION)
gc();
#endif
......@@ -172,11 +175,12 @@ public:
}
// Gets constructor stats from a Python class
static ConstructorStats& get(py::object class_) {
static ConstructorStats &get(py::object class_) {
auto &internals = py::detail::get_internals();
const std::type_index *t1 = nullptr, *t2 = nullptr;
try {
auto *type_info = internals.registered_types_py.at((PyTypeObject *) class_.ptr()).at(0);
auto *type_info
= internals.registered_types_py.at((PyTypeObject *) class_.ptr()).at(0);
for (auto &p : internals.registered_types_cpp) {
if (p.second == type_info) {
if (t1) {
......@@ -186,18 +190,20 @@ public:
t1 = &p.first;
}
}
} catch (const std::out_of_range &) {
}
catch (const std::out_of_range&) {}
if (!t1) {
throw std::runtime_error("Unknown class passed to ConstructorStats::get()");
}
auto &cs1 = get(*t1);
// If we have both a t1 and t2 match, one is probably the trampoline class; return whichever
// has more constructions (typically one or the other will be 0)
// If we have both a t1 and t2 match, one is probably the trampoline class; return
// whichever has more constructions (typically one or the other will be 0)
if (t2) {
auto &cs2 = get(*t2);
int cs1_total = cs1.default_constructions + cs1.copy_constructions + cs1.move_constructions + (int) cs1._values.size();
int cs2_total = cs2.default_constructions + cs2.copy_constructions + cs2.move_constructions + (int) cs2._values.size();
int cs1_total = cs1.default_constructions + cs1.copy_constructions
+ cs1.move_constructions + (int) cs1._values.size();
int cs2_total = cs2.default_constructions + cs2.copy_constructions
+ cs2.move_constructions + (int) cs2._values.size();
if (cs2_total > cs1_total) {
return cs2;
}
......@@ -209,78 +215,108 @@ public:
// To track construction/destruction, you need to call these methods from the various
// constructors/operators. The ones that take extra values record the given values in the
// constructor stats values for later inspection.
template <class T> void track_copy_created(T *inst) { ConstructorStats::get<T>().copy_created(inst); }
template <class T> void track_move_created(T *inst) { ConstructorStats::get<T>().move_created(inst); }
template <class T, typename... Values> void track_copy_assigned(T *, Values &&...values) {
template <class T>
void track_copy_created(T *inst) {
ConstructorStats::get<T>().copy_created(inst);
}
template <class T>
void track_move_created(T *inst) {
ConstructorStats::get<T>().move_created(inst);
}
template <class T, typename... Values>
void track_copy_assigned(T *, Values &&...values) {
auto &cst = ConstructorStats::get<T>();
cst.copy_assignments++;
cst.value(std::forward<Values>(values)...);
}
template <class T, typename... Values> void track_move_assigned(T *, Values &&...values) {
template <class T, typename... Values>
void track_move_assigned(T *, Values &&...values) {
auto &cst = ConstructorStats::get<T>();
cst.move_assignments++;
cst.value(std::forward<Values>(values)...);
}
template <class T, typename... Values> void track_default_created(T *inst, Values &&...values) {
template <class T, typename... Values>
void track_default_created(T *inst, Values &&...values) {
auto &cst = ConstructorStats::get<T>();
cst.default_created(inst);
cst.value(std::forward<Values>(values)...);
}
template <class T, typename... Values> void track_created(T *inst, Values &&...values) {
template <class T, typename... Values>
void track_created(T *inst, Values &&...values) {
auto &cst = ConstructorStats::get<T>();
cst.created(inst);
cst.value(std::forward<Values>(values)...);
}
template <class T, typename... Values> void track_destroyed(T *inst) {
template <class T, typename... Values>
void track_destroyed(T *inst) {
ConstructorStats::get<T>().destroyed(inst);
}
template <class T, typename... Values> void track_values(T *, Values &&...values) {
template <class T, typename... Values>
void track_values(T *, Values &&...values) {
ConstructorStats::get<T>().value(std::forward<Values>(values)...);
}
/// Don't cast pointers to Python, print them as strings
inline const char *format_ptrs(const char *p) { return p; }
template <typename T>
py::str format_ptrs(T *p) { return "{:#x}"_s.format(reinterpret_cast<std::uintptr_t>(p)); }
py::str format_ptrs(T *p) {
return "{:#x}"_s.format(reinterpret_cast<std::uintptr_t>(p));
}
template <typename T>
auto format_ptrs(T &&x) -> decltype(std::forward<T>(x)) { return std::forward<T>(x); }
auto format_ptrs(T &&x) -> decltype(std::forward<T>(x)) {
return std::forward<T>(x);
}
template <class T, typename... Output>
void print_constr_details(T *inst, const std::string &action, Output &&...output) {
py::print("###", py::type_id<T>(), "@", format_ptrs(inst), action,
py::print("###",
py::type_id<T>(),
"@",
format_ptrs(inst),
action,
format_ptrs(std::forward<Output>(output))...);
}
// Verbose versions of the above:
template <class T, typename... Values> void print_copy_created(T *inst, Values &&...values) { // NB: this prints, but doesn't store, given values
template <class T, typename... Values>
void print_copy_created(T *inst,
Values &&...values) { // NB: this prints, but doesn't store, given values
print_constr_details(inst, "created via copy constructor", values...);
track_copy_created(inst);
}
template <class T, typename... Values> void print_move_created(T *inst, Values &&...values) { // NB: this prints, but doesn't store, given values
template <class T, typename... Values>
void print_move_created(T *inst,
Values &&...values) { // NB: this prints, but doesn't store, given values
print_constr_details(inst, "created via move constructor", values...);
track_move_created(inst);
}
template <class T, typename... Values> void print_copy_assigned(T *inst, Values &&...values) {
template <class T, typename... Values>
void print_copy_assigned(T *inst, Values &&...values) {
print_constr_details(inst, "assigned via copy assignment", values...);
track_copy_assigned(inst, values...);
}
template <class T, typename... Values> void print_move_assigned(T *inst, Values &&...values) {
template <class T, typename... Values>
void print_move_assigned(T *inst, Values &&...values) {
print_constr_details(inst, "assigned via move assignment", values...);
track_move_assigned(inst, values...);
}
template <class T, typename... Values> void print_default_created(T *inst, Values &&...values) {
template <class T, typename... Values>
void print_default_created(T *inst, Values &&...values) {
print_constr_details(inst, "created via default constructor", values...);
track_default_created(inst, values...);
}
template <class T, typename... Values> void print_created(T *inst, Values &&...values) {
template <class T, typename... Values>
void print_created(T *inst, Values &&...values) {
print_constr_details(inst, "created", values...);
track_created(inst, values...);
}
template <class T, typename... Values> void print_destroyed(T *inst, Values &&...values) { // Prints but doesn't store given values
template <class T, typename... Values>
void print_destroyed(T *inst, Values &&...values) { // Prints but doesn't store given values
print_constr_details(inst, "destroyed", values...);
track_destroyed(inst);
}
template <class T, typename... Values> void print_values(T *inst, Values &&...values) {
template <class T, typename... Values>
void print_values(T *inst, Values &&...values) {
print_constr_details(inst, ":", values...);
track_values(inst, values...);
}
......@@ -7,6 +7,7 @@
BSD-style license that can be found in the LICENSE file.
*/
#include <pybind11/pybind11.h>
#include <cstdint>
// This file mimics a DSO that makes pybind11 calls but does not define a
......@@ -25,34 +26,25 @@ void gil_acquire() { py::gil_scoped_acquire gil; }
constexpr char kModuleName[] = "cross_module_gil_utils";
#if PY_MAJOR_VERSION >= 3
struct PyModuleDef moduledef = {
PyModuleDef_HEAD_INIT,
kModuleName,
NULL,
0,
NULL,
NULL,
NULL,
NULL,
NULL
};
struct PyModuleDef moduledef
= {PyModuleDef_HEAD_INIT, kModuleName, NULL, 0, NULL, NULL, NULL, NULL, NULL};
#else
PyMethodDef module_methods[] = {
{NULL, NULL, 0, NULL}
};
PyMethodDef module_methods[] = {{NULL, NULL, 0, NULL}};
#endif
} // namespace
} // namespace
extern "C" PYBIND11_EXPORT
#if PY_MAJOR_VERSION >= 3
PyObject* PyInit_cross_module_gil_utils()
PyObject *
PyInit_cross_module_gil_utils()
#else
void initcross_module_gil_utils()
void
initcross_module_gil_utils()
#endif
{
PyObject* m =
PyObject *m =
#if PY_MAJOR_VERSION >= 3
PyModule_Create(&moduledef);
#else
......@@ -60,11 +52,10 @@ void initcross_module_gil_utils()
#endif
if (m != NULL) {
static_assert(
sizeof(&gil_acquire) == sizeof(void*),
"Function pointer must have the same size as void*");
PyModule_AddObject(m, "gil_acquire_funcaddr",
PyLong_FromVoidPtr(reinterpret_cast<void*>(&gil_acquire)));
static_assert(sizeof(&gil_acquire) == sizeof(void *),
"Function pointer must have the same size as void*");
PyModule_AddObject(
m, "gil_acquire_funcaddr", PyLong_FromVoidPtr(reinterpret_cast<void *>(&gil_acquire)));
}
#if PY_MAJOR_VERSION >= 3
......
#pragma once
#include <utility>
#include "pybind11_tests.h"
#include <utility>
/// Simple class used to test py::local:
template <int> class LocalBase {
template <int>
class LocalBase {
public:
explicit LocalBase(int i) : i(i) { }
explicit LocalBase(int i) : i(i) {}
int i = -1;
};
......@@ -35,12 +36,12 @@ using NonLocalVec2 = std::vector<NonLocal2>;
using NonLocalMap = std::unordered_map<std::string, NonLocalType>;
using NonLocalMap2 = std::unordered_map<std::string, uint8_t>;
// Exception that will be caught via the module local translator.
class LocalException : public std::exception {
public:
explicit LocalException(const char * m) : message{m} {}
const char * what() const noexcept override {return message.c_str();}
explicit LocalException(const char *m) : message{m} {}
const char *what() const noexcept override { return message.c_str(); }
private:
std::string message = "";
};
......@@ -48,8 +49,9 @@ private:
// Exception that will be registered with register_local_exception_translator
class LocalSimpleException : public std::exception {
public:
explicit LocalSimpleException(const char * m) : message{m} {}
const char * what() const noexcept override {return message.c_str();}
explicit LocalSimpleException(const char *m) : message{m} {}
const char *what() const noexcept override { return message.c_str(); }
private:
std::string message = "";
};
......@@ -58,17 +60,16 @@ PYBIND11_MAKE_OPAQUE(LocalVec);
PYBIND11_MAKE_OPAQUE(LocalVec2);
PYBIND11_MAKE_OPAQUE(LocalMap);
PYBIND11_MAKE_OPAQUE(NonLocalVec);
//PYBIND11_MAKE_OPAQUE(NonLocalVec2); // same type as LocalVec2
// PYBIND11_MAKE_OPAQUE(NonLocalVec2); // same type as LocalVec2
PYBIND11_MAKE_OPAQUE(NonLocalMap);
PYBIND11_MAKE_OPAQUE(NonLocalMap2);
// Simple bindings (used with the above):
template <typename T, int Adjust = 0, typename... Args>
py::class_<T> bind_local(Args && ...args) {
return py::class_<T>(std::forward<Args>(args)...)
.def(py::init<int>())
.def("get", [](T &i) { return i.i + Adjust; });
py::class_<T> bind_local(Args &&...args) {
return py::class_<T>(std::forward<Args>(args)...).def(py::init<int>()).def("get", [](T &i) {
return i.i + Adjust;
});
};
// Simulate a foreign library base class (to match the example in the docs):
......@@ -81,5 +82,11 @@ public:
};
} // namespace pets
struct MixGL { int i; explicit MixGL(int i) : i{i} {} };
struct MixGL2 { int i; explicit MixGL2(int i) : i{i} {} };
struct MixGL {
int i;
explicit MixGL(int i) : i{i} {}
};
struct MixGL2 {
int i;
explicit MixGL2(int i) : i{i} {}
};
#if !defined(__OBJECT_H)
#define __OBJECT_H
# define __OBJECT_H
#include <atomic>
#include "constructor_stats.h"
# include "constructor_stats.h"
# include <atomic>
/// Reference counted object base class
class Object {
......@@ -35,13 +36,15 @@ public:
}
virtual std::string toString() const = 0;
protected:
/** \brief Virtual protected deconstructor.
* (Will only be called by \ref ref)
*/
virtual ~Object() { print_destroyed(this); }
private:
mutable std::atomic<int> m_refCount { 0 };
mutable std::atomic<int> m_refCount{0};
};
// Tag class used to track constructions of ref objects. When we track constructors, below, we
......@@ -60,10 +63,14 @@ class ref_tag {};
*
* \ingroup libcore
*/
template <typename T> class ref {
template <typename T>
class ref {
public:
/// Create a nullptr reference
ref() : m_ptr(nullptr) { print_default_created(this); track_default_created((ref_tag*) this); }
ref() : m_ptr(nullptr) {
print_default_created(this);
track_default_created((ref_tag *) this);
}
/// Construct a reference from a pointer
explicit ref(T *ptr) : m_ptr(ptr) {
......@@ -71,8 +78,8 @@ public:
((Object *) m_ptr)->incRef();
}
print_created(this, "from pointer", m_ptr); track_created((ref_tag*) this, "from pointer");
print_created(this, "from pointer", m_ptr);
track_created((ref_tag *) this, "from pointer");
}
/// Copy constructor
......@@ -81,14 +88,16 @@ public:
((Object *) m_ptr)->incRef();
}
print_copy_created(this, "with pointer", m_ptr); track_copy_created((ref_tag*) this);
print_copy_created(this, "with pointer", m_ptr);
track_copy_created((ref_tag *) this);
}
/// Move constructor
ref(ref &&r) noexcept : m_ptr(r.m_ptr) {
r.m_ptr = nullptr;
print_move_created(this, "with pointer", m_ptr); track_move_created((ref_tag*) this);
print_move_created(this, "with pointer", m_ptr);
track_move_created((ref_tag *) this);
}
/// Destroy this reference
......@@ -97,12 +106,14 @@ public:
((Object *) m_ptr)->decRef();
}
print_destroyed(this); track_destroyed((ref_tag*) this);
print_destroyed(this);
track_destroyed((ref_tag *) this);
}
/// Move another reference into the current one
ref &operator=(ref &&r) noexcept {
print_move_assigned(this, "pointer", r.m_ptr); track_move_assigned((ref_tag*) this);
print_move_assigned(this, "pointer", r.m_ptr);
track_move_assigned((ref_tag *) this);
if (*this == r) {
return *this;
......@@ -116,7 +127,7 @@ public:
}
/// Overwrite this reference with another reference
ref& operator=(const ref& r) {
ref &operator=(const ref &r) {
if (this == &r) {
return *this;
}
......@@ -137,8 +148,9 @@ public:
}
/// Overwrite this reference with a pointer to another object
ref& operator=(T *ptr) {
print_values(this, "assigned pointer"); track_values((ref_tag*) this, "assigned pointer");
ref &operator=(T *ptr) {
print_values(this, "assigned pointer");
track_values((ref_tag *) this, "assigned pointer");
if (m_ptr == ptr) {
return *this;
......@@ -160,31 +172,32 @@ public:
bool operator!=(const ref &r) const { return m_ptr != r.m_ptr; }
/// Compare this reference with a pointer
bool operator==(const T* ptr) const { return m_ptr == ptr; }
bool operator==(const T *ptr) const { return m_ptr == ptr; }
/// Compare this reference with a pointer
bool operator!=(const T* ptr) const { return m_ptr != ptr; }
bool operator!=(const T *ptr) const { return m_ptr != ptr; }
/// Access the object referenced by this reference
T* operator->() { return m_ptr; }
T *operator->() { return m_ptr; }
/// Access the object referenced by this reference
const T* operator->() const { return m_ptr; }
const T *operator->() const { return m_ptr; }
/// Return a C++ reference to the referenced object
T& operator*() { return *m_ptr; }
T &operator*() { return *m_ptr; }
/// Return a const C++ reference to the referenced object
const T& operator*() const { return *m_ptr; }
const T &operator*() const { return *m_ptr; }
/// Return a pointer to the referenced object
explicit operator T* () { return m_ptr; }
explicit operator T *() { return m_ptr; }
/// Return a const pointer to the referenced object
T* get_ptr() { return m_ptr; }
T *get_ptr() { return m_ptr; }
/// Return a pointer to the referenced object
const T* get_ptr() const { return m_ptr; }
const T *get_ptr() const { return m_ptr; }
private:
T *m_ptr;
};
......
......@@ -7,12 +7,12 @@
BSD-style license that can be found in the LICENSE file.
*/
#include "pybind11_tests.h"
#include <pybind11/stl_bind.h>
#include "local_bindings.h"
#include "pybind11_tests.h"
#include "test_exceptions.h"
#include <pybind11/stl_bind.h>
#include <numeric>
#include <utility>
......@@ -30,39 +30,45 @@ PYBIND11_MODULE(pybind11_cross_module_tests, m) {
// test_exceptions.py
py::register_local_exception<LocalSimpleException>(m, "LocalSimpleException");
m.def("raise_runtime_error", []() { PyErr_SetString(PyExc_RuntimeError, "My runtime error"); throw py::error_already_set(); });
m.def("raise_value_error", []() { PyErr_SetString(PyExc_ValueError, "My value error"); throw py::error_already_set(); });
m.def("raise_runtime_error", []() {
PyErr_SetString(PyExc_RuntimeError, "My runtime error");
throw py::error_already_set();
});
m.def("raise_value_error", []() {
PyErr_SetString(PyExc_ValueError, "My value error");
throw py::error_already_set();
});
m.def("throw_pybind_value_error", []() { throw py::value_error("pybind11 value error"); });
m.def("throw_pybind_type_error", []() { throw py::type_error("pybind11 type error"); });
m.def("throw_stop_iteration", []() { throw py::stop_iteration(); });
m.def("throw_local_error", []() { throw LocalException("just local"); });
m.def("throw_local_simple_error", []() { throw LocalSimpleException("external mod"); });
py::register_exception_translator([](std::exception_ptr p) {
try {
if (p) {
std::rethrow_exception(p);
}
} catch (const shared_exception &e) {
PyErr_SetString(PyExc_KeyError, e.what());
}
try {
if (p) {
std::rethrow_exception(p);
}
} catch (const shared_exception &e) {
PyErr_SetString(PyExc_KeyError, e.what());
}
});
// translate the local exception into a key error but only in this module
py::register_local_exception_translator([](std::exception_ptr p) {
try {
if (p) {
std::rethrow_exception(p);
}
} catch (const LocalException &e) {
PyErr_SetString(PyExc_KeyError, e.what());
}
try {
if (p) {
std::rethrow_exception(p);
}
} catch (const LocalException &e) {
PyErr_SetString(PyExc_KeyError, e.what());
}
});
// test_local_bindings.py
// Local to both:
bind_local<LocalType, 1>(m, "LocalType", py::module_local())
.def("get2", [](LocalType &t) { return t.i + 2; })
;
bind_local<LocalType, 1>(m, "LocalType", py::module_local()).def("get2", [](LocalType &t) {
return t.i + 2;
});
// Can only be called with our python type:
m.def("local_value", [](LocalType &l) { return l.i; });
......@@ -70,9 +76,7 @@ PYBIND11_MODULE(pybind11_cross_module_tests, m) {
// test_nonlocal_failure
// This registration will fail (global registration when LocalFail is already registered
// globally in the main test module):
m.def("register_nonlocal", [m]() {
bind_local<NonLocalType, 0>(m, "NonLocalType");
});
m.def("register_nonlocal", [m]() { bind_local<NonLocalType, 0>(m, "NonLocalType"); });
// test_stl_bind_local
// stl_bind.h binders defaults to py::module_local if the types are local or converting:
......@@ -82,27 +86,21 @@ PYBIND11_MODULE(pybind11_cross_module_tests, m) {
// test_stl_bind_global
// and global if the type (or one of the types, for the map) is global (so these will fail,
// assuming pybind11_tests is already loaded):
m.def("register_nonlocal_vec", [m]() {
py::bind_vector<NonLocalVec>(m, "NonLocalVec");
});
m.def("register_nonlocal_map", [m]() {
py::bind_map<NonLocalMap>(m, "NonLocalMap");
});
m.def("register_nonlocal_vec", [m]() { py::bind_vector<NonLocalVec>(m, "NonLocalVec"); });
m.def("register_nonlocal_map", [m]() { py::bind_map<NonLocalMap>(m, "NonLocalMap"); });
// The default can, however, be overridden to global using `py::module_local()` or
// `py::module_local(false)`.
// Explicitly made local:
py::bind_vector<NonLocalVec2>(m, "NonLocalVec2", py::module_local());
// Explicitly made global (and so will fail to bind):
m.def("register_nonlocal_map2", [m]() {
py::bind_map<NonLocalMap2>(m, "NonLocalMap2", py::module_local(false));
});
m.def("register_nonlocal_map2",
[m]() { py::bind_map<NonLocalMap2>(m, "NonLocalMap2", py::module_local(false)); });
// test_mixed_local_global
// We try this both with the global type registered first and vice versa (the order shouldn't
// matter).
m.def("register_mixed_global_local", [m]() {
bind_local<MixedGlobalLocal, 200>(m, "MixedGlobalLocal", py::module_local());
});
m.def("register_mixed_global_local",
[m]() { bind_local<MixedGlobalLocal, 200>(m, "MixedGlobalLocal", py::module_local()); });
m.def("register_mixed_local_global", [m]() {
bind_local<MixedLocalGlobal, 2000>(m, "MixedLocalGlobal", py::module_local(false));
});
......@@ -110,14 +108,14 @@ PYBIND11_MODULE(pybind11_cross_module_tests, m) {
m.def("get_mixed_lg", [](int i) { return MixedLocalGlobal(i); });
// test_internal_locals_differ
m.def("local_cpp_types_addr", []() { return (uintptr_t) &py::detail::get_local_internals().registered_types_cpp; });
m.def("local_cpp_types_addr",
[]() { return (uintptr_t) &py::detail::get_local_internals().registered_types_cpp; });
// test_stl_caster_vs_stl_bind
py::bind_vector<std::vector<int>>(m, "VectorInt");
m.def("load_vector_via_binding", [](std::vector<int> &v) {
return std::accumulate(v.begin(), v.end(), 0);
});
m.def("load_vector_via_binding",
[](std::vector<int> &v) { return std::accumulate(v.begin(), v.end(), 0); });
// test_cross_module_calls
m.def("return_self", [](LocalVec *v) { return v; });
......@@ -127,11 +125,9 @@ PYBIND11_MODULE(pybind11_cross_module_tests, m) {
public:
explicit Dog(std::string name) : Pet(std::move(name)) {}
};
py::class_<pets::Pet>(m, "Pet", py::module_local())
.def("name", &pets::Pet::name);
py::class_<pets::Pet>(m, "Pet", py::module_local()).def("name", &pets::Pet::name);
// Binding for local extending class:
py::class_<Dog, pets::Pet>(m, "Dog")
.def(py::init<std::string>());
py::class_<Dog, pets::Pet>(m, "Dog").def(py::init<std::string>());
m.def("pet_name", [](pets::Pet &p) { return p.name(); });
py::class_<MixGL>(m, "MixGL", py::module_local()).def(py::init<int>());
......
......@@ -8,6 +8,7 @@
*/
#include "pybind11_tests.h"
#include "constructor_stats.h"
#include <functional>
......@@ -31,9 +32,7 @@ std::list<std::function<void(py::module_ &)>> &initializers() {
return inits;
}
test_initializer::test_initializer(Initializer init) {
initializers().emplace_back(init);
}
test_initializer::test_initializer(Initializer init) { initializers().emplace_back(init); }
test_initializer::test_initializer(const char *submodule_name, Initializer init) {
initializers().emplace_back([=](py::module_ &parent) {
......@@ -51,15 +50,16 @@ void bind_ConstructorStats(py::module_ &m) {
.def_readwrite("move_assignments", &ConstructorStats::move_assignments)
.def_readwrite("copy_constructions", &ConstructorStats::copy_constructions)
.def_readwrite("move_constructions", &ConstructorStats::move_constructions)
.def_static("get", (ConstructorStats &(*)(py::object)) &ConstructorStats::get, py::return_value_policy::reference_internal)
.def_static("get",
(ConstructorStats & (*) (py::object)) & ConstructorStats::get,
py::return_value_policy::reference_internal)
// Not exactly ConstructorStats, but related: expose the internal pybind number of registered instances
// to allow instance cleanup checks (invokes a GC first)
// Not exactly ConstructorStats, but related: expose the internal pybind number of
// registered instances to allow instance cleanup checks (invokes a GC first)
.def_static("detail_reg_inst", []() {
ConstructorStats::gc();
return py::detail::get_internals().registered_instances.size();
})
;
});
}
PYBIND11_MODULE(pybind11_tests, m) {
......@@ -79,12 +79,12 @@ PYBIND11_MODULE(pybind11_tests, m) {
.def("get_value", &UserType::value, "Get value using a method")
.def("set_value", &UserType::set, "Set value using a method")
.def_property("value", &UserType::value, &UserType::set, "Get/set value using a property")
.def("__repr__", [](const UserType& u) { return "UserType({})"_s.format(u.value()); });
.def("__repr__", [](const UserType &u) { return "UserType({})"_s.format(u.value()); });
py::class_<IncType, UserType>(m, "IncType")
.def(py::init<>())
.def(py::init<int>())
.def("__repr__", [](const IncType& u) { return "IncType({})"_s.format(u.value()); });
.def("__repr__", [](const IncType &u) { return "IncType({})"_s.format(u.value()); });
for (const auto &initializer : initializers()) {
initializer(m);
......
#pragma once
#include <pybind11/pybind11.h>
#include <pybind11/eval.h>
#include <pybind11/pybind11.h>
#if defined(_MSC_VER) && _MSC_VER < 1910
// We get some really long type names here which causes MSVC 2015 to emit warnings
# pragma warning(disable : 4503) // NOLINT: warning C4503: decorated name length exceeded, name was truncated
# pragma warning( \
disable : 4503) // NOLINT: warning C4503: decorated name length exceeded, name was truncated
#endif
namespace py = pybind11;
......@@ -25,13 +26,13 @@ public:
void test_submodule_##name(py::module_ &(variable))
/// Dummy type which is not exported anywhere -- something to trigger a conversion error
struct UnregisteredType { };
struct UnregisteredType {};
/// A user-defined type which is exported and can be used by any test
class UserType {
public:
UserType() = default;
explicit UserType(int i) : i(i) { }
explicit UserType(int i) : i(i) {}
int value() const { return i; }
void set(int set) { i = set; }
......@@ -45,7 +46,7 @@ class IncType : public UserType {
public:
using UserType::UserType;
IncType() = default;
IncType(const IncType &other) : IncType(other.value() + 1) { }
IncType(const IncType &other) : IncType(other.value() + 1) {}
IncType(IncType &&) = delete;
IncType &operator=(const IncType &) = delete;
IncType &operator=(IncType &&) = delete;
......@@ -57,16 +58,21 @@ union IntFloat {
float f;
};
/// Custom cast-only type that casts to a string "rvalue" or "lvalue" depending on the cast context.
/// Used to test recursive casters (e.g. std::tuple, stl containers).
/// Custom cast-only type that casts to a string "rvalue" or "lvalue" depending on the cast
/// context. Used to test recursive casters (e.g. std::tuple, stl containers).
struct RValueCaster {};
PYBIND11_NAMESPACE_BEGIN(pybind11)
PYBIND11_NAMESPACE_BEGIN(detail)
template<> class type_caster<RValueCaster> {
template <>
class type_caster<RValueCaster> {
public:
PYBIND11_TYPE_CASTER(RValueCaster, const_name("RValueCaster"));
static handle cast(RValueCaster &&, return_value_policy, handle) { return py::str("rvalue").release(); }
static handle cast(const RValueCaster &, return_value_policy, handle) { return py::str("lvalue").release(); }
static handle cast(RValueCaster &&, return_value_policy, handle) {
return py::str("rvalue").release();
}
static handle cast(const RValueCaster &, return_value_policy, handle) {
return py::str("lvalue").release();
}
};
PYBIND11_NAMESPACE_END(detail)
PYBIND11_NAMESPACE_END(pybind11)
......@@ -80,5 +86,6 @@ void ignoreOldStyleInitWarnings(F &&body) {
with warnings.catch_warnings():
warnings.filterwarnings("ignore", message=message, category=FutureWarning)
body()
)", py::dict(py::arg("body") = py::cpp_function(body)));
)",
py::dict(py::arg("body") = py::cpp_function(body)));
}
......@@ -11,12 +11,11 @@
TEST_SUBMODULE(async_module, m) {
struct DoesNotSupportAsync {};
py::class_<DoesNotSupportAsync>(m, "DoesNotSupportAsync")
.def(py::init<>());
py::class_<DoesNotSupportAsync>(m, "DoesNotSupportAsync").def(py::init<>());
struct SupportsAsync {};
py::class_<SupportsAsync>(m, "SupportsAsync")
.def(py::init<>())
.def("__await__", [](const SupportsAsync& self) -> py::object {
.def("__await__", [](const SupportsAsync &self) -> py::object {
static_cast<void>(self);
py::object loop = py::module_::import("asyncio.events").attr("get_event_loop")();
py::object f = loop.attr("create_future")();
......
......@@ -7,10 +7,11 @@
BSD-style license that can be found in the LICENSE file.
*/
#include "pybind11_tests.h"
#include "constructor_stats.h"
#include <pybind11/stl.h>
#include "constructor_stats.h"
#include "pybind11_tests.h"
TEST_SUBMODULE(buffers, m) {
// test_from_python / test_to_python:
class Matrix {
......@@ -23,7 +24,8 @@ TEST_SUBMODULE(buffers, m) {
}
Matrix(const Matrix &s) : m_rows(s.m_rows), m_cols(s.m_cols) {
print_copy_created(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
print_copy_created(this,
std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
// NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
m_data = new float[(size_t) (m_rows * m_cols)];
memcpy(m_data, s.m_data, sizeof(float) * (size_t) (m_rows * m_cols));
......@@ -37,7 +39,8 @@ TEST_SUBMODULE(buffers, m) {
}
~Matrix() {
print_destroyed(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
print_destroyed(this,
std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
delete[] m_data;
}
......@@ -56,27 +59,33 @@ TEST_SUBMODULE(buffers, m) {
}
Matrix &operator=(Matrix &&s) noexcept {
print_move_assigned(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
print_move_assigned(this,
std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
if (&s != this) {
delete[] m_data;
m_rows = s.m_rows; m_cols = s.m_cols; m_data = s.m_data;
s.m_rows = 0; s.m_cols = 0; s.m_data = nullptr;
m_rows = s.m_rows;
m_cols = s.m_cols;
m_data = s.m_data;
s.m_rows = 0;
s.m_cols = 0;
s.m_data = nullptr;
}
return *this;
}
float operator()(py::ssize_t i, py::ssize_t j) const {
return m_data[(size_t) (i*m_cols + j)];
return m_data[(size_t) (i * m_cols + j)];
}
float &operator()(py::ssize_t i, py::ssize_t j) {
return m_data[(size_t) (i*m_cols + j)];
return m_data[(size_t) (i * m_cols + j)];
}
float *data() { return m_data; }
py::ssize_t rows() const { return m_rows; }
py::ssize_t cols() const { return m_cols; }
private:
py::ssize_t m_rows;
py::ssize_t m_cols;
......@@ -117,11 +126,10 @@ TEST_SUBMODULE(buffers, m) {
/// Provide buffer access
.def_buffer([](Matrix &m) -> py::buffer_info {
return py::buffer_info(
m.data(), /* Pointer to buffer */
{ m.rows(), m.cols() }, /* Buffer dimensions */
{ sizeof(float) * size_t(m.cols()), /* Strides (in bytes) for each index */
sizeof(float) }
);
m.data(), /* Pointer to buffer */
{m.rows(), m.cols()}, /* Buffer dimensions */
{sizeof(float) * size_t(m.cols()), /* Strides (in bytes) for each index */
sizeof(float)});
});
// test_inherited_protocol
......@@ -130,9 +138,7 @@ TEST_SUBMODULE(buffers, m) {
explicit SquareMatrix(py::ssize_t n) : Matrix(n, n) {}
};
// Derived classes inherit the buffer protocol and the buffer access function
py::class_<SquareMatrix, Matrix>(m, "SquareMatrix")
.def(py::init<py::ssize_t>());
py::class_<SquareMatrix, Matrix>(m, "SquareMatrix").def(py::init<py::ssize_t>());
// test_pointer_to_member_fn
// Tests that passing a pointer to member to the base class works in
......@@ -141,8 +147,8 @@ TEST_SUBMODULE(buffers, m) {
int32_t value = 0;
py::buffer_info get_buffer_info() {
return py::buffer_info(&value, sizeof(value),
py::format_descriptor<int32_t>::format(), 1);
return py::buffer_info(
&value, sizeof(value), py::format_descriptor<int32_t>::format(), 1);
}
};
py::class_<Buffer>(m, "Buffer", py::buffer_protocol())
......@@ -150,7 +156,6 @@ TEST_SUBMODULE(buffers, m) {
.def_readwrite("value", &Buffer::value)
.def_buffer(&Buffer::get_buffer_info);
class ConstBuffer {
std::unique_ptr<int32_t> value;
......@@ -159,8 +164,8 @@ TEST_SUBMODULE(buffers, m) {
void set_value(int32_t v) { *value = v; }
py::buffer_info get_buffer_info() const {
return py::buffer_info(value.get(), sizeof(*value),
py::format_descriptor<int32_t>::format(), 1);
return py::buffer_info(
value.get(), sizeof(*value), py::format_descriptor<int32_t>::format(), 1);
}
ConstBuffer() : value(new int32_t{0}) {}
......@@ -170,7 +175,7 @@ TEST_SUBMODULE(buffers, m) {
.def_property("value", &ConstBuffer::get_value, &ConstBuffer::set_value)
.def_buffer(&ConstBuffer::get_buffer_info);
struct DerivedBuffer : public Buffer { };
struct DerivedBuffer : public Buffer {};
py::class_<DerivedBuffer>(m, "DerivedBuffer", py::buffer_protocol())
.def(py::init<>())
.def_readwrite("value", (int32_t DerivedBuffer::*) &DerivedBuffer::value)
......@@ -180,9 +185,7 @@ TEST_SUBMODULE(buffers, m) {
const uint8_t value = 0;
explicit BufferReadOnly(uint8_t value) : value(value) {}
py::buffer_info get_buffer_info() {
return py::buffer_info(&value, 1);
}
py::buffer_info get_buffer_info() { return py::buffer_info(&value, 1); }
};
py::class_<BufferReadOnly>(m, "BufferReadOnly", py::buffer_protocol())
.def(py::init<uint8_t>())
......@@ -192,9 +195,7 @@ TEST_SUBMODULE(buffers, m) {
uint8_t value = 0;
bool readonly = false;
py::buffer_info get_buffer_info() {
return py::buffer_info(&value, 1, readonly);
}
py::buffer_info get_buffer_info() { return py::buffer_info(&value, 1, readonly); }
};
py::class_<BufferReadOnlySelect>(m, "BufferReadOnlySelect", py::buffer_protocol())
.def(py::init<>())
......@@ -213,9 +214,11 @@ TEST_SUBMODULE(buffers, m) {
.def_readonly("strides", &py::buffer_info::strides)
.def_readonly("readonly", &py::buffer_info::readonly)
.def("__repr__", [](py::handle self) {
return py::str("itemsize={0.itemsize!r}, size={0.size!r}, format={0.format!r}, ndim={0.ndim!r}, shape={0.shape!r}, strides={0.strides!r}, readonly={0.readonly!r}").format(self);
})
;
return py::str("itemsize={0.itemsize!r}, size={0.size!r}, format={0.format!r}, "
"ndim={0.ndim!r}, shape={0.shape!r}, strides={0.strides!r}, "
"readonly={0.readonly!r}")
.format(self);
});
m.def("get_buffer_info", [](const py::buffer &buffer) { return buffer.request(); });
}
......@@ -7,64 +7,67 @@
BSD-style license that can be found in the LICENSE file.
*/
#include "pybind11_tests.h"
#include <pybind11/complex.h>
#include "pybind11_tests.h"
struct ConstRefCasted {
int tag;
int tag;
};
PYBIND11_NAMESPACE_BEGIN(pybind11)
PYBIND11_NAMESPACE_BEGIN(detail)
template <>
class type_caster<ConstRefCasted> {
public:
static constexpr auto name = const_name<ConstRefCasted>();
// Input is unimportant, a new value will always be constructed based on the
// cast operator.
bool load(handle, bool) { return true; }
explicit operator ConstRefCasted &&() {
value = {1};
// NOLINTNEXTLINE(performance-move-const-arg)
return std::move(value);
}
explicit operator ConstRefCasted &() {
value = {2};
return value;
}
explicit operator ConstRefCasted *() {
value = {3};
return &value;
}
explicit operator const ConstRefCasted &() {
value = {4};
return value;
}
explicit operator const ConstRefCasted *() {
value = {5};
return &value;
}
// custom cast_op to explicitly propagate types to the conversion operators.
template <typename T_>
using cast_op_type =
/// const
conditional_t<
std::is_same<remove_reference_t<T_>, const ConstRefCasted*>::value, const ConstRefCasted*,
conditional_t<
std::is_same<T_, const ConstRefCasted&>::value, const ConstRefCasted&,
/// non-const
conditional_t<
std::is_same<remove_reference_t<T_>, ConstRefCasted*>::value, ConstRefCasted*,
conditional_t<
std::is_same<T_, ConstRefCasted&>::value, ConstRefCasted&,
/* else */ConstRefCasted&&>>>>;
private:
ConstRefCasted value = {0};
public:
static constexpr auto name = const_name<ConstRefCasted>();
// Input is unimportant, a new value will always be constructed based on the
// cast operator.
bool load(handle, bool) { return true; }
explicit operator ConstRefCasted &&() {
value = {1};
// NOLINTNEXTLINE(performance-move-const-arg)
return std::move(value);
}
explicit operator ConstRefCasted &() {
value = {2};
return value;
}
explicit operator ConstRefCasted *() {
value = {3};
return &value;
}
explicit operator const ConstRefCasted &() {
value = {4};
return value;
}
explicit operator const ConstRefCasted *() {
value = {5};
return &value;
}
// custom cast_op to explicitly propagate types to the conversion operators.
template <typename T_>
using cast_op_type =
/// const
conditional_t<
std::is_same<remove_reference_t<T_>, const ConstRefCasted *>::value,
const ConstRefCasted *,
conditional_t<
std::is_same<T_, const ConstRefCasted &>::value,
const ConstRefCasted &,
/// non-const
conditional_t<std::is_same<remove_reference_t<T_>, ConstRefCasted *>::value,
ConstRefCasted *,
conditional_t<std::is_same<T_, ConstRefCasted &>::value,
ConstRefCasted &,
/* else */ ConstRefCasted &&>>>>;
private:
ConstRefCasted value = {0};
};
PYBIND11_NAMESPACE_END(detail)
PYBIND11_NAMESPACE_END(pybind11)
......@@ -74,25 +77,43 @@ TEST_SUBMODULE(builtin_casters, m) {
m.def("string_roundtrip", [](const char *s) { return s; });
// test_unicode_conversion
// Some test characters in utf16 and utf32 encodings. The last one (the 𝐀) contains a null byte
char32_t a32 = 0x61 /*a*/, z32 = 0x7a /*z*/, ib32 = 0x203d /*‽*/, cake32 = 0x1f382 /*🎂*/, mathbfA32 = 0x1d400 /*𝐀*/;
char16_t b16 = 0x62 /*b*/, z16 = 0x7a, ib16 = 0x203d, cake16_1 = 0xd83c, cake16_2 = 0xdf82, mathbfA16_1 = 0xd835, mathbfA16_2 = 0xdc00;
// Some test characters in utf16 and utf32 encodings. The last one (the 𝐀) contains a null
// byte
char32_t a32 = 0x61 /*a*/, z32 = 0x7a /*z*/, ib32 = 0x203d /*‽*/, cake32 = 0x1f382 /*🎂*/,
mathbfA32 = 0x1d400 /*𝐀*/;
char16_t b16 = 0x62 /*b*/, z16 = 0x7a, ib16 = 0x203d, cake16_1 = 0xd83c, cake16_2 = 0xdf82,
mathbfA16_1 = 0xd835, mathbfA16_2 = 0xdc00;
std::wstring wstr;
wstr.push_back(0x61); // a
wstr.push_back(0x61); // a
wstr.push_back(0x2e18); // ⸘
if (PYBIND11_SILENCE_MSVC_C4127(sizeof(wchar_t) == 2)) { wstr.push_back(mathbfA16_1); wstr.push_back(mathbfA16_2); } // 𝐀, utf16
else { wstr.push_back((wchar_t) mathbfA32); } // 𝐀, utf32
if (PYBIND11_SILENCE_MSVC_C4127(sizeof(wchar_t) == 2)) {
wstr.push_back(mathbfA16_1);
wstr.push_back(mathbfA16_2);
} // 𝐀, utf16
else {
wstr.push_back((wchar_t) mathbfA32);
} // 𝐀, utf32
wstr.push_back(0x7a); // z
m.def("good_utf8_string", []() { return std::string((const char*)u8"Say utf8\u203d \U0001f382 \U0001d400"); }); // Say utf8‽ 🎂 𝐀
m.def("good_utf16_string", [=]() { return std::u16string({ b16, ib16, cake16_1, cake16_2, mathbfA16_1, mathbfA16_2, z16 }); }); // b‽🎂𝐀z
m.def("good_utf32_string", [=]() { return std::u32string({ a32, mathbfA32, cake32, ib32, z32 }); }); // a𝐀🎂‽z
m.def("good_utf8_string", []() {
return std::string((const char *) u8"Say utf8\u203d \U0001f382 \U0001d400");
}); // Say utf8‽ 🎂 𝐀
m.def("good_utf16_string", [=]() {
return std::u16string({b16, ib16, cake16_1, cake16_2, mathbfA16_1, mathbfA16_2, z16});
}); // b‽🎂𝐀z
m.def("good_utf32_string", [=]() {
return std::u32string({a32, mathbfA32, cake32, ib32, z32});
}); // a𝐀🎂‽z
m.def("good_wchar_string", [=]() { return wstr; }); // a‽𝐀z
m.def("bad_utf8_string", []() { return std::string("abc\xd0" "def"); });
m.def("bad_utf16_string", [=]() { return std::u16string({ b16, char16_t(0xd800), z16 }); });
m.def("bad_utf8_string", []() {
return std::string("abc\xd0"
"def");
});
m.def("bad_utf16_string", [=]() { return std::u16string({b16, char16_t(0xd800), z16}); });
#if PY_MAJOR_VERSION >= 3
// Under Python 2.7, invalid unicode UTF-32 characters don't appear to trigger UnicodeDecodeError
m.def("bad_utf32_string", [=]() { return std::u32string({ a32, char32_t(0xd800), z32 }); });
// Under Python 2.7, invalid unicode UTF-32 characters don't appear to trigger
// UnicodeDecodeError
m.def("bad_utf32_string", [=]() { return std::u32string({a32, char32_t(0xd800), z32}); });
if (PYBIND11_SILENCE_MSVC_C4127(sizeof(wchar_t) == 2)) {
m.def("bad_wchar_string", [=]() {
return std::wstring({wchar_t(0x61), wchar_t(0xd800)});
......@@ -120,8 +141,13 @@ TEST_SUBMODULE(builtin_casters, m) {
#ifdef PYBIND11_HAS_U8STRING
m.attr("has_u8string") = true;
m.def("good_utf8_u8string", []() { return std::u8string(u8"Say utf8\u203d \U0001f382 \U0001d400"); }); // Say utf8‽ 🎂 𝐀
m.def("bad_utf8_u8string", []() { return std::u8string((const char8_t*)"abc\xd0" "def"); });
m.def("good_utf8_u8string", []() {
return std::u8string(u8"Say utf8\u203d \U0001f382 \U0001d400");
}); // Say utf8‽ 🎂 𝐀
m.def("bad_utf8_u8string", []() {
return std::u8string((const char8_t *) "abc\xd0"
"def");
});
m.def("u8_char8_Z", []() -> char8_t { return u8'Z'; });
......@@ -133,46 +159,63 @@ TEST_SUBMODULE(builtin_casters, m) {
// test_string_view
#ifdef PYBIND11_HAS_STRING_VIEW
m.attr("has_string_view") = true;
m.def("string_view_print", [](std::string_view s) { py::print(s, s.size()); });
m.def("string_view_print", [](std::string_view s) { py::print(s, s.size()); });
m.def("string_view16_print", [](std::u16string_view s) { py::print(s, s.size()); });
m.def("string_view32_print", [](std::u32string_view s) { py::print(s, s.size()); });
m.def("string_view_chars", [](std::string_view s) { py::list l;
m.def("string_view_chars", [](std::string_view s) {
py::list l;
for (auto c : s) {
l.append((std::uint8_t) c);
}
return l; });
m.def("string_view16_chars", [](std::u16string_view s) { py::list l;
return l;
});
m.def("string_view16_chars", [](std::u16string_view s) {
py::list l;
for (auto c : s) {
l.append((int) c);
}
return l; });
m.def("string_view32_chars", [](std::u32string_view s) { py::list l;
return l;
});
m.def("string_view32_chars", [](std::u32string_view s) {
py::list l;
for (auto c : s) {
l.append((int) c);
}
return l; });
m.def("string_view_return", []() { return std::string_view((const char*)u8"utf8 secret \U0001f382"); });
m.def("string_view16_return", []() { return std::u16string_view(u"utf16 secret \U0001f382"); });
m.def("string_view32_return", []() { return std::u32string_view(U"utf32 secret \U0001f382"); });
return l;
});
m.def("string_view_return",
[]() { return std::string_view((const char *) u8"utf8 secret \U0001f382"); });
m.def("string_view16_return",
[]() { return std::u16string_view(u"utf16 secret \U0001f382"); });
m.def("string_view32_return",
[]() { return std::u32string_view(U"utf32 secret \U0001f382"); });
// The inner lambdas here are to also test implicit conversion
using namespace std::literals;
m.def("string_view_bytes", []() { return [](py::bytes b) { return b; }("abc \x80\x80 def"sv); });
m.def("string_view_str", []() { return [](py::str s) { return s; }("abc \342\200\275 def"sv); });
m.def("string_view_from_bytes", [](const py::bytes &b) { return [](std::string_view s) { return s; }(b); });
#if PY_MAJOR_VERSION >= 3
m.def("string_view_bytes",
[]() { return [](py::bytes b) { return b; }("abc \x80\x80 def"sv); });
m.def("string_view_str",
[]() { return [](py::str s) { return s; }("abc \342\200\275 def"sv); });
m.def("string_view_from_bytes",
[](const py::bytes &b) { return [](std::string_view s) { return s; }(b); });
# if PY_MAJOR_VERSION >= 3
m.def("string_view_memoryview", []() {
static constexpr auto val = "Have some \360\237\216\202"sv;
return py::memoryview::from_memory(val);
});
#endif
# endif
# ifdef PYBIND11_HAS_U8STRING
m.def("string_view8_print", [](std::u8string_view s) { py::print(s, s.size()); });
m.def("string_view8_chars", [](std::u8string_view s) { py::list l; for (auto c : s) l.append((std::uint8_t) c); return l; });
# ifdef PYBIND11_HAS_U8STRING
m.def("string_view8_print", [](std::u8string_view s) { py::print(s, s.size()); });
m.def("string_view8_chars", [](std::u8string_view s) {
py::list l;
for (auto c : s)
l.append((std::uint8_t) c);
return l;
});
m.def("string_view8_return", []() { return std::u8string_view(u8"utf8 secret \U0001f382"); });
m.def("string_view8_str", []() { return py::str{std::u8string_view{u8"abc ‽ def"}}; });
# endif
m.def("string_view8_str", []() { return py::str{std::u8string_view{u8"abc ‽ def"}}; });
# endif
struct TypeWithBothOperatorStringAndStringView {
// NOLINTNEXTLINE(google-explicit-constructor)
......@@ -194,7 +237,8 @@ TEST_SUBMODULE(builtin_casters, m) {
// test_int_convert
m.def("int_passthrough", [](int arg) { return arg; });
m.def("int_passthrough_noconvert", [](int arg) { return arg; }, py::arg{}.noconvert());
m.def(
"int_passthrough_noconvert", [](int arg) { return arg; }, py::arg{}.noconvert());
// test_tuple
m.def(
......@@ -203,19 +247,27 @@ TEST_SUBMODULE(builtin_casters, m) {
return std::make_pair(input.second, input.first);
},
"Return a pair in reversed order");
m.def("tuple_passthrough", [](std::tuple<bool, std::string, int> input) {
return std::make_tuple(std::get<2>(input), std::get<1>(input), std::get<0>(input));
}, "Return a triple in reversed order");
m.def(
"tuple_passthrough",
[](std::tuple<bool, std::string, int> input) {
return std::make_tuple(std::get<2>(input), std::get<1>(input), std::get<0>(input));
},
"Return a triple in reversed order");
m.def("empty_tuple", []() { return std::tuple<>(); });
static std::pair<RValueCaster, RValueCaster> lvpair;
static std::tuple<RValueCaster, RValueCaster, RValueCaster> lvtuple;
static std::pair<RValueCaster, std::tuple<RValueCaster, std::pair<RValueCaster, RValueCaster>>> lvnested;
static std::pair<RValueCaster, std::tuple<RValueCaster, std::pair<RValueCaster, RValueCaster>>>
lvnested;
m.def("rvalue_pair", []() { return std::make_pair(RValueCaster{}, RValueCaster{}); });
m.def("lvalue_pair", []() -> const decltype(lvpair) & { return lvpair; });
m.def("rvalue_tuple", []() { return std::make_tuple(RValueCaster{}, RValueCaster{}, RValueCaster{}); });
m.def("rvalue_tuple",
[]() { return std::make_tuple(RValueCaster{}, RValueCaster{}, RValueCaster{}); });
m.def("lvalue_tuple", []() -> const decltype(lvtuple) & { return lvtuple; });
m.def("rvalue_nested", []() {
return std::make_pair(RValueCaster{}, std::make_tuple(RValueCaster{}, std::make_pair(RValueCaster{}, RValueCaster{}))); });
return std::make_pair(
RValueCaster{},
std::make_tuple(RValueCaster{}, std::make_pair(RValueCaster{}, RValueCaster{})));
});
m.def("lvalue_nested", []() -> const decltype(lvnested) & { return lvnested; });
static std::pair<int, std::string> int_string_pair{2, "items"};
......@@ -223,11 +275,11 @@ TEST_SUBMODULE(builtin_casters, m) {
// test_builtins_cast_return_none
m.def("return_none_string", []() -> std::string * { return nullptr; });
m.def("return_none_char", []() -> const char * { return nullptr; });
m.def("return_none_bool", []() -> bool * { return nullptr; });
m.def("return_none_int", []() -> int * { return nullptr; });
m.def("return_none_float", []() -> float * { return nullptr; });
m.def("return_none_pair", []() -> std::pair<int,int> * { return nullptr; });
m.def("return_none_char", []() -> const char * { return nullptr; });
m.def("return_none_bool", []() -> bool * { return nullptr; });
m.def("return_none_int", []() -> int * { return nullptr; });
m.def("return_none_float", []() -> float * { return nullptr; });
m.def("return_none_pair", []() -> std::pair<int, int> * { return nullptr; });
// test_none_deferred
m.def("defer_none_cstring", [](char *) { return false; });
......@@ -245,7 +297,8 @@ TEST_SUBMODULE(builtin_casters, m) {
// test_bool_caster
m.def("bool_passthrough", [](bool arg) { return arg; });
m.def("bool_passthrough_noconvert", [](bool arg) { return arg; }, py::arg{}.noconvert());
m.def(
"bool_passthrough_noconvert", [](bool arg) { return arg; }, py::arg{}.noconvert());
// TODO: This should be disabled and fixed in future Intel compilers
#if !defined(__INTEL_COMPILER)
......@@ -253,13 +306,15 @@ TEST_SUBMODULE(builtin_casters, m) {
// When compiled with the Intel compiler, this results in segmentation faults when importing
// the module. Tested with icc (ICC) 2021.1 Beta 20200827, this should be tested again when
// a newer version of icc is available.
m.def("bool_passthrough_noconvert2", [](bool arg) { return arg; }, py::arg().noconvert());
m.def(
"bool_passthrough_noconvert2", [](bool arg) { return arg; }, py::arg().noconvert());
#endif
// test_reference_wrapper
m.def("refwrap_builtin", [](std::reference_wrapper<int> p) { return 10 * p.get(); });
m.def("refwrap_usertype", [](std::reference_wrapper<UserType> p) { return p.get().value(); });
m.def("refwrap_usertype_const", [](std::reference_wrapper<const UserType> p) { return p.get().value(); });
m.def("refwrap_usertype_const",
[](std::reference_wrapper<const UserType> p) { return p.get().value(); });
m.def("refwrap_lvalue", []() -> std::reference_wrapper<UserType> {
static UserType x(1);
......@@ -272,17 +327,20 @@ TEST_SUBMODULE(builtin_casters, m) {
// Not currently supported (std::pair caster has return-by-value cast operator);
// triggers static_assert failure.
//m.def("refwrap_pair", [](std::reference_wrapper<std::pair<int, int>>) { });
// m.def("refwrap_pair", [](std::reference_wrapper<std::pair<int, int>>) { });
m.def("refwrap_list", [](bool copy) {
static IncType x1(1), x2(2);
py::list l;
for (const auto &f : {std::ref(x1), std::ref(x2)}) {
l.append(py::cast(f, copy ? py::return_value_policy::copy
: py::return_value_policy::reference));
}
return l;
}, "copy"_a);
m.def(
"refwrap_list",
[](bool copy) {
static IncType x1(1), x2(2);
py::list l;
for (const auto &f : {std::ref(x1), std::ref(x2)}) {
l.append(py::cast(
f, copy ? py::return_value_policy::copy : py::return_value_policy::reference));
}
return l;
},
"copy"_a);
m.def("refwrap_iiw", [](const IncType &w) { return w.value(); });
m.def("refwrap_call_iiw", [](IncType &w, const py::function &f) {
......@@ -299,12 +357,13 @@ TEST_SUBMODULE(builtin_casters, m) {
// test_complex
m.def("complex_cast", [](float x) { return "{}"_s.format(x); });
m.def("complex_cast", [](std::complex<float> x) { return "({}, {})"_s.format(x.real(), x.imag()); });
m.def("complex_cast",
[](std::complex<float> x) { return "({}, {})"_s.format(x.real(), x.imag()); });
// test int vs. long (Python 2)
m.def("int_cast", []() {return (int) 42;});
m.def("long_cast", []() {return (long) 42;});
m.def("longlong_cast", []() {return ULLONG_MAX;});
m.def("int_cast", []() { return (int) 42; });
m.def("long_cast", []() { return (long) 42; });
m.def("longlong_cast", []() { return ULLONG_MAX; });
/// test void* cast operator
m.def("test_void_caster", []() -> bool {
......@@ -315,11 +374,12 @@ TEST_SUBMODULE(builtin_casters, m) {
// Tests const/non-const propagation in cast_op.
m.def("takes", [](ConstRefCasted x) { return x.tag; });
m.def("takes_move", [](ConstRefCasted&& x) { return x.tag; });
m.def("takes_ptr", [](ConstRefCasted* x) { return x->tag; });
m.def("takes_ref", [](ConstRefCasted& x) { return x.tag; });
m.def("takes_move", [](ConstRefCasted &&x) { return x.tag; });
m.def("takes_ptr", [](ConstRefCasted *x) { return x->tag; });
m.def("takes_ref", [](ConstRefCasted &x) { return x.tag; });
m.def("takes_ref_wrap", [](std::reference_wrapper<ConstRefCasted> x) { return x.get().tag; });
m.def("takes_const_ptr", [](const ConstRefCasted* x) { return x->tag; });
m.def("takes_const_ref", [](const ConstRefCasted& x) { return x.tag; });
m.def("takes_const_ref_wrap", [](std::reference_wrapper<const ConstRefCasted> x) { return x.get().tag; });
m.def("takes_const_ptr", [](const ConstRefCasted *x) { return x->tag; });
m.def("takes_const_ref", [](const ConstRefCasted &x) { return x.tag; });
m.def("takes_const_ref_wrap",
[](std::reference_wrapper<const ConstRefCasted> x) { return x.get().tag; });
}
......@@ -40,18 +40,17 @@ TEST_SUBMODULE(call_policies, m) {
Child(Child &&) = default;
~Child() { py::print("Releasing child."); }
};
py::class_<Child>(m, "Child")
.def(py::init<>());
py::class_<Child>(m, "Child").def(py::init<>());
class Parent {
public:
Parent() { py::print("Allocating parent."); }
Parent(const Parent& parent) = default;
Parent(const Parent &parent) = default;
~Parent() { py::print("Releasing parent."); }
void addChild(Child *) { }
void addChild(Child *) {}
Child *returnChild() { return new Child(); }
Child *returnNullChild() { return nullptr; }
static Child *staticFunction(Parent*) { return new Child(); }
static Child *staticFunction(Parent *) { return new Child(); }
};
py::class_<Parent>(m, "Parent")
.def(py::init<>())
......@@ -62,11 +61,12 @@ TEST_SUBMODULE(call_policies, m) {
.def("returnChildKeepAlive", &Parent::returnChild, py::keep_alive<1, 0>())
.def("returnNullChildKeepAliveChild", &Parent::returnNullChild, py::keep_alive<1, 0>())
.def("returnNullChildKeepAliveParent", &Parent::returnNullChild, py::keep_alive<0, 1>())
.def_static(
"staticFunction", &Parent::staticFunction, py::keep_alive<1, 0>());
.def_static("staticFunction", &Parent::staticFunction, py::keep_alive<1, 0>());
m.def("free_function", [](Parent*, Child*) {}, py::keep_alive<1, 2>());
m.def("invalid_arg_index", []{}, py::keep_alive<0, 1>());
m.def(
"free_function", [](Parent *, Child *) {}, py::keep_alive<1, 2>());
m.def(
"invalid_arg_index", [] {}, py::keep_alive<0, 1>());
#if !defined(PYPY_VERSION)
// test_alive_gc
......@@ -74,21 +74,28 @@ TEST_SUBMODULE(call_policies, m) {
public:
using Parent::Parent;
};
py::class_<ParentGC, Parent>(m, "ParentGC", py::dynamic_attr())
.def(py::init<>());
py::class_<ParentGC, Parent>(m, "ParentGC", py::dynamic_attr()).def(py::init<>());
#endif
// test_call_guard
m.def("unguarded_call", &CustomGuard::report_status);
m.def("guarded_call", &CustomGuard::report_status, py::call_guard<CustomGuard>());
m.def("multiple_guards_correct_order", []() {
return CustomGuard::report_status() + std::string(" & ") + DependentGuard::report_status();
}, py::call_guard<CustomGuard, DependentGuard>());
m.def("multiple_guards_wrong_order", []() {
return DependentGuard::report_status() + std::string(" & ") + CustomGuard::report_status();
}, py::call_guard<DependentGuard, CustomGuard>());
m.def(
"multiple_guards_correct_order",
[]() {
return CustomGuard::report_status() + std::string(" & ")
+ DependentGuard::report_status();
},
py::call_guard<CustomGuard, DependentGuard>());
m.def(
"multiple_guards_wrong_order",
[]() {
return DependentGuard::report_status() + std::string(" & ")
+ CustomGuard::report_status();
},
py::call_guard<DependentGuard, CustomGuard>());
#if defined(WITH_THREAD) && !defined(PYPY_VERSION)
// `py::call_guard<py::gil_scoped_release>()` should work in PyPy as well,
......
......@@ -7,11 +7,12 @@
BSD-style license that can be found in the LICENSE file.
*/
#include "pybind11_tests.h"
#include "constructor_stats.h"
#include <pybind11/functional.h>
#include <thread>
#include "constructor_stats.h"
#include "pybind11_tests.h"
#include <thread>
int dummy_function(int i) { return i + 1; }
......@@ -20,11 +21,12 @@ TEST_SUBMODULE(callbacks, m) {
m.def("test_callback1", [](const py::object &func) { return func(); });
m.def("test_callback2", [](const py::object &func) { return func("Hello", 'x', true, 5); });
m.def("test_callback3", [](const std::function<int(int)> &func) {
return "func(43) = " + std::to_string(func(43)); });
m.def("test_callback4", []() -> std::function<int(int)> { return [](int i) { return i+1; }; });
m.def("test_callback5", []() {
return py::cpp_function([](int i) { return i+1; }, py::arg("number"));
return "func(43) = " + std::to_string(func(43));
});
m.def("test_callback4",
[]() -> std::function<int(int)> { return [](int i) { return i + 1; }; });
m.def("test_callback5",
[]() { return py::cpp_function([](int i) { return i + 1; }, py::arg("number")); });
// test_keyword_args_and_generalized_unpacking
m.def("test_tuple_unpacking", [](const py::function &f) {
......@@ -34,9 +36,9 @@ TEST_SUBMODULE(callbacks, m) {
});
m.def("test_dict_unpacking", [](const py::function &f) {
auto d1 = py::dict("key"_a="value", "a"_a=1);
auto d1 = py::dict("key"_a = "value", "a"_a = 1);
auto d2 = py::dict();
auto d3 = py::dict("b"_a=2);
auto d3 = py::dict("b"_a = 2);
return f("positional", 1, **d1, **d2, **d3);
});
......@@ -44,32 +46,40 @@ TEST_SUBMODULE(callbacks, m) {
m.def("test_unpacking_and_keywords1", [](const py::function &f) {
auto args = py::make_tuple(2);
auto kwargs = py::dict("d"_a=4);
return f(1, *args, "c"_a=3, **kwargs);
auto kwargs = py::dict("d"_a = 4);
return f(1, *args, "c"_a = 3, **kwargs);
});
m.def("test_unpacking_and_keywords2", [](const py::function &f) {
auto kwargs1 = py::dict("a"_a=1);
auto kwargs2 = py::dict("c"_a=3, "d"_a=4);
return f("positional", *py::make_tuple(1), 2, *py::make_tuple(3, 4), 5,
"key"_a="value", **kwargs1, "b"_a=2, **kwargs2, "e"_a=5);
auto kwargs1 = py::dict("a"_a = 1);
auto kwargs2 = py::dict("c"_a = 3, "d"_a = 4);
return f("positional",
*py::make_tuple(1),
2,
*py::make_tuple(3, 4),
5,
"key"_a = "value",
**kwargs1,
"b"_a = 2,
**kwargs2,
"e"_a = 5);
});
m.def("test_unpacking_error1", [](const py::function &f) {
auto kwargs = py::dict("x"_a=3);
return f("x"_a=1, "y"_a=2, **kwargs); // duplicate ** after keyword
auto kwargs = py::dict("x"_a = 3);
return f("x"_a = 1, "y"_a = 2, **kwargs); // duplicate ** after keyword
});
m.def("test_unpacking_error2", [](const py::function &f) {
auto kwargs = py::dict("x"_a=3);
return f(**kwargs, "x"_a=1); // duplicate keyword after **
auto kwargs = py::dict("x"_a = 3);
return f(**kwargs, "x"_a = 1); // duplicate keyword after **
});
m.def("test_arg_conversion_error1",
[](const py::function &f) { f(234, UnregisteredType(), "kw"_a = 567); });
m.def("test_arg_conversion_error2", [](const py::function &f) {
f(234, "expected_name"_a=UnregisteredType(), "kw"_a=567);
f(234, "expected_name"_a = UnregisteredType(), "kw"_a = 567);
});
// test_lambda_closure_cleanup
......@@ -158,7 +168,6 @@ TEST_SUBMODULE(callbacks, m) {
return "matches dummy_function: eval(1) = " + std::to_string(r);
}
return "argument does NOT match dummy_function. This should never happen!";
});
class AbstractBase {
......@@ -190,7 +199,7 @@ TEST_SUBMODULE(callbacks, m) {
// test_movable_object
m.def("callback_with_movable", [](const std::function<void(MovableObject &)> &f) {
auto x = MovableObject();
f(x); // lvalue reference shouldn't move out object
f(x); // lvalue reference shouldn't move out object
return x.valid; // must still return `true`
});
......@@ -202,9 +211,10 @@ TEST_SUBMODULE(callbacks, m) {
// This checks that builtin functions can be passed as callbacks
// rather than throwing RuntimeError due to trying to extract as capsule
m.def("test_sum_builtin", [](const std::function<double(py::iterable)> &sum_builtin, const py::iterable &i) {
return sum_builtin(i);
});
m.def("test_sum_builtin",
[](const std::function<double(py::iterable)> &sum_builtin, const py::iterable &i) {
return sum_builtin(i);
});
// test async Python callbacks
using callback_f = std::function<void(int)>;
......
......@@ -8,21 +8,20 @@
BSD-style license that can be found in the LICENSE file.
*/
#include "pybind11_tests.h"
#include <pybind11/chrono.h>
#include "pybind11_tests.h"
#include <chrono>
struct different_resolutions {
using time_point_h = std::chrono::time_point<
std::chrono::system_clock, std::chrono::hours>;
using time_point_m = std::chrono::time_point<
std::chrono::system_clock, std::chrono::minutes>;
using time_point_s = std::chrono::time_point<
std::chrono::system_clock, std::chrono::seconds>;
using time_point_ms = std::chrono::time_point<
std::chrono::system_clock, std::chrono::milliseconds>;
using time_point_us = std::chrono::time_point<
std::chrono::system_clock, std::chrono::microseconds>;
using time_point_h = std::chrono::time_point<std::chrono::system_clock, std::chrono::hours>;
using time_point_m = std::chrono::time_point<std::chrono::system_clock, std::chrono::minutes>;
using time_point_s = std::chrono::time_point<std::chrono::system_clock, std::chrono::seconds>;
using time_point_ms
= std::chrono::time_point<std::chrono::system_clock, std::chrono::milliseconds>;
using time_point_us
= std::chrono::time_point<std::chrono::system_clock, std::chrono::microseconds>;
time_point_h timestamp_h;
time_point_m timestamp_m;
time_point_s timestamp_s;
......@@ -65,12 +64,11 @@ TEST_SUBMODULE(chrono, m) {
// Roundtrip a duration in microseconds from a float argument
m.def("test_chrono7", [](std::chrono::microseconds t) { return t; });
// Float durations (issue #719)
m.def("test_chrono_float_diff", [](std::chrono::duration<float> a, std::chrono::duration<float> b) {
return a - b; });
m.def("test_chrono_float_diff",
[](std::chrono::duration<float> a, std::chrono::duration<float> b) { return a - b; });
m.def("test_nano_timepoint", [](timestamp start, timespan delta) -> timestamp {
return start + delta;
});
m.def("test_nano_timepoint",
[](timestamp start, timespan delta) -> timestamp { return start + delta; });
// Test different resolutions
py::class_<different_resolutions>(m, "different_resolutions")
......@@ -79,6 +77,5 @@ TEST_SUBMODULE(chrono, m) {
.def_readwrite("timestamp_m", &different_resolutions::timestamp_m)
.def_readwrite("timestamp_s", &different_resolutions::timestamp_s)
.def_readwrite("timestamp_ms", &different_resolutions::timestamp_ms)
.def_readwrite("timestamp_us", &different_resolutions::timestamp_us)
;
.def_readwrite("timestamp_us", &different_resolutions::timestamp_us);
}
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