summaryrefslogtreecommitdiff
path: root/ext/pybind11/include/pybind11/attr.h
diff options
context:
space:
mode:
Diffstat (limited to 'ext/pybind11/include/pybind11/attr.h')
-rw-r--r--ext/pybind11/include/pybind11/attr.h132
1 files changed, 96 insertions, 36 deletions
diff --git a/ext/pybind11/include/pybind11/attr.h b/ext/pybind11/include/pybind11/attr.h
index 448612c52..e38a1a32d 100644
--- a/ext/pybind11/include/pybind11/attr.h
+++ b/ext/pybind11/include/pybind11/attr.h
@@ -14,6 +14,9 @@
NAMESPACE_BEGIN(pybind11)
+/// \addtogroup annotations
+/// @{
+
/// Annotation for methods
struct is_method { handle class_; is_method(const handle &c) : class_(c) { } };
@@ -39,7 +42,7 @@ template <typename T> struct base {
};
/// Keep patient alive while nurse lives
-template <int Nurse, int Patient> struct keep_alive { };
+template <size_t Nurse, size_t Patient> struct keep_alive { };
/// Annotation indicating that a class is involved in a multiple inheritance relationship
struct multiple_inheritance { };
@@ -47,9 +50,25 @@ struct multiple_inheritance { };
/// Annotation which enables dynamic attributes, i.e. adds `__dict__` to a class
struct dynamic_attr { };
+/// Annotation which enables the buffer protocol for a type
+struct buffer_protocol { };
+
+/// Annotation which requests that a special metaclass is created for a type
+struct metaclass {
+ handle value;
+
+ PYBIND11_DEPRECATED("py::metaclass() is no longer required. It's turned on by default now.")
+ metaclass() = default;
+
+ /// Override pybind11's default metaclass
+ explicit metaclass(handle value) : value(value) { }
+};
+
/// Annotation to mark enums as an arithmetic type
struct arithmetic { };
+/// @} annotations
+
NAMESPACE_BEGIN(detail)
/* Forward declarations */
enum op_id : int;
@@ -58,16 +77,17 @@ struct undefined_t;
template <op_id id, op_type ot, typename L = undefined_t, typename R = undefined_t> struct op_;
template <typename... Args> struct init;
template <typename... Args> struct init_alias;
-inline void keep_alive_impl(int Nurse, int Patient, handle args, handle ret);
+inline void keep_alive_impl(size_t Nurse, size_t Patient, function_call &call, handle ret);
/// Internal data structure which holds metadata about a keyword argument
struct argument_record {
const char *name; ///< Argument name
const char *descr; ///< Human-readable version of the argument value
handle value; ///< Associated Python object
+ bool convert : 1; ///< True if the argument is allowed to convert when loading
- argument_record(const char *name, const char *descr, handle value)
- : name(name), descr(descr), value(value) { }
+ argument_record(const char *name, const char *descr, handle value, bool convert)
+ : name(name), descr(descr), value(value), convert(convert) { }
};
/// Internal data structure which holds metadata about a bound function (signature, overloads, etc.)
@@ -89,7 +109,7 @@ struct function_record {
std::vector<argument_record> args;
/// Pointer to lambda function which converts arguments and performs the actual call
- handle (*impl) (function_record *, handle, handle, handle) = nullptr;
+ handle (*impl) (function_call &) = nullptr;
/// Storage for the wrapped function pointer and captured data, if any
void *data[3] = { };
@@ -118,8 +138,8 @@ struct function_record {
/// True if this is a method
bool is_method : 1;
- /// Number of arguments
- uint16_t nargs;
+ /// Number of arguments (including py::args and/or py::kwargs, if present)
+ std::uint16_t nargs;
/// Python method object
PyMethodDef *def = nullptr;
@@ -136,7 +156,8 @@ struct function_record {
/// Special data structure which (temporarily) holds metadata about a bound class
struct type_record {
- PYBIND11_NOINLINE type_record() { }
+ PYBIND11_NOINLINE type_record()
+ : multiple_inheritance(false), dynamic_attr(false), buffer_protocol(false) { }
/// Handle to the parent scope
handle scope;
@@ -153,6 +174,9 @@ struct type_record {
/// How large is pybind11::instance<type>?
size_t instance_size = 0;
+ /// The global operator new can be overridden with a class-specific variant
+ void *(*operator_new)(size_t) = ::operator new;
+
/// Function pointer to class_<..>::init_holder
void (*init_holder)(PyObject *, const void *) = nullptr;
@@ -165,11 +189,20 @@ struct type_record {
/// Optional docstring
const char *doc = nullptr;
+ /// Custom metaclass (optional)
+ handle metaclass;
+
/// Multiple inheritance marker
- bool multiple_inheritance = false;
+ bool multiple_inheritance : 1;
/// Does the class manage a __dict__?
- bool dynamic_attr = false;
+ bool dynamic_attr : 1;
+
+ /// Does the class implement the buffer protocol?
+ bool buffer_protocol : 1;
+
+ /// Is the default (unique_ptr) holder type used?
+ bool default_holder : 1;
PYBIND11_NOINLINE void add_base(const std::type_info *base, void *(*caster)(void *)) {
auto base_info = detail::get_type_info(*base, false);
@@ -180,6 +213,15 @@ struct type_record {
"\" referenced unknown base type \"" + tname + "\"");
}
+ if (default_holder != base_info->default_holder) {
+ std::string tname(base->name());
+ detail::clean_type_id(tname);
+ pybind11_fail("generic_type: type \"" + std::string(name) + "\" " +
+ (default_holder ? "does not have" : "has") +
+ " a non-default holder type while its base \"" + tname + "\" " +
+ (base_info->default_holder ? "does not" : "does"));
+ }
+
bases.append((PyObject *) base_info->type);
if (base_info->type->tp_dictoffset != 0)
@@ -190,6 +232,12 @@ struct type_record {
}
};
+inline function_call::function_call(function_record &f, handle p) :
+ func(f), parent(p) {
+ args.reserve(f.nargs);
+ args_convert.reserve(f.nargs);
+}
+
/**
* Partial template specializations to process custom attributes provided to
* cpp_function_ and class_. These are either used to initialize the respective
@@ -202,8 +250,8 @@ template <typename T> struct process_attribute_default {
/// Default implementation: do nothing
static void init(const T &, function_record *) { }
static void init(const T &, type_record *) { }
- static void precall(handle) { }
- static void postcall(handle, handle) { }
+ static void precall(function_call &) { }
+ static void postcall(function_call &, handle) { }
};
/// Process an attribute specifying the function's name
@@ -252,8 +300,8 @@ template <> struct process_attribute<is_operator> : process_attribute_default<is
template <> struct process_attribute<arg> : process_attribute_default<arg> {
static void init(const arg &a, function_record *r) {
if (r->is_method && r->args.empty())
- r->args.emplace_back("self", nullptr, handle());
- r->args.emplace_back(a.name, nullptr, handle());
+ r->args.emplace_back("self", nullptr, handle(), true /*convert*/);
+ r->args.emplace_back(a.name, nullptr, handle(), !a.flag_noconvert);
}
};
@@ -261,32 +309,34 @@ template <> struct process_attribute<arg> : process_attribute_default<arg> {
template <> struct process_attribute<arg_v> : process_attribute_default<arg_v> {
static void init(const arg_v &a, function_record *r) {
if (r->is_method && r->args.empty())
- r->args.emplace_back("self", nullptr, handle());
+ r->args.emplace_back("self", nullptr /*descr*/, handle() /*parent*/, true /*convert*/);
if (!a.value) {
#if !defined(NDEBUG)
- auto descr = "'" + std::string(a.name) + ": " + a.type + "'";
+ std::string descr("'");
+ if (a.name) descr += std::string(a.name) + ": ";
+ descr += a.type + "'";
if (r->is_method) {
if (r->name)
descr += " in method '" + (std::string) str(r->scope) + "." + (std::string) r->name + "'";
else
descr += " in method of '" + (std::string) str(r->scope) + "'";
} else if (r->name) {
- descr += " in function named '" + (std::string) r->name + "'";
+ descr += " in function '" + (std::string) r->name + "'";
}
- pybind11_fail("arg(): could not convert default keyword argument "
+ pybind11_fail("arg(): could not convert default argument "
+ descr + " into a Python object (type not registered yet?)");
#else
- pybind11_fail("arg(): could not convert default keyword argument "
+ pybind11_fail("arg(): could not convert default argument "
"into a Python object (type not registered yet?). "
"Compile in debug mode for more information.");
#endif
}
- r->args.emplace_back(a.name, a.descr, a.value.inc_ref());
+ r->args.emplace_back(a.name, a.descr, a.value.inc_ref(), !a.flag_noconvert);
}
};
-/// Process a parent class attribute
+/// Process a parent class attribute. Single inheritance only (class_ itself already guarantees that)
template <typename T>
struct process_attribute<T, enable_if_t<is_pyobject<T>::value>> : process_attribute_default<handle> {
static void init(const handle &h, type_record *r) { r->bases.append(h); }
@@ -309,6 +359,16 @@ struct process_attribute<dynamic_attr> : process_attribute_default<dynamic_attr>
static void init(const dynamic_attr &, type_record *r) { r->dynamic_attr = true; }
};
+template <>
+struct process_attribute<buffer_protocol> : process_attribute_default<buffer_protocol> {
+ static void init(const buffer_protocol &, type_record *r) { r->buffer_protocol = true; }
+};
+
+template <>
+struct process_attribute<metaclass> : process_attribute_default<metaclass> {
+ static void init(const metaclass &m, type_record *r) { r->metaclass = m.value; }
+};
+
/// Process an 'arithmetic' attribute for enums (does nothing here)
template <>
@@ -319,15 +379,15 @@ struct process_attribute<arithmetic> : process_attribute_default<arithmetic> {};
* pre-call handler if both Nurse, Patient != 0 and use the post-call handler
* otherwise
*/
-template <int Nurse, int Patient> struct process_attribute<keep_alive<Nurse, Patient>> : public process_attribute_default<keep_alive<Nurse, Patient>> {
- template <int N = Nurse, int P = Patient, enable_if_t<N != 0 && P != 0, int> = 0>
- static void precall(handle args) { keep_alive_impl(Nurse, Patient, args, handle()); }
- template <int N = Nurse, int P = Patient, enable_if_t<N != 0 && P != 0, int> = 0>
- static void postcall(handle, handle) { }
- template <int N = Nurse, int P = Patient, enable_if_t<N == 0 || P == 0, int> = 0>
- static void precall(handle) { }
- template <int N = Nurse, int P = Patient, enable_if_t<N == 0 || P == 0, int> = 0>
- static void postcall(handle args, handle ret) { keep_alive_impl(Nurse, Patient, args, ret); }
+template <size_t Nurse, size_t Patient> struct process_attribute<keep_alive<Nurse, Patient>> : public process_attribute_default<keep_alive<Nurse, Patient>> {
+ template <size_t N = Nurse, size_t P = Patient, enable_if_t<N != 0 && P != 0, int> = 0>
+ static void precall(function_call &call) { keep_alive_impl(Nurse, Patient, call, handle()); }
+ template <size_t N = Nurse, size_t P = Patient, enable_if_t<N != 0 && P != 0, int> = 0>
+ static void postcall(function_call &, handle) { }
+ template <size_t N = Nurse, size_t P = Patient, enable_if_t<N == 0 || P == 0, int> = 0>
+ static void precall(function_call &) { }
+ template <size_t N = Nurse, size_t P = Patient, enable_if_t<N == 0 || P == 0, int> = 0>
+ static void postcall(function_call &call, handle ret) { keep_alive_impl(Nurse, Patient, call, ret); }
};
/// Recursively iterate over variadic template arguments
@@ -340,12 +400,12 @@ template <typename... Args> struct process_attributes {
int unused[] = { 0, (process_attribute<typename std::decay<Args>::type>::init(args, r), 0) ... };
ignore_unused(unused);
}
- static void precall(handle fn_args) {
- int unused[] = { 0, (process_attribute<typename std::decay<Args>::type>::precall(fn_args), 0) ... };
+ static void precall(function_call &call) {
+ int unused[] = { 0, (process_attribute<typename std::decay<Args>::type>::precall(call), 0) ... };
ignore_unused(unused);
}
- static void postcall(handle fn_args, handle fn_ret) {
- int unused[] = { 0, (process_attribute<typename std::decay<Args>::type>::postcall(fn_args, fn_ret), 0) ... };
+ static void postcall(function_call &call, handle fn_ret) {
+ int unused[] = { 0, (process_attribute<typename std::decay<Args>::type>::postcall(call, fn_ret), 0) ... };
ignore_unused(unused);
}
};
@@ -354,8 +414,8 @@ template <typename... Args> struct process_attributes {
template <typename... Extra,
size_t named = constexpr_sum(std::is_base_of<arg, Extra>::value...),
size_t self = constexpr_sum(std::is_same<is_method, Extra>::value...)>
-constexpr bool expected_num_args(size_t nargs) {
- return named == 0 || (self + named) == nargs;
+constexpr bool expected_num_args(size_t nargs, bool has_args, bool has_kwargs) {
+ return named == 0 || (self + named + has_args + has_kwargs) == nargs;
}
NAMESPACE_END(detail)