mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-25 22:52:01 +00:00
switched cpp_function to use variadic arguments
This commit is contained in:
parent
fbe82bf94d
commit
71867830f5
@ -45,17 +45,17 @@ template <op_id, op_type, typename B, typename L, typename R> struct op_impl { }
|
|||||||
|
|
||||||
/// Operator implementation generator
|
/// Operator implementation generator
|
||||||
template <op_id id, op_type ot, typename L, typename R> struct op_ {
|
template <op_id id, op_type ot, typename L, typename R> struct op_ {
|
||||||
template <typename base, typename holder> void execute(pybind::class_<base, holder> &class_, const char *doc, return_value_policy policy) const {
|
template <typename Base, typename Holder, typename... Extra> void execute(pybind::class_<Base, Holder> &class_, Extra&&... extra) const {
|
||||||
typedef typename std::conditional<std::is_same<L, self_t>::value, base, L>::type L_type;
|
typedef typename std::conditional<std::is_same<L, self_t>::value, Base, L>::type L_type;
|
||||||
typedef typename std::conditional<std::is_same<R, self_t>::value, base, R>::type R_type;
|
typedef typename std::conditional<std::is_same<R, self_t>::value, Base, R>::type R_type;
|
||||||
typedef op_impl<id, ot, base, L_type, R_type> op;
|
typedef op_impl<id, ot, Base, L_type, R_type> op;
|
||||||
class_.def(op::name(), &op::execute, doc, policy);
|
class_.def(op::name(), &op::execute, std::forward<Extra>(extra)...);
|
||||||
}
|
}
|
||||||
template <typename base, typename holder> void execute_cast(pybind::class_<base, holder> &class_, const char *doc, return_value_policy policy) const {
|
template <typename Base, typename Holder, typename... Extra> void execute_cast(pybind::class_<Base, Holder> &class_, Extra&&... extra) const {
|
||||||
typedef typename std::conditional<std::is_same<L, self_t>::value, base, L>::type L_type;
|
typedef typename std::conditional<std::is_same<L, self_t>::value, Base, L>::type L_type;
|
||||||
typedef typename std::conditional<std::is_same<R, self_t>::value, base, R>::type R_type;
|
typedef typename std::conditional<std::is_same<R, self_t>::value, Base, R>::type R_type;
|
||||||
typedef op_impl<id, ot, base, L_type, R_type> op;
|
typedef op_impl<id, ot, Base, L_type, R_type> op;
|
||||||
class_.def(op::name(), &op::execute_cast, doc, policy);
|
class_.def(op::name(), &op::execute_cast, std::forward<Extra>(extra)...);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -22,16 +22,48 @@
|
|||||||
|
|
||||||
NAMESPACE_BEGIN(pybind)
|
NAMESPACE_BEGIN(pybind)
|
||||||
|
|
||||||
|
template <typename T> struct arg_t;
|
||||||
|
|
||||||
|
/// Annotation for keyword arguments
|
||||||
|
struct arg {
|
||||||
|
arg(const char *name) : name(name) { }
|
||||||
|
template <typename T> inline arg_t<T> operator=(const T &value);
|
||||||
|
const char *name;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Annotation for keyword arguments with default values
|
||||||
|
template <typename T> struct arg_t : public arg {
|
||||||
|
arg_t(const char *name, const T &value) : arg(name), value(value) { }
|
||||||
|
T value;
|
||||||
|
};
|
||||||
|
template <typename T> inline arg_t<T> arg::operator=(const T &value) { return arg_t<T>(name, value); }
|
||||||
|
|
||||||
|
/// Annotation for methods
|
||||||
|
struct is_method { };
|
||||||
|
|
||||||
|
/// Annotation for documentation
|
||||||
|
struct doc { const char *value; doc(const char *value) : value(value) { } };
|
||||||
|
|
||||||
|
/// Annotation for function names
|
||||||
|
struct name { const char *value; name(const char *value) : value(value) { } };
|
||||||
|
|
||||||
|
/// Annotation for function siblings
|
||||||
|
struct sibling { PyObject *value; sibling(handle value) : value(value.ptr()) { } };
|
||||||
|
|
||||||
/// Wraps an arbitrary C++ function/method/lambda function/.. into a callable Python object
|
/// Wraps an arbitrary C++ function/method/lambda function/.. into a callable Python object
|
||||||
class cpp_function : public function {
|
class cpp_function : public function {
|
||||||
private:
|
private:
|
||||||
/// Chained list of function entries for overloading
|
/// Chained list of function entries for overloading
|
||||||
struct function_entry {
|
struct function_entry {
|
||||||
PyObject * (*impl) (function_entry *, PyObject *, PyObject *);
|
const char *name = nullptr;
|
||||||
|
PyObject * (*impl) (function_entry *, PyObject *, PyObject *, PyObject *);
|
||||||
void *data;
|
void *data;
|
||||||
std::string signature, doc;
|
bool is_constructor = false, is_method = false;
|
||||||
bool is_constructor;
|
short keywords = 0;
|
||||||
return_value_policy policy;
|
return_value_policy policy = return_value_policy::automatic;
|
||||||
|
std::string signature;
|
||||||
|
PyObject *sibling = nullptr;
|
||||||
|
const char *doc = nullptr;
|
||||||
function_entry *next = nullptr;
|
function_entry *next = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -41,93 +73,121 @@ private:
|
|||||||
std::is_void<T>::value, detail::void_type, typename detail::decay<T>::type>::type>;
|
std::is_void<T>::value, detail::void_type, typename detail::decay<T>::type>::type>;
|
||||||
|
|
||||||
/// Picks a suitable argument value converter from cast.h
|
/// Picks a suitable argument value converter from cast.h
|
||||||
template <typename ... T> using arg_value_caster =
|
template <typename... T> using arg_value_caster =
|
||||||
detail::type_caster<typename std::tuple<T...>>;
|
detail::type_caster<typename std::tuple<T...>>;
|
||||||
|
|
||||||
|
|
||||||
|
template <typename... T> void process_args(const std::tuple<T...> &args, function_entry *entry) {
|
||||||
|
process_args(args, entry, typename detail::make_index_sequence<sizeof...(T)>::type());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... T, size_t ... Index> void process_args(const
|
||||||
|
std::tuple<T...> &args, function_entry *entry,
|
||||||
|
detail::index_sequence<Index...>) {
|
||||||
|
int unused[] = { 0, (process_arg(std::get<Index>(args), entry), 0)... };
|
||||||
|
(void) unused;
|
||||||
|
}
|
||||||
|
|
||||||
|
void process_arg(const char *doc, function_entry *entry) { entry->doc = doc; }
|
||||||
|
void process_arg(const pybind::doc &d, function_entry *entry) { entry->doc = d.value; }
|
||||||
|
void process_arg(const pybind::name &n, function_entry *entry) { entry->name = n.value; }
|
||||||
|
void process_arg(const pybind::arg &, function_entry *entry) { entry->keywords++; }
|
||||||
|
void process_arg(const pybind::is_method &, function_entry *entry) { entry->is_method = true; }
|
||||||
|
void process_arg(const pybind::return_value_policy p, function_entry *entry) { entry->policy = p; }
|
||||||
|
void process_arg(pybind::sibling s, function_entry *entry) { entry->sibling = s.value; }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
cpp_function() { }
|
cpp_function() { }
|
||||||
|
|
||||||
/// Vanilla function pointers
|
/// Vanilla function pointers
|
||||||
template <typename return_type, typename... arg_type>
|
template <typename Return, typename... Arg, typename... Extra>
|
||||||
cpp_function(return_type (*f)(arg_type...), const char *name = nullptr,
|
cpp_function(Return (*f)(Arg...), Extra&&... extra) {
|
||||||
const char *doc = nullptr, return_value_policy policy = return_value_policy::automatic,
|
struct capture {
|
||||||
const function &sibling = function(), bool is_method = false) {
|
Return (*f)(Arg...);
|
||||||
|
std::tuple<Extra...> extra;
|
||||||
typedef arg_value_caster<arg_type...> cast_in;
|
|
||||||
typedef return_value_caster<return_type> cast_out;
|
|
||||||
|
|
||||||
auto impl = [](function_entry *entry, PyObject *pyArgs, PyObject *parent) -> PyObject * {
|
|
||||||
cast_in args;
|
|
||||||
if (!args.load(pyArgs, true)) return nullptr;
|
|
||||||
auto f = (return_type (*) (arg_type...)) entry->data;
|
|
||||||
return cast_out::cast(args.template call<return_type>(f),
|
|
||||||
entry->policy, parent);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
initialize(name, doc, cast_in::name() + std::string(" -> ") + cast_out::name(),
|
function_entry *entry = new function_entry();
|
||||||
sibling, is_method, policy, impl, (void *) f);
|
entry->data = new capture { f, std::tuple<Extra...>(std::forward<Extra>(extra)...) };
|
||||||
|
|
||||||
|
typedef arg_value_caster<Arg...> cast_in;
|
||||||
|
typedef return_value_caster<Return> cast_out;
|
||||||
|
|
||||||
|
entry->impl = [](function_entry *entry, PyObject *pyArgs, PyObject *kwargs, PyObject *parent) -> PyObject * {
|
||||||
|
cast_in args;
|
||||||
|
if (!args.load(pyArgs, true)) return nullptr;
|
||||||
|
auto f = ((capture *) entry->data)->f;
|
||||||
|
(void)kwargs;
|
||||||
|
return cast_out::cast(args.template call<Return>(f), entry->policy, parent);
|
||||||
|
};
|
||||||
|
|
||||||
|
entry->signature = cast_in::name();
|
||||||
|
entry->signature += " -> ";
|
||||||
|
entry->signature += cast_out::name();
|
||||||
|
process_args(((capture *) entry->data)->extra, entry);
|
||||||
|
initialize(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Delegating helper constructor to deal with lambda functions
|
/// Delegating helper constructor to deal with lambda functions
|
||||||
template <typename func>
|
template <typename Func, typename... Extra> cpp_function(Func &&f, Extra&&... extra) {
|
||||||
cpp_function(func &&f, const char *name = nullptr,
|
initialize(std::forward<Func>(f),
|
||||||
const char *doc = nullptr,
|
|
||||||
return_value_policy policy = return_value_policy::automatic,
|
|
||||||
const function &sibling = function(), bool is_method = false) {
|
|
||||||
initialize(std::forward<func>(f), name, doc, policy, sibling, is_method,
|
|
||||||
(typename detail::remove_class<decltype(
|
(typename detail::remove_class<decltype(
|
||||||
&std::remove_reference<func>::type::operator())>::type *) nullptr);
|
&std::remove_reference<Func>::type::operator())>::type *) nullptr,
|
||||||
|
std::forward<Extra>(extra)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Class methods (non-const)
|
/// Class methods (non-const)
|
||||||
template <typename return_type, typename class_type, typename ... arg_type> cpp_function(
|
template <typename Return, typename Class, typename... Arg, typename... Extra> cpp_function(
|
||||||
return_type (class_type::*f)(arg_type...), const char *name = nullptr,
|
Return (Class::*f)(Arg...), Extra&&... extra) {
|
||||||
const char *doc = nullptr, return_value_policy policy = return_value_policy::automatic,
|
initialize([f](Class *c, Arg... args) -> Return { return (c->*f)(args...); },
|
||||||
const function &sibling = function(), bool is_method = false) {
|
(Return (*) (Class *, Arg...)) nullptr, std::forward<Extra>(extra)...);
|
||||||
initialize([f](class_type *c, arg_type... args) -> return_type { return (c->*f)(args...); },
|
|
||||||
name, doc, policy, sibling, is_method, (return_type (*)(class_type *, arg_type ...)) nullptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Class methods (const)
|
/// Class methods (const)
|
||||||
template <typename return_type, typename class_type, typename ... arg_type> cpp_function(
|
template <typename Return, typename Class, typename... Arg, typename... Extra> cpp_function(
|
||||||
return_type (class_type::*f)(arg_type...) const, const char *name = nullptr,
|
Return (Class::*f)(Arg...) const, Extra&&... extra) {
|
||||||
const char *doc = nullptr, return_value_policy policy = return_value_policy::automatic,
|
initialize([f](const Class *c, Arg... args) -> Return { return (c->*f)(args...); },
|
||||||
const function &sibling = function(), bool is_method = false) {
|
(Return (*)(const Class *, Arg ...)) nullptr, std::forward<Extra>(extra)...);
|
||||||
initialize([f](const class_type *c, arg_type... args) -> return_type { return (c->*f)(args...); },
|
|
||||||
name, doc, policy, sibling, is_method, (return_type (*)(const class_type *, arg_type ...)) nullptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Functors, lambda functions, etc.
|
/// Functors, lambda functions, etc.
|
||||||
template <typename func, typename return_type, typename... arg_type>
|
template <typename Func, typename Return, typename... Arg, typename... Extra>
|
||||||
void initialize(func &&f, const char *name, const char *doc,
|
void initialize(Func &&f, Return (*)(Arg...), Extra&&... extra) {
|
||||||
return_value_policy policy, const function &sibling,
|
struct capture {
|
||||||
bool is_method, return_type (*)(arg_type...)) {
|
typename std::remove_reference<Func>::type f;
|
||||||
|
std::tuple<Extra...> extra;
|
||||||
typedef arg_value_caster<arg_type...> cast_in;
|
|
||||||
typedef return_value_caster<return_type> cast_out;
|
|
||||||
struct capture { typename std::remove_reference<func>::type f; };
|
|
||||||
void *ptr = new capture { std::forward<func>(f) };
|
|
||||||
|
|
||||||
auto impl = [](function_entry *entry, PyObject *pyArgs, PyObject *parent) -> PyObject *{
|
|
||||||
cast_in args;
|
|
||||||
if (!args.load(pyArgs, true)) return nullptr;
|
|
||||||
func &f = ((capture *) entry->data)->f;
|
|
||||||
return cast_out::cast(args.template call<return_type>(f),
|
|
||||||
entry->policy, parent);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
initialize(name, doc, cast_in::name() + std::string(" -> ") + cast_out::name(),
|
function_entry *entry = new function_entry();
|
||||||
sibling, is_method, policy, impl, ptr);
|
entry->data = new capture { std::forward<Func>(f), std::tuple<Extra...>(std::forward<Extra>(extra)...) };
|
||||||
|
|
||||||
|
typedef arg_value_caster<Arg...> cast_in;
|
||||||
|
typedef return_value_caster<Return> cast_out;
|
||||||
|
|
||||||
|
entry->impl = [](function_entry *entry, PyObject *pyArgs, PyObject *kwargs, PyObject *parent) -> PyObject *{
|
||||||
|
cast_in args;
|
||||||
|
if (!args.load(pyArgs, true)) return nullptr;
|
||||||
|
Func &f = ((capture *) entry->data)->f;
|
||||||
|
(void)kwargs;
|
||||||
|
return cast_out::cast(args.template call<Return>(f), entry->policy, parent);
|
||||||
|
};
|
||||||
|
|
||||||
|
entry->signature = cast_in::name();
|
||||||
|
entry->signature += " -> ";
|
||||||
|
entry->signature += cast_out::name();
|
||||||
|
process_args(((capture *) entry->data)->extra, entry);
|
||||||
|
initialize(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *dispatcher(PyObject *self, PyObject *args, PyObject * /* kwargs */) {
|
static PyObject *dispatcher(PyObject *self, PyObject *args, PyObject *kwargs ) {
|
||||||
function_entry *overloads = (function_entry *) PyCapsule_GetPointer(self, nullptr);
|
function_entry *overloads = (function_entry *) PyCapsule_GetPointer(self, nullptr);
|
||||||
PyObject *result = nullptr;
|
PyObject *result = nullptr;
|
||||||
PyObject *parent = PyTuple_Size(args) > 0 ? PyTuple_GetItem(args, 0) : nullptr;
|
PyObject *parent = PyTuple_Size(args) > 0 ? PyTuple_GetItem(args, 0) : nullptr;
|
||||||
try {
|
try {
|
||||||
for (function_entry *it = overloads; it != nullptr; it = it->next) {
|
for (function_entry *it = overloads; it != nullptr; it = it->next) {
|
||||||
if ((result = it->impl(it, args, parent)) != nullptr)
|
if ((result = it->impl(it, args, kwargs, parent)) != nullptr)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} catch (const error_already_set &) { return nullptr;
|
} catch (const error_already_set &) { return nullptr;
|
||||||
@ -161,27 +221,16 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void initialize(const char *name, const char *doc,
|
void initialize(function_entry *entry) {
|
||||||
const std::string &signature, function sibling,
|
if (entry->name == nullptr)
|
||||||
bool is_method, return_value_policy policy,
|
entry->name = "";
|
||||||
PyObject *(*impl) (function_entry *, PyObject *, PyObject *),
|
|
||||||
void *data) {
|
|
||||||
if (name == nullptr)
|
|
||||||
name = "";
|
|
||||||
|
|
||||||
/* Linked list of function call handlers (for overloading) */
|
entry->is_constructor = !strcmp(entry->name, "__init__");
|
||||||
function_entry *entry = new function_entry();
|
|
||||||
entry->impl = impl;
|
|
||||||
entry->is_constructor = !strcmp(name, "__init__");
|
|
||||||
entry->policy = policy;
|
|
||||||
entry->signature = signature;
|
|
||||||
entry->data = data;
|
|
||||||
if (doc) entry->doc = doc;
|
|
||||||
|
|
||||||
if (!sibling.ptr() || !PyCFunction_Check(sibling.ptr())) {
|
if (!entry->sibling || !PyCFunction_Check(entry->sibling)) {
|
||||||
PyMethodDef *def = new PyMethodDef();
|
PyMethodDef *def = new PyMethodDef();
|
||||||
memset(def, 0, sizeof(PyMethodDef));
|
memset(def, 0, sizeof(PyMethodDef));
|
||||||
def->ml_name = name != nullptr ? strdup(name) : name;
|
def->ml_name = entry->name;
|
||||||
def->ml_meth = reinterpret_cast<PyCFunction>(*dispatcher);
|
def->ml_meth = reinterpret_cast<PyCFunction>(*dispatcher);
|
||||||
def->ml_flags = METH_VARARGS | METH_KEYWORDS;
|
def->ml_flags = METH_VARARGS | METH_KEYWORDS;
|
||||||
capsule entry_capsule(entry);
|
capsule entry_capsule(entry);
|
||||||
@ -189,7 +238,7 @@ private:
|
|||||||
if (!m_ptr)
|
if (!m_ptr)
|
||||||
throw std::runtime_error("cpp_function::cpp_function(): Could not allocate function object");
|
throw std::runtime_error("cpp_function::cpp_function(): Could not allocate function object");
|
||||||
} else {
|
} else {
|
||||||
m_ptr = sibling.ptr();
|
m_ptr = entry->sibling;
|
||||||
inc_ref();
|
inc_ref();
|
||||||
capsule entry_capsule(PyCFunction_GetSelf(m_ptr), true);
|
capsule entry_capsule(PyCFunction_GetSelf(m_ptr), true);
|
||||||
function_entry *parent = (function_entry *) entry_capsule, *backup = parent;
|
function_entry *parent = (function_entry *) entry_capsule, *backup = parent;
|
||||||
@ -199,22 +248,23 @@ private:
|
|||||||
entry = backup;
|
entry = backup;
|
||||||
}
|
}
|
||||||
std::string signatures;
|
std::string signatures;
|
||||||
int it = 0;
|
int index = 0;
|
||||||
while (entry) { /* Create pydoc entry */
|
function_entry *it = entry;
|
||||||
if (sibling.ptr())
|
while (it) { /* Create pydoc it */
|
||||||
signatures += std::to_string(++it) + ". ";
|
if (it->sibling)
|
||||||
signatures += "Signature : " + std::string(entry->signature) + "\n";
|
signatures += std::to_string(++index) + ". ";
|
||||||
if (!entry->doc.empty())
|
signatures += "Signature : " + std::string(it->signature) + "\n";
|
||||||
signatures += "\n" + std::string(entry->doc) + "\n";
|
if (it->doc && strlen(it->doc) > 0)
|
||||||
if (entry->next)
|
signatures += "\n" + std::string(it->doc) + "\n";
|
||||||
|
if (it->next)
|
||||||
signatures += "\n";
|
signatures += "\n";
|
||||||
entry = entry->next;
|
it = it->next;
|
||||||
}
|
}
|
||||||
PyCFunctionObject *func = (PyCFunctionObject *) m_ptr;
|
PyCFunctionObject *func = (PyCFunctionObject *) m_ptr;
|
||||||
if (func->m_ml->ml_doc)
|
if (func->m_ml->ml_doc)
|
||||||
std::free((char *) func->m_ml->ml_doc);
|
std::free((char *) func->m_ml->ml_doc);
|
||||||
func->m_ml->ml_doc = strdup(signatures.c_str());
|
func->m_ml->ml_doc = strdup(signatures.c_str());
|
||||||
if (is_method) {
|
if (entry->is_method) {
|
||||||
m_ptr = PyInstanceMethod_New(m_ptr);
|
m_ptr = PyInstanceMethod_New(m_ptr);
|
||||||
if (!m_ptr)
|
if (!m_ptr)
|
||||||
throw std::runtime_error("cpp_function::cpp_function(): Could not allocate instance method object");
|
throw std::runtime_error("cpp_function::cpp_function(): Could not allocate instance method object");
|
||||||
@ -223,15 +273,6 @@ private:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class cpp_method : public cpp_function {
|
|
||||||
public:
|
|
||||||
cpp_method () { }
|
|
||||||
template <typename func> cpp_method(func &&f, const char *name = nullptr,
|
|
||||||
const char *doc = nullptr, return_value_policy
|
|
||||||
policy = return_value_policy::automatic, function sibling = function())
|
|
||||||
: cpp_function(std::forward<func>(f), name, doc, policy, sibling, true) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
class module : public object {
|
class module : public object {
|
||||||
public:
|
public:
|
||||||
PYBIND_OBJECT_DEFAULT(module, object, PyModule_Check)
|
PYBIND_OBJECT_DEFAULT(module, object, PyModule_Check)
|
||||||
@ -249,12 +290,12 @@ public:
|
|||||||
inc_ref();
|
inc_ref();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Func>
|
template <typename Func, typename... Extra>
|
||||||
module &def(const char *name, Func f, const char *doc = nullptr,
|
module &def(const char *name_, Func &&f, Extra&& ... extra) {
|
||||||
return_value_policy policy = return_value_policy::automatic) {
|
cpp_function func(std::forward<Func>(f), name(name_),
|
||||||
cpp_function func(f, name, doc, policy, (function) attr(name));
|
sibling((handle) attr(name_)), std::forward<Extra>(extra)...);
|
||||||
func.inc_ref(); /* The following line steals a reference to 'func' */
|
func.inc_ref(); /* The following line steals a reference to 'func' */
|
||||||
PyModule_AddObject(ptr(), name, func.ptr());
|
PyModule_AddObject(ptr(), name_, func.ptr());
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -270,13 +311,6 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
NAMESPACE_BEGIN(detail)
|
NAMESPACE_BEGIN(detail)
|
||||||
/* Forward declarations */
|
|
||||||
enum op_id : int;
|
|
||||||
enum op_type : int;
|
|
||||||
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;
|
|
||||||
|
|
||||||
/// Basic support for creating new Python heap types
|
/// Basic support for creating new Python heap types
|
||||||
class custom_type : public object {
|
class custom_type : public object {
|
||||||
public:
|
public:
|
||||||
@ -435,6 +469,13 @@ protected:
|
|||||||
|
|
||||||
static void releasebuffer(PyObject *, Py_buffer *view) { delete (buffer_info *) view->internal; }
|
static void releasebuffer(PyObject *, Py_buffer *view) { delete (buffer_info *) view->internal; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Forward declarations */
|
||||||
|
enum op_id : int;
|
||||||
|
enum op_type : int;
|
||||||
|
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;
|
||||||
NAMESPACE_END(detail)
|
NAMESPACE_END(detail)
|
||||||
|
|
||||||
template <typename type, typename holder_type = std::unique_ptr<type>> class class_ : public detail::custom_type {
|
template <typename type, typename holder_type = std::unique_ptr<type>> class class_ : public detail::custom_type {
|
||||||
@ -454,42 +495,41 @@ public:
|
|||||||
sizeof(instance_type), init_holder, dealloc,
|
sizeof(instance_type), init_holder, dealloc,
|
||||||
parent.ptr(), doc) { }
|
parent.ptr(), doc) { }
|
||||||
|
|
||||||
template <typename Func>
|
template <typename Func, typename... Extra>
|
||||||
class_ &def(const char *name, Func f, const char *doc = nullptr,
|
class_ &def(const char *name_, Func&& f, Extra&&... extra) {
|
||||||
return_value_policy policy = return_value_policy::automatic) {
|
attr(name_) = cpp_function(std::forward<Func>(f), name(name_),
|
||||||
attr(name) = cpp_method(f, name, doc, policy, (function) attr(name));
|
sibling(attr(name_)), is_method(),
|
||||||
|
std::forward<Extra>(extra)...);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Func> class_ &
|
template <typename Func, typename... Extra> class_ &
|
||||||
def_static(const char *name, Func f, const char *doc = nullptr,
|
def_static(const char *name_, Func f, Extra&&... extra) {
|
||||||
return_value_policy policy = return_value_policy::automatic) {
|
attr(name_) = cpp_function(std::forward<Func>(f), name(name_),
|
||||||
attr(name) = cpp_function(f, name, doc, policy, (function) attr(name));
|
sibling(attr(name_)),
|
||||||
|
std::forward<Extra>(extra)...);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <detail::op_id id, detail::op_type ot, typename L, typename R>
|
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 char *doc = nullptr,
|
class_ &def(const detail::op_<id, ot, L, R> &op, Extra&&... extra) {
|
||||||
return_value_policy policy = return_value_policy::automatic) {
|
op.template execute<type>(*this, std::forward<Extra>(extra)...);
|
||||||
op.template execute<type>(*this, doc, policy);
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <detail::op_id id, detail::op_type ot, typename L, typename R> class_ &
|
template <detail::op_id id, detail::op_type ot, typename L, typename R, typename... Extra>
|
||||||
def_cast(const detail::op_<id, ot, L, R> &op, const char *doc = nullptr,
|
class_ & def_cast(const detail::op_<id, ot, L, R> &op, Extra&&... extra) {
|
||||||
return_value_policy policy = return_value_policy::automatic) {
|
op.template execute_cast<type>(*this, std::forward<Extra>(extra)...);
|
||||||
op.template execute_cast<type>(*this, doc, policy);
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args, typename... Extra>
|
||||||
class_ &def(const detail::init<Args...> &init, const char *doc = nullptr) {
|
class_ &def(const detail::init<Args...> &init, Extra&&... extra) {
|
||||||
init.template execute<type>(*this, doc);
|
init.template execute<type>(*this, std::forward<Extra>(extra)...);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Func>
|
template <typename Func> class_& def_buffer(Func &&func) {
|
||||||
class_& def_buffer(Func &&func) {
|
|
||||||
struct capture { Func func; };
|
struct capture { Func func; };
|
||||||
capture *ptr = new capture { std::forward<Func>(func) };
|
capture *ptr = new capture { std::forward<Func>(func) };
|
||||||
install_buffer_funcs([](PyObject *obj, void *ptr) -> buffer_info* {
|
install_buffer_funcs([](PyObject *obj, void *ptr) -> buffer_info* {
|
||||||
@ -501,73 +541,69 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename C, typename D>
|
template <typename C, typename D, typename... Extra>
|
||||||
class_ &def_readwrite(const char *name, D C::*pm,
|
class_ &def_readwrite(const char *name, D C::*pm, Extra&&... extra) {
|
||||||
const char *doc = nullptr) {
|
cpp_function fget([pm](const C &c) -> const D &{ return c.*pm; },
|
||||||
cpp_method fget([pm](const C &c) -> const D &{ return c.*pm; }, nullptr,
|
return_value_policy::reference_internal,
|
||||||
nullptr, return_value_policy::reference_internal),
|
is_method(), extra...),
|
||||||
fset([pm](C &c, const D &value) { c.*pm = value; });
|
fset([pm](C &c, const D &value) { c.*pm = value; },
|
||||||
def_property(name, fget, fset, doc);
|
is_method(), extra...);
|
||||||
|
def_property(name, fget, fset);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename C, typename D>
|
template <typename C, typename D, typename... Extra>
|
||||||
class_ &def_readonly(const char *name, const D C::*pm,
|
class_ &def_readonly(const char *name, const D C::*pm, Extra&& ...extra) {
|
||||||
const char *doc = nullptr) {
|
cpp_function fget([pm](const C &c) -> const D &{ return c.*pm; },
|
||||||
cpp_method fget([pm](const C &c) -> const D &{ return c.*pm; }, nullptr,
|
return_value_policy::reference_internal,
|
||||||
nullptr, return_value_policy::reference_internal);
|
is_method(), std::forward<Extra>(extra)...);
|
||||||
def_property(name, fget, doc);
|
def_property_readonly(name, fget);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename D>
|
template <typename D, typename... Extra>
|
||||||
class_ &def_readwrite_static(const char *name, D *pm,
|
class_ &def_readwrite_static(const char *name, D *pm, Extra&& ...extra) {
|
||||||
const char *doc = nullptr) {
|
|
||||||
cpp_function fget([pm](object) -> const D &{ return *pm; }, nullptr,
|
cpp_function fget([pm](object) -> const D &{ return *pm; }, nullptr,
|
||||||
nullptr, return_value_policy::reference_internal),
|
return_value_policy::reference_internal, extra...),
|
||||||
fset([pm](object, const D &value) { *pm = value; });
|
fset([pm](object, const D &value) { *pm = value; }, extra...);
|
||||||
def_property_static(name, fget, fset, doc);
|
def_property_static(name, fget, fset);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename D>
|
template <typename D, typename... Extra>
|
||||||
class_ &def_readonly_static(const char *name, const D *pm,
|
class_ &def_readonly_static(const char *name, const D *pm, Extra&& ...extra) {
|
||||||
const char *doc = nullptr) {
|
|
||||||
cpp_function fget([pm](object) -> const D &{ return *pm; }, nullptr,
|
cpp_function fget([pm](object) -> const D &{ return *pm; }, nullptr,
|
||||||
nullptr, return_value_policy::reference_internal);
|
return_value_policy::reference_internal, std::forward<Extra>(extra)...);
|
||||||
def_property_static(name, fget, doc);
|
def_property_readonly_static(name, fget);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
class_ &def_property(const char *name, const cpp_method &fget,
|
class_ &def_property_readonly(const char *name, const cpp_function &fget) {
|
||||||
const char *doc = nullptr) {
|
def_property(name, fget, cpp_function());
|
||||||
def_property(name, fget, cpp_method(), doc);
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
class_ &def_property_static(const char *name, const cpp_function &fget,
|
class_ &def_property_readonly_static(const char *name, const cpp_function &fget) {
|
||||||
const char *doc = nullptr) {
|
def_property_static(name, fget, cpp_function());
|
||||||
def_property_static(name, fget, cpp_function(), doc);
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
class_ &def_property(const char *name, const cpp_method &fget,
|
class_ &def_property(const char *name, const cpp_function &fget, const cpp_function &fset) {
|
||||||
const cpp_method &fset, const char *doc = nullptr) {
|
|
||||||
object property(
|
object property(
|
||||||
PyObject_CallFunction((PyObject *)&PyProperty_Type,
|
PyObject_CallFunction((PyObject *)&PyProperty_Type,
|
||||||
const_cast<char *>("OOOs"), fget.ptr() ? fget.ptr() : Py_None,
|
const_cast<char *>("OOOO"), fget.ptr() ? fget.ptr() : Py_None,
|
||||||
fset.ptr() ? fset.ptr() : Py_None, Py_None, doc), false);
|
fset.ptr() ? fset.ptr() : Py_None, Py_None,
|
||||||
|
((object) const_cast<cpp_function&>(fget).attr("__doc__")).ptr()), false);
|
||||||
attr(name) = property;
|
attr(name) = property;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
class_ &def_property_static(const char *name, const cpp_function &fget,
|
class_ &def_property_static(const char *name, const cpp_function &fget, const cpp_function &fset) {
|
||||||
const cpp_function &fset,
|
|
||||||
const char *doc = nullptr) {
|
|
||||||
object property(
|
object property(
|
||||||
PyObject_CallFunction((PyObject *)&PyProperty_Type,
|
PyObject_CallFunction((PyObject *)&PyProperty_Type,
|
||||||
const_cast<char *>("OOOs"), fget.ptr() ? fget.ptr() : Py_None,
|
const_cast<char *>("OOOO"), fget.ptr() ? fget.ptr() : Py_None,
|
||||||
fset.ptr() ? fset.ptr() : Py_None, Py_None, doc), false);
|
fset.ptr() ? fset.ptr() : Py_None, Py_None,
|
||||||
|
((object) const_cast<cpp_function&>(fget).attr("__doc__")).ptr()), false);
|
||||||
metaclass().attr(name) = property;
|
metaclass().attr(name) = property;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@ -626,10 +662,10 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
NAMESPACE_BEGIN(detail)
|
NAMESPACE_BEGIN(detail)
|
||||||
template <typename ... Args> struct init {
|
template <typename... Args> struct init {
|
||||||
template <typename Base, typename Holder> void execute(pybind::class_<Base, Holder> &class_, const char *doc) const {
|
template <typename Base, typename Holder, typename... Extra> void execute(pybind::class_<Base, Holder> &class_, Extra&&... extra) const {
|
||||||
/// Function which calls a specific C++ in-place constructor
|
/// Function which calls a specific C++ in-place constructor
|
||||||
class_.def("__init__", [](Base *instance, Args... args) { new (instance) Base(args...); }, doc);
|
class_.def("__init__", [](Base *instance, Args... args) { new (instance) Base(args...); }, std::forward<Extra>(extra)...);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
NAMESPACE_END(detail)
|
NAMESPACE_END(detail)
|
||||||
|
Loading…
Reference in New Issue
Block a user