mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-25 14:45:12 +00:00
major cleanup of the whole codebase
- new pybind11::base<> attribute to indicate a subclass relationship - unified infrastructure for parsing variadic arguments in class_ and cpp_function - use 'handle' and 'object' more consistently everywhere
This commit is contained in:
parent
140546b135
commit
ed3d23a5d6
@ -80,6 +80,7 @@ include_directories(${PYTHON_INCLUDE_DIR})
|
||||
include_directories(include)
|
||||
|
||||
set(PYBIND11_HEADERS
|
||||
include/pybind11/attr.h
|
||||
include/pybind11/cast.h
|
||||
include/pybind11/common.h
|
||||
include/pybind11/complex.h
|
||||
@ -167,7 +168,7 @@ elseif (UNIX)
|
||||
# Strip unnecessary sections of the binary on Linux/Mac OS
|
||||
if(APPLE)
|
||||
set_target_properties(example PROPERTIES MACOSX_RPATH ".")
|
||||
set_target_properties(example PROPERTIES LINK_FLAGS "-undefined dynamic_lookup -dead_strip")
|
||||
set_target_properties(example PROPERTIES LINK_FLAGS "-undefined dynamic_lookup ")
|
||||
if (NOT ${U_CMAKE_BUILD_TYPE} MATCHES DEBUG)
|
||||
add_custom_command(TARGET example POST_BUILD COMMAND strip -u -r ${PROJECT_SOURCE_DIR}/example/example.so)
|
||||
endif()
|
||||
|
@ -925,7 +925,7 @@ If not available, the signature may not be very helpful, e.g.:
|
||||
FUNCTIONS
|
||||
...
|
||||
| myFunction(...)
|
||||
| Signature : (MyClass, arg : SomeType = <SomeType object at 0x101b7b080>) -> None
|
||||
| Signature : (MyClass, arg : SomeType = <SomeType object at 0x101b7b080>) -> NoneType
|
||||
...
|
||||
|
||||
The first way of addressing this is by defining ``SomeType.__repr__``.
|
||||
|
@ -5,15 +5,19 @@ Changelog
|
||||
|
||||
1.2 (not yet released)
|
||||
--------------------------
|
||||
|
||||
* Optional: efficient generation of function signatures at compile time using C++14
|
||||
* Switched to a simpler and more general way of dealing with function default arguments
|
||||
Unused keyword arguments in function calls are now detected and cause errors as expected
|
||||
* Switched to a simpler and more general way of dealing with function default
|
||||
arguments. Unused keyword arguments in function calls are now detected and
|
||||
cause errors as expected
|
||||
* New ``keep_alive`` call policy analogous to Boost.Python's ``with_custodian_and_ward``
|
||||
* New ``pybind11::base<>`` attribute to indicate a subclass relationship
|
||||
* Improved interface for RAII type wrappers in ``pytypes.h``
|
||||
* Use RAII type wrappers consistently within pybind11 itself. This
|
||||
fixes various potential refcount leaks when exceptions occur
|
||||
* Added new ``bytes`` RAII type wrapper (maps to ``string`` in Python 2.7).
|
||||
* Made handle and related RAII classes const correct
|
||||
* Made handle and related RAII classes const correct, using them more
|
||||
consistently everywhere now
|
||||
* Got rid of the ugly ``__pybind11__`` attributes on the Python side---they are
|
||||
now stored in a C++ hash table that is not visible in Python
|
||||
* Fixed refcount leaks involving NumPy arrays and bound functions
|
||||
@ -21,7 +25,9 @@ Changelog
|
||||
* Removed an unnecessary copy operation in ``pybind11::vectorize``
|
||||
* Fixed naming clashes when both pybind11 and NumPy headers are included
|
||||
* Added conversions for additional exception types
|
||||
* Documentation improvements (using multiple extension modules, smart pointers, other minor clarifications)
|
||||
* Documentation improvements (using multiple extension modules, smart pointers,
|
||||
other minor clarifications)
|
||||
* unified infrastructure for parsing variadic arguments in class_ and cpp_function
|
||||
* Fixed license text (was: ZLIB, should have been: 3-clause BSD)
|
||||
* Python 3.2 compatibility
|
||||
|
||||
|
@ -177,9 +177,22 @@ inheritance relationship:
|
||||
std::string bark() const { return "woof!"; }
|
||||
};
|
||||
|
||||
To capture the hierarchical relationship in pybind11, we must assign a name to
|
||||
the ``Pet`` :class:`class_` instance and reference it when binding the ``Dog``
|
||||
class.
|
||||
There are two different ways of indicating a hierarchical relationship to
|
||||
pybind11: the first is by specifying the C++ base class explicitly during
|
||||
construction using the ``base`` attribute:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
py::class_<Pet>(m, "Pet")
|
||||
.def(py::init<const std::string &>())
|
||||
.def_readwrite("name", &Pet::name);
|
||||
|
||||
py::class_<Dog>(m, "Dog", py::base<Pet>() /* <- specify C++ parent type */)
|
||||
.def(py::init<const std::string &>())
|
||||
.def("bark", &Dog::bark);
|
||||
|
||||
Alternatively, we can also assign a name to the previously bound ``Pet``
|
||||
:class:`class_` object and reference it when binding the ``Dog`` class:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
@ -187,11 +200,12 @@ class.
|
||||
pet.def(py::init<const std::string &>())
|
||||
.def_readwrite("name", &Pet::name);
|
||||
|
||||
py::class_<Dog>(m, "Dog", pet /* <- specify parent */)
|
||||
py::class_<Dog>(m, "Dog", pet /* <- specify Python parent type */)
|
||||
.def(py::init<const std::string &>())
|
||||
.def("bark", &Dog::bark);
|
||||
|
||||
Instances then expose fields and methods of both types:
|
||||
Functionality-wise, both approaches are completely equivalent. Afterwards,
|
||||
instances will expose fields and methods of both types:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@ -242,14 +256,14 @@ The overload signatures are also visible in the method's docstring:
|
||||
| Methods defined here:
|
||||
|
|
||||
| __init__(...)
|
||||
| Signature : (Pet, str, int) -> None
|
||||
| Signature : (Pet, str, int) -> NoneType
|
||||
|
|
||||
| set(...)
|
||||
| 1. Signature : (Pet, int) -> None
|
||||
| 1. Signature : (Pet, int) -> NoneType
|
||||
|
|
||||
| Set the pet's age
|
||||
|
|
||||
| 2. Signature : (Pet, str) -> None
|
||||
| 2. Signature : (Pet, str) -> NoneType
|
||||
|
|
||||
| Set the pet's name
|
||||
|
||||
|
@ -115,7 +115,7 @@ and that the pybind11 repository is located in a subdirectory named :file:`pybin
|
||||
# Strip unnecessary sections of the binary on Linux/Mac OS
|
||||
if(APPLE)
|
||||
set_target_properties(example PROPERTIES MACOSX_RPATH ".")
|
||||
set_target_properties(example PROPERTIES LINK_FLAGS "-undefined dynamic_lookup -dead_strip")
|
||||
set_target_properties(example PROPERTIES LINK_FLAGS "-undefined dynamic_lookup ")
|
||||
if (NOT ${U_CMAKE_BUILD_TYPE} MATCHES DEBUG)
|
||||
add_custom_command(TARGET example POST_BUILD COMMAND strip -u -r ${PROJECT_BINARY_DIR}/example.so)
|
||||
endif()
|
||||
|
@ -63,17 +63,19 @@ Without reference counting
|
||||
|
||||
Return the ``PyObject *`` underlying a :class:`handle`.
|
||||
|
||||
.. function:: void handle::inc_ref() const
|
||||
.. function:: const handle& handle::inc_ref() const
|
||||
|
||||
Manually increase the reference count of the Python object. Usually, it is
|
||||
preferable to use the :class:`object` class which derives from
|
||||
:class:`handle` and calls this function automatically.
|
||||
:class:`handle` and calls this function automatically. Returns a reference
|
||||
to itself.
|
||||
|
||||
.. function:: void handle::dec_ref() const
|
||||
.. function:: const handle& handle::dec_ref() const
|
||||
|
||||
Manually decrease the reference count of the Python object. Usually, it is
|
||||
preferable to use the :class:`object` class which derives from
|
||||
:class:`handle` and calls this function automatically.
|
||||
:class:`handle` and calls this function automatically. Returns a reference
|
||||
to itself.
|
||||
|
||||
.. function:: void handle::ref_count() const
|
||||
|
||||
@ -167,11 +169,11 @@ With reference counting
|
||||
Move constructor; steals the object from ``other`` and preserves its
|
||||
reference count.
|
||||
|
||||
.. function:: PyObject* object::release()
|
||||
.. function:: handle object::release()
|
||||
|
||||
Release ownership of underlying ``PyObject *``. Returns raw Python object
|
||||
pointer without decreasing its reference count and resets handle to
|
||||
``nullptr``-valued pointer.
|
||||
Resets the internal pointer to ``nullptr`` without without decreasing the
|
||||
object's reference count. The function returns a raw handle to the original
|
||||
Python object.
|
||||
|
||||
.. function:: object::~object()
|
||||
|
||||
|
@ -29,6 +29,11 @@ public:
|
||||
void bark() const { std::cout << "Woof!" << std::endl; }
|
||||
};
|
||||
|
||||
class Rabbit : public Pet {
|
||||
public:
|
||||
Rabbit(const std::string &name) : Pet(name, "parrot") {}
|
||||
};
|
||||
|
||||
void pet_print(const Pet &pet) {
|
||||
std::cout << pet.name() + " is a " + pet.species() << std::endl;
|
||||
}
|
||||
@ -62,9 +67,14 @@ void init_ex5(py::module &m) {
|
||||
.def("name", &Pet::name)
|
||||
.def("species", &Pet::species);
|
||||
|
||||
/* One way of declaring a subclass relationship: reference parent's class_ object */
|
||||
py::class_<Dog>(m, "Dog", pet_class)
|
||||
.def(py::init<std::string>());
|
||||
|
||||
/* Another way of declaring a subclass relationship: reference parent's C++ type */
|
||||
py::class_<Rabbit>(m, "Rabbit", py::base<Pet>())
|
||||
.def(py::init<std::string>());
|
||||
|
||||
m.def("pet_print", pet_print);
|
||||
m.def("dog_bark", dog_bark);
|
||||
|
||||
|
@ -5,11 +5,15 @@ sys.path.append('.')
|
||||
|
||||
from example import Pet
|
||||
from example import Dog
|
||||
from example import Rabbit
|
||||
from example import dog_bark
|
||||
from example import pet_print
|
||||
|
||||
polly = Pet('Polly', 'parrot')
|
||||
molly = Dog('Molly')
|
||||
roger = Rabbit('Rabbit')
|
||||
print(roger.name() + " is a " + roger.species())
|
||||
pet_print(roger)
|
||||
print(polly.name() + " is a " + polly.species())
|
||||
pet_print(polly)
|
||||
print(molly.name() + " is a " + molly.species())
|
||||
|
@ -1,16 +1,7 @@
|
||||
Rabbit is a parrot
|
||||
Polly is a parrot
|
||||
Polly is a parrot
|
||||
Molly is a dog
|
||||
Molly is a dog
|
||||
Woof!
|
||||
The following error is expected: Incompatible function arguments. The following argument types are supported:
|
||||
1. (Dog) -> NoneType
|
||||
|
||||
Callback function 1 called!
|
||||
False
|
||||
Callback function 2 called : Hello, x, True, 5
|
||||
5
|
||||
func(43) = 44
|
||||
func(43) = 44
|
||||
Payload constructor
|
||||
Payload copy constructor
|
||||
@ -18,3 +9,14 @@ Payload move constructor
|
||||
Payload destructor
|
||||
Payload destructor
|
||||
Payload destructor
|
||||
Rabbit is a parrot
|
||||
Polly is a parrot
|
||||
Molly is a dog
|
||||
The following error is expected: Incompatible function arguments. The following argument types are supported:
|
||||
1. (example.Dog) -> NoneType
|
||||
|
||||
Callback function 1 called!
|
||||
False
|
||||
Callback function 2 called : Hello, x, True, 5
|
||||
5
|
||||
func(43) = 44
|
||||
|
275
include/pybind11/attr.h
Normal file
275
include/pybind11/attr.h
Normal file
@ -0,0 +1,275 @@
|
||||
/*
|
||||
pybind11/pybind11.h: Infrastructure for processing custom
|
||||
type and function attributes
|
||||
|
||||
Copyright (c) 2015 Wenzel Jakob <wenzel@inf.ethz.ch>
|
||||
|
||||
All rights reserved. Use of this source code is governed by a
|
||||
BSD-style license that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cast.h"
|
||||
|
||||
NAMESPACE_BEGIN(pybind11)
|
||||
|
||||
template <typename T> struct arg_t;
|
||||
|
||||
/// Annotation for keyword arguments
|
||||
struct arg {
|
||||
arg(const char *name) : name(name) { }
|
||||
template <typename T> 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, const char *descr = nullptr)
|
||||
: arg(name), value(value), descr(descr) { }
|
||||
T value;
|
||||
const char *descr;
|
||||
};
|
||||
|
||||
template <typename T> arg_t<T> arg::operator=(const T &value) { return arg_t<T>(name, value); }
|
||||
|
||||
/// Annotation for methods
|
||||
struct is_method { handle class_; is_method(const handle &c) : class_(c) { } };
|
||||
|
||||
/// 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 indicating that a function is an overload associated with a given "sibling"
|
||||
struct sibling { handle value; sibling(const handle &value) : value(value.ptr()) { } };
|
||||
|
||||
/// Annotation indicating that a class derives from another given type
|
||||
template <typename T> struct base { };
|
||||
|
||||
/// Keep patient alive while nurse lives
|
||||
template <int Nurse, int Patient> struct keep_alive { };
|
||||
|
||||
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;
|
||||
inline void keep_alive_impl(int Nurse, int Patient, handle args, 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
|
||||
|
||||
argument_record(const char *name, const char *descr, handle value)
|
||||
: name(name), descr(descr), value(value) { }
|
||||
};
|
||||
|
||||
/// Internal data structure which holds metadata about a bound function (signature, overloads, etc.)
|
||||
struct function_record {
|
||||
/// Function name
|
||||
char *name = nullptr; /* why no C++ strings? They generate heavier code.. */
|
||||
|
||||
// User-specified documentation string
|
||||
char *doc = nullptr;
|
||||
|
||||
/// Human-readable version of the function signature
|
||||
char *signature = nullptr;
|
||||
|
||||
/// List of registered keyword arguments
|
||||
std::vector<argument_record> args;
|
||||
|
||||
/// Pointer to lambda function which converts arguments and performs the actual call
|
||||
handle (*impl) (function_record *, handle, handle) = nullptr;
|
||||
|
||||
/// Storage for the wrapped function pointer and captured data, if any
|
||||
void *data = nullptr;
|
||||
|
||||
/// Pointer to custom destructor for 'data' (if needed)
|
||||
void (*free_data) (void *ptr) = nullptr;
|
||||
|
||||
/// Return value policy associated with this function
|
||||
return_value_policy policy = return_value_policy::automatic;
|
||||
|
||||
/// True if name == '__init__'
|
||||
bool is_constructor = false;
|
||||
|
||||
/// Python method object
|
||||
PyMethodDef *def = nullptr;
|
||||
|
||||
/// Python handle to the associated class (if this is method)
|
||||
handle class_;
|
||||
|
||||
/// Python handle to the sibling function representing an overload chain
|
||||
handle sibling;
|
||||
|
||||
/// Pointer to next overload
|
||||
function_record *next = nullptr;
|
||||
};
|
||||
|
||||
/// Special data structure which (temporarily) holds metadata about a bound class
|
||||
struct type_record {
|
||||
/// Handle to the parent scope
|
||||
handle scope;
|
||||
|
||||
/// Name of the class
|
||||
const char *name = nullptr;
|
||||
|
||||
// Pointer to RTTI type_info data structure
|
||||
const std::type_info *type = nullptr;
|
||||
|
||||
/// How large is the underlying C++ type?
|
||||
size_t type_size = 0;
|
||||
|
||||
/// How large is pybind11::instance<type>?
|
||||
size_t instance_size = 0;
|
||||
|
||||
/// Function pointer to class_<..>::init_holder
|
||||
void (*init_holder)(PyObject *, const void *) = nullptr;
|
||||
|
||||
/// Function pointer to class_<..>::dealloc
|
||||
void (*dealloc)(PyObject *) = nullptr;
|
||||
|
||||
// Pointer to RTTI type_info data structure of base class
|
||||
const std::type_info *base_type = nullptr;
|
||||
|
||||
/// OR: Python handle to base class
|
||||
handle base_handle;
|
||||
|
||||
/// Optional docstring
|
||||
const char *doc = nullptr;
|
||||
};
|
||||
|
||||
/**
|
||||
* Partial template specializations to process custom attributes provided to
|
||||
* cpp_function_ and class_. These are either used to initialize the respective
|
||||
* fields in the type_record and function_record data structures or executed
|
||||
* at runtime to deal with custom call policies (e.g. keep_alive).
|
||||
*/
|
||||
template <typename T, typename SFINAE = void> struct process_attribute;
|
||||
|
||||
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) { }
|
||||
};
|
||||
|
||||
/// Process an attribute specifying the function's name
|
||||
template <> struct process_attribute<name> : process_attribute_default<name> {
|
||||
static void init(const name &n, function_record *r) { r->name = const_cast<char *>(n.value); }
|
||||
};
|
||||
|
||||
/// Process an attribute specifying the function's docstring
|
||||
template <> struct process_attribute<doc> : process_attribute_default<doc> {
|
||||
static void init(const doc &n, function_record *r) { r->doc = const_cast<char *>(n.value); }
|
||||
};
|
||||
|
||||
/// Process an attribute specifying the function's docstring (provided as a C-style string)
|
||||
template <> struct process_attribute<const char *> : process_attribute_default<const char *> {
|
||||
static void init(const char *d, function_record *r) { r->doc = const_cast<char *>(d); }
|
||||
static void init(const char *d, type_record *r) { r->doc = const_cast<char *>(d); }
|
||||
};
|
||||
template <> struct process_attribute<char *> : process_attribute<const char *> { };
|
||||
|
||||
/// Process an attribute indicating the function's return value policy
|
||||
template <> struct process_attribute<return_value_policy> : process_attribute_default<return_value_policy> {
|
||||
static void init(const return_value_policy &p, function_record *r) { r->policy = p; }
|
||||
};
|
||||
|
||||
/// Process an attribute which indicates that this is an overloaded function associated with a given sibling
|
||||
template <> struct process_attribute<sibling> : process_attribute_default<sibling> {
|
||||
static void init(const sibling &s, function_record *r) { r->sibling = s.value; }
|
||||
};
|
||||
|
||||
/// Process an attribute which indicates that this function is a method
|
||||
template <> struct process_attribute<is_method> : process_attribute_default<is_method> {
|
||||
static void init(const is_method &s, function_record *r) { r->class_ = s.class_; }
|
||||
};
|
||||
|
||||
/// Process a keyword argument attribute (*without* a default value)
|
||||
template <> struct process_attribute<arg> : process_attribute_default<arg> {
|
||||
static void init(const arg &a, function_record *r) {
|
||||
if (r->class_ && r->args.empty())
|
||||
r->args.emplace_back("self", nullptr, handle());
|
||||
r->args.emplace_back(a.name, nullptr, handle());
|
||||
}
|
||||
};
|
||||
|
||||
/// Process a keyword argument attribute (*with* a default value)
|
||||
template <typename T>
|
||||
struct process_attribute<arg_t<T>> : process_attribute_default<arg_t<T>> {
|
||||
static void init(const arg_t<T> &a, function_record *r) {
|
||||
if (r->class_ && r->args.empty())
|
||||
r->args.emplace_back("self", nullptr, handle());
|
||||
|
||||
/* Convert keyword value into a Python object */
|
||||
object o = object(detail::type_caster<typename detail::intrinsic_type<T>::type>::cast(
|
||||
a.value, return_value_policy::automatic, handle()), false);
|
||||
|
||||
if (!o)
|
||||
pybind11_fail("arg(): could not convert default keyword "
|
||||
"argument into a Python object (type not "
|
||||
"registered yet?)");
|
||||
|
||||
r->args.emplace_back(a.name, a.descr, o.release());
|
||||
}
|
||||
};
|
||||
|
||||
/// Process a parent class attribute
|
||||
template <typename T>
|
||||
struct process_attribute<T, typename std::enable_if<std::is_base_of<handle, T>::value>::type> : process_attribute_default<handle> {
|
||||
static void init(const handle &h, type_record *r) { r->base_handle = h; }
|
||||
};
|
||||
|
||||
/// Process a parent class attribute
|
||||
template <typename T>
|
||||
struct process_attribute<base<T>> : process_attribute_default<base<T>> {
|
||||
static void init(const base<T> &, type_record *r) { r->base_type = &typeid(T); }
|
||||
};
|
||||
|
||||
/***
|
||||
* Process a keep_alive call policy -- invokes keep_alive_impl during the
|
||||
* 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, typename std::enable_if<N != 0 && P != 0, int>::type = 0>
|
||||
static void precall(handle args) { keep_alive_impl(Nurse, Patient, args, handle()); }
|
||||
template <int N = Nurse, int P = Patient, typename std::enable_if<N != 0 && P != 0, int>::type = 0>
|
||||
static void postcall(handle, handle) { }
|
||||
template <int N = Nurse, int P = Patient, typename std::enable_if<N == 0 || P == 0, int>::type = 0>
|
||||
static void precall(handle) { }
|
||||
template <int N = Nurse, int P = Patient, typename std::enable_if<N == 0 || P == 0, int>::type = 0>
|
||||
static void postcall(handle args, handle ret) { keep_alive_impl(Nurse, Patient, args, ret); }
|
||||
};
|
||||
|
||||
|
||||
/// Recursively iterate over variadic template arguments
|
||||
template <typename... Args> struct process_attributes {
|
||||
static void init(const Args&... args, function_record *r) {
|
||||
int unused[] = { 0, (process_attribute<typename std::decay<Args>::type>::init(args, r), 0) ... };
|
||||
(void) unused;
|
||||
}
|
||||
static void init(const Args&... args, type_record *r) {
|
||||
int unused[] = { 0, (process_attribute<typename std::decay<Args>::type>::init(args, r), 0) ... };
|
||||
(void) unused;
|
||||
}
|
||||
static void precall(handle fn_args) {
|
||||
int unused[] = { 0, (process_attribute<typename std::decay<Args>::type>::precall(fn_args), 0) ... };
|
||||
(void) 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) ... };
|
||||
(void) unused;
|
||||
}
|
||||
};
|
||||
|
||||
NAMESPACE_END(detail)
|
||||
NAMESPACE_END(pybind11)
|
@ -19,95 +19,168 @@
|
||||
NAMESPACE_BEGIN(pybind11)
|
||||
NAMESPACE_BEGIN(detail)
|
||||
|
||||
class type_caster_generic {
|
||||
public:
|
||||
PYBIND11_NOINLINE type_caster_generic(const std::type_info *type_info) {
|
||||
auto &types = get_internals().registered_types_cpp;
|
||||
/// Additional type information which does not fit into the PyTypeObject
|
||||
struct type_info {
|
||||
PyTypeObject *type;
|
||||
size_t type_size;
|
||||
void (*init_holder)(PyObject *, const void *);
|
||||
std::vector<PyObject *(*)(PyObject *, PyTypeObject *) > implicit_conversions;
|
||||
buffer_info *(*get_buffer)(PyObject *, void *) = nullptr;
|
||||
void *get_buffer_data = nullptr;
|
||||
};
|
||||
|
||||
auto it = types.find(type_info);
|
||||
if (it != types.end()) {
|
||||
typeinfo = (detail::type_info *) it->second;
|
||||
} else {
|
||||
/* Unknown type?! Since std::type_info* often varies across
|
||||
module boundaries, the following does an explicit check */
|
||||
for (auto const &type : types) {
|
||||
auto *first = (const std::type_info *) type.first;
|
||||
if (strcmp(first->name(), type_info->name()) == 0) {
|
||||
types[type_info] = type.second;
|
||||
typeinfo = (detail::type_info *) type.second;
|
||||
break;
|
||||
}
|
||||
PYBIND11_NOINLINE inline internals &get_internals() {
|
||||
static internals *internals_ptr = nullptr;
|
||||
if (internals_ptr)
|
||||
return *internals_ptr;
|
||||
handle builtins(PyEval_GetBuiltins());
|
||||
capsule caps(builtins["__pybind11__"]);
|
||||
if (caps.check()) {
|
||||
internals_ptr = caps;
|
||||
} else {
|
||||
internals_ptr = new internals();
|
||||
builtins["__pybind11__"] = capsule(internals_ptr);
|
||||
}
|
||||
return *internals_ptr;
|
||||
}
|
||||
|
||||
PYBIND11_NOINLINE inline detail::type_info* get_type_info(PyTypeObject *type) {
|
||||
auto const &type_dict = get_internals().registered_types_py;
|
||||
do {
|
||||
auto it = type_dict.find(type);
|
||||
if (it != type_dict.end())
|
||||
return (detail::type_info *) it->second;
|
||||
type = type->tp_base;
|
||||
if (!type)
|
||||
pybind11_fail("pybind11::detail::get_type_info: unable to find type object!");
|
||||
} while (true);
|
||||
}
|
||||
|
||||
PYBIND11_NOINLINE inline detail::type_info *get_type_info(const std::type_info &tp) {
|
||||
auto &types = get_internals().registered_types_cpp;
|
||||
|
||||
auto it = types.find(&tp);
|
||||
if (it != types.end()) {
|
||||
return (detail::type_info *) it->second;
|
||||
} else {
|
||||
/* Unknown type?! Since std::type_info* often varies across
|
||||
module boundaries, the following does an explicit check */
|
||||
for (auto const &type : types) {
|
||||
auto *first = (const std::type_info *) type.first;
|
||||
if (strcmp(first->name(), tp.name()) == 0) {
|
||||
types[&tp] = type.second;
|
||||
return (detail::type_info *) type.second;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PYBIND11_NOINLINE bool load(PyObject *src, bool convert) {
|
||||
if (src == nullptr || typeinfo == nullptr)
|
||||
PYBIND11_NOINLINE inline handle get_type_handle(const std::type_info &tp) {
|
||||
detail::type_info *type_info = get_type_info(tp);
|
||||
return handle(type_info ? ((PyObject *) type_info->type) : nullptr);
|
||||
}
|
||||
|
||||
PYBIND11_NOINLINE inline std::string error_string() {
|
||||
std::string errorString;
|
||||
PyThreadState *tstate = PyThreadState_GET();
|
||||
if (tstate == nullptr)
|
||||
return "";
|
||||
|
||||
if (tstate->curexc_type) {
|
||||
errorString += (std::string) handle(tstate->curexc_type).str();
|
||||
errorString += ": ";
|
||||
}
|
||||
if (tstate->curexc_value)
|
||||
errorString += (std::string) handle(tstate->curexc_value).str();
|
||||
|
||||
return errorString;
|
||||
}
|
||||
|
||||
PYBIND11_NOINLINE inline handle get_object_handle(const void *ptr) {
|
||||
auto instances = get_internals().registered_instances;
|
||||
auto it = instances.find(ptr);
|
||||
if (it == instances.end())
|
||||
return handle();
|
||||
return handle((PyObject *) it->second);
|
||||
}
|
||||
|
||||
class type_caster_generic {
|
||||
public:
|
||||
PYBIND11_NOINLINE type_caster_generic(const std::type_info &type_info)
|
||||
: typeinfo(get_type_info(type_info)) { }
|
||||
|
||||
PYBIND11_NOINLINE bool load(handle src, bool convert) {
|
||||
if (!src || !typeinfo)
|
||||
return false;
|
||||
if (PyType_IsSubtype(Py_TYPE(src), typeinfo->type)) {
|
||||
value = ((instance<void> *) src)->value;
|
||||
if (PyType_IsSubtype(Py_TYPE(src.ptr()), typeinfo->type)) {
|
||||
value = ((instance<void> *) src.ptr())->value;
|
||||
return true;
|
||||
}
|
||||
if (convert) {
|
||||
for (auto &converter : typeinfo->implicit_conversions) {
|
||||
temp = object(converter(src, typeinfo->type), false);
|
||||
if (load(temp.ptr(), false))
|
||||
temp = object(converter(src.ptr(), typeinfo->type), false);
|
||||
if (load(temp, false))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
PYBIND11_NOINLINE static PyObject *cast(const void *_src, return_value_policy policy, PyObject *parent,
|
||||
const std::type_info *type_info,
|
||||
void *(*copy_constructor)(const void *),
|
||||
const void *existing_holder = nullptr) {
|
||||
PYBIND11_NOINLINE static handle cast(const void *_src, return_value_policy policy, handle parent,
|
||||
const std::type_info *type_info,
|
||||
void *(*copy_constructor)(const void *),
|
||||
const void *existing_holder = nullptr) {
|
||||
void *src = const_cast<void *>(_src);
|
||||
if (src == nullptr) {
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
if (src == nullptr)
|
||||
return handle(Py_None).inc_ref();
|
||||
|
||||
// avoid an issue with internal references matching their parent's address
|
||||
bool dont_cache = policy == return_value_policy::reference_internal &&
|
||||
parent && ((instance<void> *) parent)->value == (void *) src;
|
||||
parent && ((instance<void> *) parent.ptr())->value == (void *) src;
|
||||
|
||||
auto& internals = get_internals();
|
||||
auto it_instance = internals.registered_instances.find(src);
|
||||
if (it_instance != internals.registered_instances.end() && !dont_cache) {
|
||||
PyObject *inst = (PyObject *) it_instance->second;
|
||||
Py_INCREF(inst);
|
||||
return inst;
|
||||
}
|
||||
if (it_instance != internals.registered_instances.end() && !dont_cache)
|
||||
return handle((PyObject *) it_instance->second).inc_ref();
|
||||
|
||||
auto it = internals.registered_types_cpp.find(type_info);
|
||||
if (it == internals.registered_types_cpp.end()) {
|
||||
std::string tname = type_info->name();
|
||||
detail::clean_type_id(tname);
|
||||
std::string msg = "Unregistered type : " + tname;
|
||||
PyErr_SetString(PyExc_TypeError, msg.c_str());
|
||||
return nullptr;
|
||||
return handle();
|
||||
}
|
||||
|
||||
auto tinfo = (const detail::type_info *) it->second;
|
||||
instance<void> *inst = (instance<void> *) PyType_GenericAlloc(tinfo->type, 0);
|
||||
inst->value = src;
|
||||
inst->owned = true;
|
||||
inst->parent = nullptr;
|
||||
object inst(PyType_GenericAlloc(tinfo->type, 0), false);
|
||||
|
||||
auto wrapper = (instance<void> *) inst.ptr();
|
||||
|
||||
wrapper->value = src;
|
||||
wrapper->owned = true;
|
||||
wrapper->parent = nullptr;
|
||||
|
||||
if (policy == return_value_policy::automatic)
|
||||
policy = return_value_policy::take_ownership;
|
||||
|
||||
if (policy == return_value_policy::copy) {
|
||||
inst->value = copy_constructor(inst->value);
|
||||
if (inst->value == nullptr)
|
||||
wrapper->value = copy_constructor(wrapper->value);
|
||||
if (wrapper->value == nullptr)
|
||||
throw cast_error("return_value_policy = copy, but the object is non-copyable!");
|
||||
} else if (policy == return_value_policy::reference) {
|
||||
inst->owned = false;
|
||||
wrapper->owned = false;
|
||||
} else if (policy == return_value_policy::reference_internal) {
|
||||
inst->owned = false;
|
||||
inst->parent = parent;
|
||||
Py_XINCREF(parent);
|
||||
wrapper->owned = false;
|
||||
wrapper->parent = parent.inc_ref().ptr();
|
||||
}
|
||||
PyObject *inst_pyobj = (PyObject *) inst;
|
||||
tinfo->init_holder(inst_pyobj, existing_holder);
|
||||
|
||||
tinfo->init_holder(inst.ptr(), existing_holder);
|
||||
if (!dont_cache)
|
||||
internals.registered_instances[inst->value] = inst_pyobj;
|
||||
return inst_pyobj;
|
||||
internals.registered_instances[wrapper->value] = inst.ptr();
|
||||
|
||||
return inst.release();
|
||||
}
|
||||
|
||||
protected:
|
||||
@ -121,15 +194,15 @@ template <typename type, typename Enable = void> class type_caster : public type
|
||||
public:
|
||||
static PYBIND11_DESCR name() { return type_descr(_<type>()); }
|
||||
|
||||
type_caster() : type_caster_generic(&typeid(type)) { }
|
||||
type_caster() : type_caster_generic(typeid(type)) { }
|
||||
|
||||
static PyObject *cast(const type &src, return_value_policy policy, PyObject *parent) {
|
||||
static handle cast(const type &src, return_value_policy policy, handle parent) {
|
||||
if (policy == return_value_policy::automatic)
|
||||
policy = return_value_policy::copy;
|
||||
return type_caster_generic::cast(&src, policy, parent, &typeid(type), ©_constructor);
|
||||
}
|
||||
|
||||
static PyObject *cast(const type *src, return_value_policy policy, PyObject *parent) {
|
||||
static handle cast(const type *src, return_value_policy policy, handle parent) {
|
||||
return type_caster_generic::cast(src, policy, parent, &typeid(type), ©_constructor);
|
||||
}
|
||||
|
||||
@ -149,7 +222,7 @@ protected:
|
||||
type value; \
|
||||
public: \
|
||||
static PYBIND11_DESCR name() { return type_descr(py_name); } \
|
||||
static PyObject *cast(const type *src, return_value_policy policy, PyObject *parent) { \
|
||||
static handle cast(const type *src, return_value_policy policy, handle parent) { \
|
||||
return cast(*src, policy, parent); \
|
||||
} \
|
||||
operator type*() { return &value; } \
|
||||
@ -171,21 +244,21 @@ struct type_caster<
|
||||
typedef typename std::conditional<std::is_floating_point<T>::value, double, _py_type_1>::type py_type;
|
||||
public:
|
||||
|
||||
bool load(PyObject *src, bool) {
|
||||
bool load(handle src, bool) {
|
||||
py_type py_value;
|
||||
|
||||
if (std::is_floating_point<T>::value) {
|
||||
py_value = (py_type) PyFloat_AsDouble(src);
|
||||
py_value = (py_type) PyFloat_AsDouble(src.ptr());
|
||||
} else if (sizeof(T) <= sizeof(long)) {
|
||||
if (std::is_signed<T>::value)
|
||||
py_value = (py_type) PyLong_AsLong(src);
|
||||
py_value = (py_type) PyLong_AsLong(src.ptr());
|
||||
else
|
||||
py_value = (py_type) PyLong_AsUnsignedLong(src);
|
||||
py_value = (py_type) PyLong_AsUnsignedLong(src.ptr());
|
||||
} else {
|
||||
if (std::is_signed<T>::value)
|
||||
py_value = (py_type) PYBIND11_LONG_AS_LONGLONG(src);
|
||||
py_value = (py_type) PYBIND11_LONG_AS_LONGLONG(src.ptr());
|
||||
else
|
||||
py_value = (py_type) PYBIND11_LONG_AS_UNSIGNED_LONGLONG(src);
|
||||
py_value = (py_type) PYBIND11_LONG_AS_UNSIGNED_LONGLONG(src.ptr());
|
||||
}
|
||||
|
||||
if ((py_value == (py_type) -1 && PyErr_Occurred()) ||
|
||||
@ -200,7 +273,7 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
static PyObject *cast(T src, return_value_policy /* policy */, PyObject * /* parent */) {
|
||||
static handle cast(T src, return_value_policy /* policy */, handle /* parent */) {
|
||||
if (std::is_floating_point<T>::value) {
|
||||
return PyFloat_FromDouble((double) src);
|
||||
} else if (sizeof(T) <= sizeof(long)) {
|
||||
@ -216,12 +289,13 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
static PyObject *cast(const T *src, return_value_policy policy, PyObject *parent) {
|
||||
static handle cast(const T *src, return_value_policy policy, handle parent) {
|
||||
return cast(*src, policy, parent);
|
||||
}
|
||||
|
||||
template <typename T2 = T, typename std::enable_if<std::is_integral<T2>::value, int>::type = 0>
|
||||
static PYBIND11_DESCR name() { return type_descr(_("int")); }
|
||||
|
||||
template <typename T2 = T, typename std::enable_if<!std::is_integral<T2>::value, int>::type = 0>
|
||||
static PYBIND11_DESCR name() { return type_descr(_("float")); }
|
||||
|
||||
@ -234,10 +308,9 @@ protected:
|
||||
|
||||
template <> class type_caster<void_type> {
|
||||
public:
|
||||
bool load(PyObject *, bool) { return false; }
|
||||
static PyObject *cast(void_type, return_value_policy /* policy */, PyObject * /* parent */) {
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
bool load(handle, bool) { return false; }
|
||||
static handle cast(void_type, return_value_policy /* policy */, handle /* parent */) {
|
||||
return handle(Py_None).inc_ref();
|
||||
}
|
||||
PYBIND11_TYPE_CASTER(void_type, _("NoneType"));
|
||||
};
|
||||
@ -247,38 +320,36 @@ template <> class type_caster<std::nullptr_t> : public type_caster<void_type> {
|
||||
|
||||
template <> class type_caster<bool> {
|
||||
public:
|
||||
bool load(PyObject *src, bool) {
|
||||
if (src == Py_True) { value = true; return true; }
|
||||
else if (src == Py_False) { value = false; return true; }
|
||||
bool load(handle src, bool) {
|
||||
if (src.ptr() == Py_True) { value = true; return true; }
|
||||
else if (src.ptr() == Py_False) { value = false; return true; }
|
||||
else return false;
|
||||
}
|
||||
static PyObject *cast(bool src, return_value_policy /* policy */, PyObject * /* parent */) {
|
||||
PyObject *result = src ? Py_True : Py_False;
|
||||
Py_INCREF(result);
|
||||
return result;
|
||||
static handle cast(bool src, return_value_policy /* policy */, handle /* parent */) {
|
||||
return handle(src ? Py_True : Py_False).inc_ref();
|
||||
}
|
||||
PYBIND11_TYPE_CASTER(bool, _("bool"));
|
||||
};
|
||||
|
||||
template <> class type_caster<std::string> {
|
||||
public:
|
||||
bool load(PyObject *src, bool) {
|
||||
bool load(handle src, bool) {
|
||||
object temp;
|
||||
PyObject *load_src = src;
|
||||
if (PyUnicode_Check(src)) {
|
||||
temp = object(PyUnicode_AsUTF8String(src), false);
|
||||
handle load_src = src;
|
||||
if (PyUnicode_Check(load_src.ptr())) {
|
||||
temp = object(PyUnicode_AsUTF8String(load_src.ptr()), false);
|
||||
if (!temp) { PyErr_Clear(); return false; } // UnicodeEncodeError
|
||||
load_src = temp.ptr();
|
||||
load_src = temp;
|
||||
}
|
||||
char *buffer;
|
||||
ssize_t length;
|
||||
int err = PYBIND11_BYTES_AS_STRING_AND_SIZE(load_src, &buffer, &length);
|
||||
int err = PYBIND11_BYTES_AS_STRING_AND_SIZE(load_src.ptr(), &buffer, &length);
|
||||
if (err == -1) { PyErr_Clear(); return false; } // TypeError
|
||||
value = std::string(buffer, length);
|
||||
return true;
|
||||
}
|
||||
|
||||
static PyObject *cast(const std::string &src, return_value_policy /* policy */, PyObject * /* parent */) {
|
||||
static handle cast(const std::string &src, return_value_policy /* policy */, handle /* parent */) {
|
||||
return PyUnicode_FromStringAndSize(src.c_str(), src.length());
|
||||
}
|
||||
|
||||
@ -287,25 +358,25 @@ public:
|
||||
|
||||
template <> class type_caster<char> {
|
||||
public:
|
||||
bool load(PyObject *src, bool) {
|
||||
bool load(handle src, bool) {
|
||||
object temp;
|
||||
PyObject *load_src = src;
|
||||
if (PyUnicode_Check(src)) {
|
||||
temp = object(PyUnicode_AsUTF8String(src), false);
|
||||
handle load_src = src;
|
||||
if (PyUnicode_Check(load_src.ptr())) {
|
||||
temp = object(PyUnicode_AsUTF8String(load_src.ptr()), false);
|
||||
if (!temp) { PyErr_Clear(); return false; } // UnicodeEncodeError
|
||||
load_src = temp.ptr();
|
||||
load_src = temp;
|
||||
}
|
||||
const char *ptr = PYBIND11_BYTES_AS_STRING(load_src);
|
||||
const char *ptr = PYBIND11_BYTES_AS_STRING(load_src.ptr());
|
||||
if (!ptr) { PyErr_Clear(); return false; } // TypeError
|
||||
value = std::string(ptr);
|
||||
return true;
|
||||
}
|
||||
|
||||
static PyObject *cast(const char *src, return_value_policy /* policy */, PyObject * /* parent */) {
|
||||
static handle cast(const char *src, return_value_policy /* policy */, handle /* parent */) {
|
||||
return PyUnicode_FromString(src);
|
||||
}
|
||||
|
||||
static PyObject *cast(char src, return_value_policy /* policy */, PyObject * /* parent */) {
|
||||
static handle cast(char src, return_value_policy /* policy */, handle /* parent */) {
|
||||
char str[2] = { src, '\0' };
|
||||
return PyUnicode_DecodeLatin1(str, 1, nullptr);
|
||||
}
|
||||
@ -321,25 +392,22 @@ protected:
|
||||
template <typename T1, typename T2> class type_caster<std::pair<T1, T2>> {
|
||||
typedef std::pair<T1, T2> type;
|
||||
public:
|
||||
bool load(PyObject *src, bool convert) {
|
||||
if (!PyTuple_Check(src) || PyTuple_Size(src) != 2)
|
||||
bool load(handle src, bool convert) {
|
||||
if (!PyTuple_Check(src.ptr()) || PyTuple_Size(src.ptr()) != 2)
|
||||
return false;
|
||||
if (!first.load(PyTuple_GET_ITEM(src, 0), convert))
|
||||
return false;
|
||||
return second.load(PyTuple_GET_ITEM(src, 1), convert);
|
||||
return first.load(PyTuple_GET_ITEM(src.ptr(), 0), convert) &&
|
||||
second.load(PyTuple_GET_ITEM(src.ptr(), 1), convert);
|
||||
}
|
||||
|
||||
static PyObject *cast(const type &src, return_value_policy policy, PyObject *parent) {
|
||||
object o1(type_caster<typename intrinsic_type<T1>::type>::cast(src.first, policy, parent), false);
|
||||
object o2(type_caster<typename intrinsic_type<T2>::type>::cast(src.second, policy, parent), false);
|
||||
static handle cast(const type &src, return_value_policy policy, handle parent) {
|
||||
object o1 = object(type_caster<typename intrinsic_type<T1>::type>::cast(src.first, policy, parent), false);
|
||||
object o2 = object(type_caster<typename intrinsic_type<T2>::type>::cast(src.second, policy, parent), false);
|
||||
if (!o1 || !o2)
|
||||
return nullptr;
|
||||
PyObject *tuple = PyTuple_New(2);
|
||||
if (!tuple)
|
||||
return nullptr;
|
||||
PyTuple_SET_ITEM(tuple, 0, o1.release());
|
||||
PyTuple_SET_ITEM(tuple, 1, o2.release());
|
||||
return tuple;
|
||||
return handle();
|
||||
tuple result(2);
|
||||
PyTuple_SET_ITEM(result.ptr(), 0, o1.release().ptr());
|
||||
PyTuple_SET_ITEM(result.ptr(), 1, o2.release().ptr());
|
||||
return result.release();
|
||||
}
|
||||
|
||||
static PYBIND11_DESCR name() {
|
||||
@ -361,11 +429,11 @@ template <typename... Tuple> class type_caster<std::tuple<Tuple...>> {
|
||||
public:
|
||||
enum { size = sizeof...(Tuple) };
|
||||
|
||||
bool load(PyObject *src, bool convert) {
|
||||
bool load(handle src, bool convert) {
|
||||
return load(src, convert, typename make_index_sequence<sizeof...(Tuple)>::type());
|
||||
}
|
||||
|
||||
static PyObject *cast(const type &src, return_value_policy policy, PyObject *parent) {
|
||||
static handle cast(const type &src, return_value_policy policy, handle parent) {
|
||||
return cast(src, policy, parent, typename make_index_sequence<size>::type());
|
||||
}
|
||||
|
||||
@ -398,36 +466,32 @@ protected:
|
||||
return type((Tuple) std::get<Index>(value)...);
|
||||
}
|
||||
|
||||
template <size_t ... Indices> bool load(PyObject *src, bool convert, index_sequence<Indices...>) {
|
||||
if (!PyTuple_Check(src))
|
||||
template <size_t ... Indices> bool load(handle src, bool convert, index_sequence<Indices...>) {
|
||||
if (!PyTuple_Check(src.ptr()) || PyTuple_Size(src.ptr()) != size)
|
||||
return false;
|
||||
if (PyTuple_Size(src) != size)
|
||||
return false;
|
||||
std::array<bool, size> results {{
|
||||
(PyTuple_GET_ITEM(src, Indices) != nullptr ? std::get<Indices>(value).load(PyTuple_GET_ITEM(src, Indices), convert) : false)...
|
||||
std::array<bool, size> success {{
|
||||
(PyTuple_GET_ITEM(src.ptr(), Indices) != nullptr ? std::get<Indices>(value).load(PyTuple_GET_ITEM(src.ptr(), Indices), convert) : false)...
|
||||
}};
|
||||
(void) convert; /* avoid a warning when the tuple is empty */
|
||||
for (bool r : results)
|
||||
for (bool r : success)
|
||||
if (!r)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Implementation: Convert a C++ tuple into a Python tuple */
|
||||
template <size_t ... Indices> static PyObject *cast(const type &src, return_value_policy policy, PyObject *parent, index_sequence<Indices...>) {
|
||||
std::array<object, size> results {{
|
||||
template <size_t ... Indices> static handle cast(const type &src, return_value_policy policy, handle parent, index_sequence<Indices...>) {
|
||||
std::array<object, size> entries {{
|
||||
object(type_caster<typename intrinsic_type<Tuple>::type>::cast(std::get<Indices>(src), policy, parent), false)...
|
||||
}};
|
||||
for (const auto & result : results)
|
||||
if (!result)
|
||||
return nullptr;
|
||||
PyObject *tuple = PyTuple_New(size);
|
||||
if (!tuple)
|
||||
return nullptr;
|
||||
for (const auto &entry: entries)
|
||||
if (!entry)
|
||||
return handle();
|
||||
tuple result(size);
|
||||
int counter = 0;
|
||||
for (auto & result : results)
|
||||
PyTuple_SET_ITEM(tuple, counter++, result.release());
|
||||
return tuple;
|
||||
for (auto & entry: entries)
|
||||
PyTuple_SET_ITEM(result.ptr(), counter++, entry.release().ptr());
|
||||
return result.release();
|
||||
}
|
||||
|
||||
protected:
|
||||
@ -443,19 +507,21 @@ public:
|
||||
using type_caster<type>::temp;
|
||||
using type_caster<type>::copy_constructor;
|
||||
|
||||
bool load(PyObject *src, bool convert) {
|
||||
if (src == nullptr || typeinfo == nullptr)
|
||||
bool load(handle src, bool convert) {
|
||||
if (!src || !typeinfo)
|
||||
return false;
|
||||
if (PyType_IsSubtype(Py_TYPE(src), typeinfo->type)) {
|
||||
auto inst = (instance<type, holder_type> *) src;
|
||||
|
||||
if (PyType_IsSubtype(Py_TYPE(src.ptr()), typeinfo->type)) {
|
||||
auto inst = (instance<type, holder_type> *) src.ptr();
|
||||
value = inst->value;
|
||||
holder = inst->holder;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (convert) {
|
||||
for (auto &converter : typeinfo->implicit_conversions) {
|
||||
temp = object(converter(src, typeinfo->type), false);
|
||||
if (load(temp.ptr(), false))
|
||||
temp = object(converter(src.ptr(), typeinfo->type), false);
|
||||
if (load(temp, false))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -467,7 +533,7 @@ public:
|
||||
explicit operator holder_type&() { return holder; }
|
||||
explicit operator holder_type*() { return &holder; }
|
||||
|
||||
static PyObject *cast(const holder_type &src, return_value_policy policy, PyObject *parent) {
|
||||
static handle cast(const holder_type &src, return_value_policy policy, handle parent) {
|
||||
return type_caster_generic::cast(
|
||||
src.get(), policy, parent, &typeid(type), ©_constructor, &src);
|
||||
}
|
||||
@ -483,27 +549,27 @@ template <typename type>
|
||||
struct type_caster<type, typename std::enable_if<std::is_base_of<handle, type>::value>::type> {
|
||||
public:
|
||||
template <typename T = type, typename std::enable_if<std::is_same<T, handle>::value, int>::type = 0>
|
||||
bool load(PyObject *src, bool /* convert */) { value = handle(src); return value.check(); }
|
||||
bool load(handle src, bool /* convert */) { value = src; return value.check(); }
|
||||
|
||||
template <typename T = type, typename std::enable_if<!std::is_same<T, handle>::value, int>::type = 0>
|
||||
bool load(PyObject *src, bool /* convert */) { value = type(src, true); return value.check(); }
|
||||
bool load(handle src, bool /* convert */) { value = type(src, true); return value.check(); }
|
||||
|
||||
static PyObject *cast(const handle &src, return_value_policy /* policy */, PyObject * /* parent */) {
|
||||
src.inc_ref(); return (PyObject *) src.ptr();
|
||||
static handle cast(const handle &src, return_value_policy /* policy */, handle /* parent */) {
|
||||
return src.inc_ref();
|
||||
}
|
||||
PYBIND11_TYPE_CASTER(type, handle_type_name<type>::name());
|
||||
};
|
||||
|
||||
NAMESPACE_END(detail)
|
||||
|
||||
template <typename T> inline T cast(PyObject *object) {
|
||||
template <typename T> inline T cast(handle handle) {
|
||||
detail::type_caster<typename detail::intrinsic_type<T>::type> conv;
|
||||
if (!conv.load(object, true))
|
||||
if (!conv.load(handle, true))
|
||||
throw cast_error("Unable to cast Python object to C++ type");
|
||||
return conv;
|
||||
}
|
||||
|
||||
template <typename T> inline object cast(const T &value, return_value_policy policy = return_value_policy::automatic, PyObject *parent = nullptr) {
|
||||
template <typename T> inline object cast(const T &value, return_value_policy policy = return_value_policy::automatic, handle parent = handle()) {
|
||||
if (policy == return_value_policy::automatic)
|
||||
policy = std::is_pointer<T>::value ? return_value_policy::take_ownership : return_value_policy::copy;
|
||||
return object(detail::type_caster<typename detail::intrinsic_type<T>::type>::cast(value, policy, parent), false);
|
||||
@ -514,23 +580,22 @@ template <> inline void handle::cast() const { return; }
|
||||
|
||||
template <typename... Args> inline object handle::call(Args&&... args_) const {
|
||||
const size_t size = sizeof...(Args);
|
||||
std::array<object, size> args{
|
||||
std::array<object, size> args {
|
||||
{ object(detail::type_caster<typename detail::intrinsic_type<Args>::type>::cast(
|
||||
std::forward<Args>(args_), return_value_policy::reference, nullptr), false)... }
|
||||
};
|
||||
for (const auto & result : args)
|
||||
if (!result)
|
||||
throw cast_error("handle::call(): unable to convert input arguments to Python objects");
|
||||
object tuple(PyTuple_New(size), false);
|
||||
if (!tuple)
|
||||
throw cast_error("handle::call(): unable to allocate tuple");
|
||||
for (auto &arg_value : args)
|
||||
if (!arg_value)
|
||||
throw cast_error("handle::call(): unable to convert input "
|
||||
"arguments to Python objects");
|
||||
tuple args_tuple(size);
|
||||
int counter = 0;
|
||||
for (auto & result : args)
|
||||
PyTuple_SET_ITEM(tuple.ptr(), counter++, result.release());
|
||||
PyObject *result = PyObject_CallObject(m_ptr, tuple.ptr());
|
||||
if (result == nullptr && PyErr_Occurred())
|
||||
for (auto &arg_value : args)
|
||||
PyTuple_SET_ITEM(args_tuple.ptr(), counter++, arg_value.release().ptr());
|
||||
object result(PyObject_CallObject(m_ptr, args_tuple.ptr()), false);
|
||||
if (!result)
|
||||
throw error_already_set();
|
||||
return object(result, false);
|
||||
return result;
|
||||
}
|
||||
|
||||
NAMESPACE_END(pybind11)
|
||||
|
@ -73,6 +73,7 @@
|
||||
#include <memory>
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3 /// Compatibility macros for various Python versions
|
||||
#define PYBIND11_INSTANCE_METHOD_NEW(ptr, class_) PyInstanceMethod_New(ptr)
|
||||
#define PYBIND11_BYTES_CHECK PyBytes_Check
|
||||
#define PYBIND11_BYTES_FROM_STRING PyBytes_FromString
|
||||
#define PYBIND11_BYTES_FROM_STRING_AND_SIZE PyBytes_FromStringAndSize
|
||||
@ -89,6 +90,7 @@
|
||||
#define PYBIND11_PLUGIN_IMPL(name) \
|
||||
extern "C" PYBIND11_EXPORT PyObject *PyInit_##name()
|
||||
#else
|
||||
#define PYBIND11_INSTANCE_METHOD_NEW(ptr, class_) PyMethod_New(ptr, nullptr, class_)
|
||||
#define PYBIND11_BYTES_CHECK PyString_Check
|
||||
#define PYBIND11_BYTES_FROM_STRING PyString_FromString
|
||||
#define PYBIND11_BYTES_FROM_STRING_AND_SIZE PyString_FromStringAndSize
|
||||
@ -200,16 +202,6 @@ template <typename type, typename holder_type = std::unique_ptr<type>> struct in
|
||||
holder_type holder;
|
||||
};
|
||||
|
||||
/// Additional type information which does not fit into the PyTypeObject
|
||||
struct type_info {
|
||||
PyTypeObject *type;
|
||||
size_t type_size;
|
||||
void (*init_holder)(PyObject *, const void *);
|
||||
std::vector<PyObject *(*)(PyObject *, PyTypeObject *)> implicit_conversions;
|
||||
buffer_info *(*get_buffer)(PyObject *, void *) = nullptr;
|
||||
void *get_buffer_data = nullptr;
|
||||
};
|
||||
|
||||
struct overload_hash {
|
||||
inline std::size_t operator()(const std::pair<const PyObject *, const char *>& v) const {
|
||||
size_t value = std::hash<const void *>()(v.first);
|
||||
@ -218,16 +210,6 @@ struct overload_hash {
|
||||
}
|
||||
};
|
||||
|
||||
/// Stores information about a keyword argument
|
||||
struct argument_entry {
|
||||
const char *name; ///< Argument name
|
||||
const char *descr; ///< Human-readable version of the argument value
|
||||
PyObject *value; ///< Associated Python object
|
||||
|
||||
argument_entry(const char *name, const char *descr, PyObject *value)
|
||||
: name(name), descr(descr), value(value) { }
|
||||
};
|
||||
|
||||
/// Internal data struture used to track registered instances and types
|
||||
struct internals {
|
||||
std::unordered_map<const void *, void*> registered_types_cpp; // std::type_info* -> type_info
|
||||
|
@ -20,8 +20,8 @@ PYBIND11_DECL_FMT(std::complex<double>, "Zd");
|
||||
NAMESPACE_BEGIN(detail)
|
||||
template <typename T> class type_caster<std::complex<T>> {
|
||||
public:
|
||||
bool load(PyObject *src, bool) {
|
||||
Py_complex result = PyComplex_AsCComplex(src);
|
||||
bool load(handle src, bool) {
|
||||
Py_complex result = PyComplex_AsCComplex(src.ptr());
|
||||
if (result.real == -1.0 && PyErr_Occurred()) {
|
||||
PyErr_Clear();
|
||||
return false;
|
||||
@ -30,7 +30,7 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
static PyObject *cast(const std::complex<T> &src, return_value_policy /* policy */, PyObject * /* parent */) {
|
||||
static handle cast(const std::complex<T> &src, return_value_policy /* policy */, handle /* parent */) {
|
||||
return PyComplex_FromDoubles((double) src.real(), (double) src.imag());
|
||||
}
|
||||
|
||||
|
@ -18,14 +18,13 @@ NAMESPACE_BEGIN(detail)
|
||||
template <typename Return, typename... Args> struct type_caster<std::function<Return(Args...)>> {
|
||||
typedef std::function<Return(Args...)> type;
|
||||
public:
|
||||
|
||||
bool load(PyObject *src_, bool) {
|
||||
bool load(handle src_, bool) {
|
||||
src_ = detail::get_function(src_);
|
||||
if (!src_ || !(PyFunction_Check(src_) || PyCFunction_Check(src_)))
|
||||
if (!src_ || !(PyFunction_Check(src_.ptr()) || PyCFunction_Check(src_.ptr())))
|
||||
return false;
|
||||
object src(src_, true);
|
||||
value = [src](Args... args) -> Return {
|
||||
object retval(pybind11::handle(src).call(std::move(args)...));
|
||||
object retval(src.call(std::move(args)...));
|
||||
/* Visual studio 2015 parser issue: need parentheses around this expression */
|
||||
return (retval.template cast<Return>());
|
||||
};
|
||||
@ -33,10 +32,8 @@ public:
|
||||
}
|
||||
|
||||
template <typename Func>
|
||||
static PyObject *cast(Func &&f_, return_value_policy policy, PyObject *) {
|
||||
cpp_function f(std::forward<Func>(f_), policy);
|
||||
f.inc_ref();
|
||||
return f.ptr();
|
||||
static handle cast(Func &&f_, return_value_policy policy, handle /* parent */) {
|
||||
return cpp_function(std::forward<Func>(f_), policy).release();
|
||||
}
|
||||
|
||||
PYBIND11_TYPE_CASTER(type, _("function<") +
|
||||
|
@ -79,36 +79,36 @@ public:
|
||||
API& api = lookup_api();
|
||||
PyObject *descr = api.PyArray_DescrFromType_(npy_format_descriptor<Type>::value);
|
||||
if (descr == nullptr)
|
||||
throw std::runtime_error("NumPy: unsupported buffer format!");
|
||||
pybind11_fail("NumPy: unsupported buffer format!");
|
||||
Py_intptr_t shape = (Py_intptr_t) size;
|
||||
object tmp = object(api.PyArray_NewFromDescr_(
|
||||
api.PyArray_Type_, descr, 1, &shape, nullptr, (void *) ptr, 0, nullptr), false);
|
||||
if (ptr && tmp)
|
||||
tmp = object(api.PyArray_NewCopy_(tmp.ptr(), -1 /* any order */), false);
|
||||
if (!tmp)
|
||||
throw std::runtime_error("NumPy: unable to create array!");
|
||||
m_ptr = tmp.release();
|
||||
pybind11_fail("NumPy: unable to create array!");
|
||||
m_ptr = tmp.release().ptr();
|
||||
}
|
||||
|
||||
array(const buffer_info &info) {
|
||||
API& api = lookup_api();
|
||||
if ((info.format.size() < 1) || (info.format.size() > 2))
|
||||
throw std::runtime_error("Unsupported buffer format!");
|
||||
pybind11_fail("Unsupported buffer format!");
|
||||
int fmt = (int) info.format[0];
|
||||
if (info.format == "Zd") fmt = API::NPY_CDOUBLE_;
|
||||
else if (info.format == "Zf") fmt = API::NPY_CFLOAT_;
|
||||
|
||||
PyObject *descr = api.PyArray_DescrFromType_(fmt);
|
||||
if (descr == nullptr)
|
||||
throw std::runtime_error("NumPy: unsupported buffer format '" + info.format + "'!");
|
||||
pybind11_fail("NumPy: unsupported buffer format '" + info.format + "'!");
|
||||
object tmp(api.PyArray_NewFromDescr_(
|
||||
api.PyArray_Type_, descr, info.ndim, (Py_intptr_t *) &info.shape[0],
|
||||
(Py_intptr_t *) &info.strides[0], info.ptr, 0, nullptr), false);
|
||||
if (info.ptr && tmp)
|
||||
tmp = object(api.PyArray_NewCopy_(tmp.ptr(), -1 /* any order */), false);
|
||||
if (!tmp)
|
||||
throw std::runtime_error("NumPy: unable to create array!");
|
||||
m_ptr = tmp.release();
|
||||
pybind11_fail("NumPy: unable to create array!");
|
||||
m_ptr = tmp.release().ptr();
|
||||
}
|
||||
|
||||
protected:
|
||||
@ -186,7 +186,7 @@ struct vectorize_helper {
|
||||
/* Check if the parameters are actually compatible */
|
||||
for (size_t i=0; i<N; ++i)
|
||||
if (buffers[i].size != 1 && (buffers[i].ndim != ndim || buffers[i].shape != shape))
|
||||
throw std::runtime_error("pybind11::vectorize: incompatible size/dimension of inputs!");
|
||||
pybind11_fail("pybind11::vectorize: incompatible size/dimension of inputs!");
|
||||
|
||||
if (size == 1)
|
||||
return cast(f(*((Args *) buffers[Index].ptr)...));
|
||||
|
@ -45,17 +45,17 @@ 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 Base, typename Holder, typename... Extra> void execute(pybind11::class_<Base, Holder> &class_, Extra&&... extra) const {
|
||||
template <typename Base, typename Holder, typename... Extra> void execute(pybind11::class_<Base, Holder> &class_, const 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<R, self_t>::value, Base, R>::type R_type;
|
||||
typedef op_impl<id, ot, Base, L_type, R_type> op;
|
||||
class_.def(op::name(), &op::execute, std::forward<Extra>(extra)...);
|
||||
class_.def(op::name(), &op::execute, extra...);
|
||||
}
|
||||
template <typename Base, typename Holder, typename... Extra> void execute_cast(pybind11::class_<Base, Holder> &class_, Extra&&... extra) const {
|
||||
template <typename Base, typename Holder, typename... Extra> void execute_cast(pybind11::class_<Base, Holder> &class_, const 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<R, self_t>::value, Base, R>::type R_type;
|
||||
typedef op_impl<id, ot, Base, L_type, R_type> op;
|
||||
class_.def(op::name(), &op::execute_cast, std::forward<Extra>(extra)...);
|
||||
class_.def(op::name(), &op::execute_cast, extra...);
|
||||
}
|
||||
};
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -30,10 +30,11 @@ public:
|
||||
handle(const handle &other) : m_ptr(other.m_ptr) { }
|
||||
handle(PyObject *ptr) : m_ptr(ptr) { }
|
||||
PyObject *ptr() const { return m_ptr; }
|
||||
void inc_ref() const { Py_XINCREF(m_ptr); }
|
||||
void dec_ref() const { Py_XDECREF(m_ptr); }
|
||||
PyObject *&ptr() { return m_ptr; }
|
||||
const handle& inc_ref() const { Py_XINCREF(m_ptr); return *this; }
|
||||
const handle& dec_ref() const { Py_XDECREF(m_ptr); return *this; }
|
||||
int ref_count() const { return (int) Py_REFCNT(m_ptr); }
|
||||
handle get_type() const { return (PyObject *) Py_TYPE(m_ptr); }
|
||||
handle get_type() const { return handle((PyObject *) Py_TYPE(m_ptr)); }
|
||||
inline iterator begin() const;
|
||||
inline iterator end() const;
|
||||
inline detail::accessor operator[](handle key) const;
|
||||
@ -44,6 +45,8 @@ public:
|
||||
template <typename T> T cast() const;
|
||||
template <typename ... Args> object call(Args&&... args_) const;
|
||||
operator bool() const { return m_ptr != nullptr; }
|
||||
bool operator==(const handle &h) const { return m_ptr == h.m_ptr; }
|
||||
bool operator!=(const handle &h) const { return m_ptr != h.m_ptr; }
|
||||
bool check() const { return m_ptr != nullptr; }
|
||||
protected:
|
||||
PyObject *m_ptr;
|
||||
@ -59,25 +62,25 @@ public:
|
||||
object(object &&other) { m_ptr = other.m_ptr; other.m_ptr = nullptr; }
|
||||
~object() { dec_ref(); }
|
||||
|
||||
PyObject * release() {
|
||||
handle release() {
|
||||
PyObject *tmp = m_ptr;
|
||||
m_ptr = nullptr;
|
||||
return tmp;
|
||||
return handle(tmp);
|
||||
}
|
||||
|
||||
object& operator=(object &other) {
|
||||
Py_XINCREF(other.m_ptr);
|
||||
Py_XDECREF(m_ptr);
|
||||
other.inc_ref();
|
||||
dec_ref();
|
||||
m_ptr = other.m_ptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
object& operator=(object &&other) {
|
||||
if (this != &other) {
|
||||
PyObject *temp = m_ptr;
|
||||
handle temp(m_ptr);
|
||||
m_ptr = other.m_ptr;
|
||||
other.m_ptr = nullptr;
|
||||
Py_XDECREF(temp);
|
||||
temp.dec_ref();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
@ -85,7 +88,7 @@ public:
|
||||
|
||||
class iterator : public object {
|
||||
public:
|
||||
iterator(PyObject *obj, bool borrowed = false) : object(obj, borrowed) { ++*this; }
|
||||
iterator(handle obj, bool borrowed = false) : object(obj, borrowed) { ++*this; }
|
||||
iterator& operator++() {
|
||||
if (ptr())
|
||||
value = object(PyIter_Next(m_ptr), false);
|
||||
@ -100,108 +103,106 @@ private:
|
||||
};
|
||||
|
||||
NAMESPACE_BEGIN(detail)
|
||||
inline PyObject *get_function(PyObject *value) {
|
||||
if (value == nullptr)
|
||||
return nullptr;
|
||||
inline handle get_function(handle value) {
|
||||
if (value) {
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
if (PyInstanceMethod_Check(value))
|
||||
value = PyInstanceMethod_GET_FUNCTION(value);
|
||||
if (PyInstanceMethod_Check(value.ptr()))
|
||||
value = PyInstanceMethod_GET_FUNCTION(value.ptr());
|
||||
#endif
|
||||
if (PyMethod_Check(value))
|
||||
value = PyMethod_GET_FUNCTION(value);
|
||||
if (PyMethod_Check(value.ptr()))
|
||||
value = PyMethod_GET_FUNCTION(value.ptr());
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
class accessor {
|
||||
public:
|
||||
accessor(PyObject *obj, PyObject *key, bool attr)
|
||||
: obj(obj), key(key), attr(attr) { Py_INCREF(key); }
|
||||
accessor(PyObject *obj, const char *key, bool attr)
|
||||
: obj(obj), key(PyUnicode_FromString(key)), attr(attr) { }
|
||||
accessor(const accessor &a) : obj(a.obj), key(a.key), attr(a.attr)
|
||||
{ Py_INCREF(key); }
|
||||
~accessor() { Py_DECREF(key); }
|
||||
accessor(handle obj, handle key, bool attr)
|
||||
: obj(obj), key(key, true), attr(attr) { }
|
||||
accessor(handle obj, const char *key, bool attr)
|
||||
: obj(obj), key(PyUnicode_FromString(key), false), attr(attr) { }
|
||||
accessor(const accessor &a) : obj(a.obj), key(a.key), attr(a.attr) { }
|
||||
|
||||
void operator=(accessor o) { operator=(object(o)); }
|
||||
|
||||
void operator=(const handle &h) {
|
||||
void operator=(const handle &value) {
|
||||
if (attr) {
|
||||
if (PyObject_SetAttr(obj, key, (PyObject *) h.ptr()) < 0)
|
||||
if (PyObject_SetAttr(obj.ptr(), key.ptr(), value.ptr()) == -1)
|
||||
pybind11_fail("Unable to set object attribute");
|
||||
} else {
|
||||
if (PyObject_SetItem(obj, key, (PyObject *) h.ptr()) < 0)
|
||||
if (PyObject_SetItem(obj.ptr(), key.ptr(), value.ptr()) == -1)
|
||||
pybind11_fail("Unable to set object item");
|
||||
}
|
||||
}
|
||||
|
||||
operator object() const {
|
||||
object result(attr ? PyObject_GetAttr(obj, key)
|
||||
: PyObject_GetItem(obj, key), false);
|
||||
if (!result) PyErr_Clear();
|
||||
object result(attr ? PyObject_GetAttr(obj.ptr(), key.ptr())
|
||||
: PyObject_GetItem(obj.ptr(), key.ptr()), false);
|
||||
if (!result) {PyErr_Clear(); }
|
||||
return result;
|
||||
}
|
||||
|
||||
operator bool() const {
|
||||
if (attr) {
|
||||
return (bool) PyObject_HasAttr(obj, key);
|
||||
return (bool) PyObject_HasAttr(obj.ptr(), key.ptr());
|
||||
} else {
|
||||
object result(PyObject_GetItem(obj, key), false);
|
||||
object result(PyObject_GetItem(obj.ptr(), key.ptr()), false);
|
||||
if (!result) PyErr_Clear();
|
||||
return (bool) result;
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
PyObject *obj;
|
||||
PyObject *key;
|
||||
handle obj;
|
||||
object key;
|
||||
bool attr;
|
||||
};
|
||||
|
||||
struct list_accessor {
|
||||
public:
|
||||
list_accessor(PyObject *list, size_t index) : list(list), index(index) { }
|
||||
list_accessor(handle list, size_t index) : list(list), index(index) { }
|
||||
void operator=(list_accessor o) { return operator=(object(o)); }
|
||||
void operator=(const handle &o) {
|
||||
o.inc_ref(); // PyList_SetItem steals a reference
|
||||
if (PyList_SetItem(list, (ssize_t) index, (PyObject *) o.ptr()) < 0)
|
||||
// PyList_SetItem steals a reference to 'o'
|
||||
if (PyList_SetItem(list.ptr(), (ssize_t) index, o.inc_ref().ptr()) < 0)
|
||||
pybind11_fail("Unable to assign value in Python list!");
|
||||
}
|
||||
operator object() const {
|
||||
PyObject *result = PyList_GetItem(list, (ssize_t) index);
|
||||
PyObject *result = PyList_GetItem(list.ptr(), (ssize_t) index);
|
||||
if (!result)
|
||||
pybind11_fail("Unable to retrieve value from Python list!");
|
||||
return object(result, true);
|
||||
}
|
||||
private:
|
||||
PyObject *list;
|
||||
handle list;
|
||||
size_t index;
|
||||
};
|
||||
|
||||
struct tuple_accessor {
|
||||
public:
|
||||
tuple_accessor(PyObject *tuple, size_t index) : tuple(tuple), index(index) { }
|
||||
tuple_accessor(handle tuple, size_t index) : tuple(tuple), index(index) { }
|
||||
void operator=(tuple_accessor o) { return operator=(object(o)); }
|
||||
void operator=(const handle &o) {
|
||||
o.inc_ref(); // PyTuple_SetItem steals a reference
|
||||
if (PyTuple_SetItem(tuple, (ssize_t) index, (PyObject *) o.ptr()) < 0)
|
||||
// PyTuple_SetItem steals a referenceto 'o'
|
||||
if (PyTuple_SetItem(tuple.ptr(), (ssize_t) index, o.inc_ref().ptr()) < 0)
|
||||
pybind11_fail("Unable to assign value in Python tuple!");
|
||||
}
|
||||
operator object() const {
|
||||
PyObject *result = PyTuple_GetItem(tuple, (ssize_t) index);
|
||||
PyObject *result = PyTuple_GetItem(tuple.ptr(), (ssize_t) index);
|
||||
if (!result)
|
||||
pybind11_fail("Unable to retrieve value from Python tuple!");
|
||||
return object(result, true);
|
||||
}
|
||||
private:
|
||||
PyObject *tuple;
|
||||
handle tuple;
|
||||
size_t index;
|
||||
};
|
||||
|
||||
struct dict_iterator {
|
||||
public:
|
||||
dict_iterator(PyObject *dict = nullptr, ssize_t pos = -1) : dict(dict), pos(pos) { }
|
||||
dict_iterator(handle dict = handle(), ssize_t pos = -1) : dict(dict), pos(pos) { }
|
||||
dict_iterator& operator++() {
|
||||
if (!PyDict_Next(dict, &pos, &key, &value))
|
||||
if (!PyDict_Next(dict.ptr(), &pos, &key.ptr(), &value.ptr()))
|
||||
pos = -1;
|
||||
return *this;
|
||||
}
|
||||
@ -211,7 +212,7 @@ public:
|
||||
bool operator==(const dict_iterator &it) const { return it.pos == pos; }
|
||||
bool operator!=(const dict_iterator &it) const { return it.pos != pos; }
|
||||
private:
|
||||
PyObject *dict, *key, *value;
|
||||
handle dict, key, value;
|
||||
ssize_t pos = 0;
|
||||
};
|
||||
|
||||
@ -410,8 +411,8 @@ public:
|
||||
if (!m_ptr) pybind11_fail("Could not allocate list object!");
|
||||
}
|
||||
size_t size() const { return (size_t) PyList_Size(m_ptr); }
|
||||
detail::list_accessor operator[](size_t index) const { return detail::list_accessor(ptr(), index); }
|
||||
void append(const object &object) const { PyList_Append(m_ptr, (PyObject *) object.ptr()); }
|
||||
detail::list_accessor operator[](size_t index) const { return detail::list_accessor(*this, index); }
|
||||
void append(const object &object) const { PyList_Append(m_ptr, object.ptr()); }
|
||||
};
|
||||
|
||||
class set : public object {
|
||||
@ -421,7 +422,7 @@ public:
|
||||
if (!m_ptr) pybind11_fail("Could not allocate set object!");
|
||||
}
|
||||
size_t size() const { return (size_t) PySet_Size(m_ptr); }
|
||||
bool add(const object &object) const { return PySet_Add(m_ptr, (PyObject *) object.ptr()) == 0; }
|
||||
bool add(const object &object) const { return PySet_Add(m_ptr, object.ptr()) == 0; }
|
||||
void clear() const { PySet_Clear(m_ptr); }
|
||||
};
|
||||
|
||||
@ -429,8 +430,8 @@ class function : public object {
|
||||
public:
|
||||
PYBIND11_OBJECT_DEFAULT(function, object, PyFunction_Check)
|
||||
bool is_cpp_function() const {
|
||||
PyObject *ptr = detail::get_function(m_ptr);
|
||||
return ptr != nullptr && PyCFunction_Check(ptr);
|
||||
handle fun = detail::get_function(m_ptr);
|
||||
return fun && PyCFunction_Check(fun.ptr());
|
||||
}
|
||||
};
|
||||
|
||||
@ -448,57 +449,4 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
NAMESPACE_BEGIN(detail)
|
||||
PYBIND11_NOINLINE inline internals &get_internals() {
|
||||
static internals *internals_ptr = nullptr;
|
||||
if (internals_ptr)
|
||||
return *internals_ptr;
|
||||
handle builtins(PyEval_GetBuiltins());
|
||||
capsule caps(builtins["__pybind11__"]);
|
||||
if (caps.check()) {
|
||||
internals_ptr = caps;
|
||||
} else {
|
||||
internals_ptr = new internals();
|
||||
builtins["__pybind11__"] = capsule(internals_ptr);
|
||||
}
|
||||
return *internals_ptr;
|
||||
}
|
||||
|
||||
PYBIND11_NOINLINE inline detail::type_info* get_type_info(PyTypeObject *type) {
|
||||
auto const &type_dict = get_internals().registered_types_py;
|
||||
do {
|
||||
auto it = type_dict.find(type);
|
||||
if (it != type_dict.end())
|
||||
return (detail::type_info *) it->second;
|
||||
type = type->tp_base;
|
||||
if (type == nullptr)
|
||||
pybind11_fail("pybind11::detail::get_type_info: unable to find type object!");
|
||||
} while (true);
|
||||
}
|
||||
|
||||
PYBIND11_NOINLINE inline std::string error_string() {
|
||||
std::string errorString;
|
||||
PyThreadState *tstate = PyThreadState_GET();
|
||||
if (tstate == nullptr)
|
||||
return "";
|
||||
|
||||
if (tstate->curexc_type) {
|
||||
errorString += (std::string) handle(tstate->curexc_type).str();
|
||||
errorString += ": ";
|
||||
}
|
||||
if (tstate->curexc_value)
|
||||
errorString += (std::string) handle(tstate->curexc_value).str();
|
||||
|
||||
return errorString;
|
||||
}
|
||||
|
||||
PYBIND11_NOINLINE inline handle get_object_handle(const void *ptr) {
|
||||
auto instances = get_internals().registered_instances;
|
||||
auto it = instances.find(ptr);
|
||||
if (it == instances.end())
|
||||
return handle();
|
||||
return handle((PyObject *) it->second);
|
||||
}
|
||||
|
||||
NAMESPACE_END(detail)
|
||||
NAMESPACE_END(pybind11)
|
||||
|
@ -26,7 +26,7 @@ template <typename Value, typename Alloc> struct type_caster<std::vector<Value,
|
||||
typedef std::vector<Value, Alloc> type;
|
||||
typedef type_caster<Value> value_conv;
|
||||
public:
|
||||
bool load(PyObject *src, bool convert) {
|
||||
bool load(handle src, bool convert) {
|
||||
list l(src, true);
|
||||
if (!l.check())
|
||||
return false;
|
||||
@ -34,21 +34,21 @@ public:
|
||||
value.clear();
|
||||
value_conv conv;
|
||||
for (auto it : l) {
|
||||
if (!conv.load(it.ptr(), convert))
|
||||
if (!conv.load(it, convert))
|
||||
return false;
|
||||
value.push_back((Value) conv);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static PyObject *cast(const type &src, return_value_policy policy, PyObject *parent) {
|
||||
static handle cast(const type &src, return_value_policy policy, handle parent) {
|
||||
list l(src.size());
|
||||
size_t index = 0;
|
||||
for (auto const &value: src) {
|
||||
object value_(value_conv::cast(value, policy, parent), false);
|
||||
object value_ = object(value_conv::cast(value, policy, parent), false);
|
||||
if (!value_)
|
||||
return nullptr;
|
||||
PyList_SET_ITEM(l.ptr(), index++, value_.release()); // steals a reference
|
||||
return handle();
|
||||
PyList_SET_ITEM(l.ptr(), index++, value_.release().ptr()); // steals a reference
|
||||
}
|
||||
return l.release();
|
||||
}
|
||||
@ -59,26 +59,26 @@ template <typename Key, typename Compare, typename Alloc> struct type_caster<std
|
||||
typedef std::set<Key, Compare, Alloc> type;
|
||||
typedef type_caster<Key> key_conv;
|
||||
public:
|
||||
bool load(PyObject *src, bool convert) {
|
||||
bool load(handle src, bool convert) {
|
||||
pybind11::set s(src, true);
|
||||
if (!s.check())
|
||||
return false;
|
||||
value.clear();
|
||||
key_conv conv;
|
||||
for (auto entry : s) {
|
||||
if (!conv.load(entry.ptr(), convert))
|
||||
if (!conv.load(entry, convert))
|
||||
return false;
|
||||
value.insert((Key) conv);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static PyObject *cast(const type &src, return_value_policy policy, PyObject *parent) {
|
||||
static handle cast(const type &src, return_value_policy policy, handle parent) {
|
||||
pybind11::set s;
|
||||
for (auto const &value: src) {
|
||||
object value_(key_conv::cast(value, policy, parent), false);
|
||||
object value_ = object(key_conv::cast(value, policy, parent), false);
|
||||
if (!value_ || !s.add(value))
|
||||
return nullptr;
|
||||
return handle();
|
||||
}
|
||||
return s.release();
|
||||
}
|
||||
@ -91,7 +91,7 @@ public:
|
||||
typedef type_caster<Key> key_conv;
|
||||
typedef type_caster<Value> value_conv;
|
||||
|
||||
bool load(PyObject *src, bool convert) {
|
||||
bool load(handle src, bool convert) {
|
||||
dict d(src, true);
|
||||
if (!d.check())
|
||||
return false;
|
||||
@ -107,13 +107,13 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
static PyObject *cast(const type &src, return_value_policy policy, PyObject *parent) {
|
||||
static handle cast(const type &src, return_value_policy policy, handle parent) {
|
||||
dict d;
|
||||
for (auto const &kv: src) {
|
||||
object key(key_conv::cast(kv.first, policy, parent), false);
|
||||
object value(value_conv::cast(kv.second, policy, parent), false);
|
||||
object key = object(key_conv::cast(kv.first, policy, parent), false);
|
||||
object value = object(value_conv::cast(kv.second, policy, parent), false);
|
||||
if (!key || !value)
|
||||
return nullptr;
|
||||
return handle();
|
||||
d[key] = value;
|
||||
}
|
||||
return d.release();
|
||||
|
15
setup.py
15
setup.py
@ -15,6 +15,7 @@ setup(
|
||||
packages=[],
|
||||
license='BSD',
|
||||
headers=[
|
||||
'include/pybind11/attr.h',
|
||||
'include/pybind11/cast.h',
|
||||
'include/pybind11/complex.h',
|
||||
'include/pybind11/descr.h',
|
||||
@ -58,10 +59,10 @@ C++11-compatible compilers are widely available, this heavy machinery has
|
||||
become an excessively large and unnecessary dependency.
|
||||
|
||||
Think of this library as a tiny self-contained version of Boost.Python with
|
||||
everything stripped away that isn't relevant for binding generation. The core
|
||||
header files only require ~2.5K lines of code and depend on Python (2.7 or 3.x)
|
||||
and the C++ standard library. This compact implementation was possible thanks
|
||||
to some of the new C++11 language features (specifically: tuples, lambda
|
||||
functions and variadic templates). Since its creation, this library has grown
|
||||
beyond Boost.Python in many ways, leading to dramatically simpler binding code
|
||||
in many common situations.""")
|
||||
everything stripped away that isn't relevant for binding generation. Without
|
||||
comments, the core header files only require ~2.5K lines of code and depend on
|
||||
Python (2.7 or 3.x) and the C++ standard library. This compact implementation
|
||||
was possible thanks to some of the new C++11 language features (specifically:
|
||||
tuples, lambda functions and variadic templates). Since its creation, this
|
||||
library has grown beyond Boost.Python in many ways, leading to dramatically
|
||||
simpler binding code in many common situations.""")
|
||||
|
Loading…
Reference in New Issue
Block a user