mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-29 08:32:02 +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)
|
include_directories(include)
|
||||||
|
|
||||||
set(PYBIND11_HEADERS
|
set(PYBIND11_HEADERS
|
||||||
|
include/pybind11/attr.h
|
||||||
include/pybind11/cast.h
|
include/pybind11/cast.h
|
||||||
include/pybind11/common.h
|
include/pybind11/common.h
|
||||||
include/pybind11/complex.h
|
include/pybind11/complex.h
|
||||||
@ -167,7 +168,7 @@ elseif (UNIX)
|
|||||||
# Strip unnecessary sections of the binary on Linux/Mac OS
|
# Strip unnecessary sections of the binary on Linux/Mac OS
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
set_target_properties(example PROPERTIES MACOSX_RPATH ".")
|
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)
|
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)
|
add_custom_command(TARGET example POST_BUILD COMMAND strip -u -r ${PROJECT_SOURCE_DIR}/example/example.so)
|
||||||
endif()
|
endif()
|
||||||
|
@ -925,7 +925,7 @@ If not available, the signature may not be very helpful, e.g.:
|
|||||||
FUNCTIONS
|
FUNCTIONS
|
||||||
...
|
...
|
||||||
| myFunction(...)
|
| 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__``.
|
The first way of addressing this is by defining ``SomeType.__repr__``.
|
||||||
|
@ -5,15 +5,19 @@ Changelog
|
|||||||
|
|
||||||
1.2 (not yet released)
|
1.2 (not yet released)
|
||||||
--------------------------
|
--------------------------
|
||||||
|
|
||||||
* Optional: efficient generation of function signatures at compile time using C++14
|
* 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
|
* Switched to a simpler and more general way of dealing with function default
|
||||||
Unused keyword arguments in function calls are now detected and cause errors as expected
|
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 ``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``
|
* Improved interface for RAII type wrappers in ``pytypes.h``
|
||||||
* Use RAII type wrappers consistently within pybind11 itself. This
|
* Use RAII type wrappers consistently within pybind11 itself. This
|
||||||
fixes various potential refcount leaks when exceptions occur
|
fixes various potential refcount leaks when exceptions occur
|
||||||
* Added new ``bytes`` RAII type wrapper (maps to ``string`` in Python 2.7).
|
* 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
|
* 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
|
now stored in a C++ hash table that is not visible in Python
|
||||||
* Fixed refcount leaks involving NumPy arrays and bound functions
|
* Fixed refcount leaks involving NumPy arrays and bound functions
|
||||||
@ -21,7 +25,9 @@ Changelog
|
|||||||
* Removed an unnecessary copy operation in ``pybind11::vectorize``
|
* Removed an unnecessary copy operation in ``pybind11::vectorize``
|
||||||
* Fixed naming clashes when both pybind11 and NumPy headers are included
|
* Fixed naming clashes when both pybind11 and NumPy headers are included
|
||||||
* Added conversions for additional exception types
|
* 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)
|
* Fixed license text (was: ZLIB, should have been: 3-clause BSD)
|
||||||
* Python 3.2 compatibility
|
* Python 3.2 compatibility
|
||||||
|
|
||||||
|
@ -177,9 +177,22 @@ inheritance relationship:
|
|||||||
std::string bark() const { return "woof!"; }
|
std::string bark() const { return "woof!"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
To capture the hierarchical relationship in pybind11, we must assign a name to
|
There are two different ways of indicating a hierarchical relationship to
|
||||||
the ``Pet`` :class:`class_` instance and reference it when binding the ``Dog``
|
pybind11: the first is by specifying the C++ base class explicitly during
|
||||||
class.
|
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
|
.. code-block:: cpp
|
||||||
|
|
||||||
@ -187,11 +200,12 @@ class.
|
|||||||
pet.def(py::init<const std::string &>())
|
pet.def(py::init<const std::string &>())
|
||||||
.def_readwrite("name", &Pet::name);
|
.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(py::init<const std::string &>())
|
||||||
.def("bark", &Dog::bark);
|
.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
|
.. code-block:: python
|
||||||
|
|
||||||
@ -242,14 +256,14 @@ The overload signatures are also visible in the method's docstring:
|
|||||||
| Methods defined here:
|
| Methods defined here:
|
||||||
|
|
|
|
||||||
| __init__(...)
|
| __init__(...)
|
||||||
| Signature : (Pet, str, int) -> None
|
| Signature : (Pet, str, int) -> NoneType
|
||||||
|
|
|
|
||||||
| set(...)
|
| set(...)
|
||||||
| 1. Signature : (Pet, int) -> None
|
| 1. Signature : (Pet, int) -> NoneType
|
||||||
|
|
|
|
||||||
| Set the pet's age
|
| Set the pet's age
|
||||||
|
|
|
|
||||||
| 2. Signature : (Pet, str) -> None
|
| 2. Signature : (Pet, str) -> NoneType
|
||||||
|
|
|
|
||||||
| Set the pet's name
|
| 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
|
# Strip unnecessary sections of the binary on Linux/Mac OS
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
set_target_properties(example PROPERTIES MACOSX_RPATH ".")
|
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)
|
if (NOT ${U_CMAKE_BUILD_TYPE} MATCHES DEBUG)
|
||||||
add_custom_command(TARGET example POST_BUILD COMMAND strip -u -r ${PROJECT_BINARY_DIR}/example.so)
|
add_custom_command(TARGET example POST_BUILD COMMAND strip -u -r ${PROJECT_BINARY_DIR}/example.so)
|
||||||
endif()
|
endif()
|
||||||
|
@ -63,17 +63,19 @@ Without reference counting
|
|||||||
|
|
||||||
Return the ``PyObject *`` underlying a :class:`handle`.
|
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
|
Manually increase the reference count of the Python object. Usually, it is
|
||||||
preferable to use the :class:`object` class which derives from
|
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
|
Manually decrease the reference count of the Python object. Usually, it is
|
||||||
preferable to use the :class:`object` class which derives from
|
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
|
.. function:: void handle::ref_count() const
|
||||||
|
|
||||||
@ -167,11 +169,11 @@ With reference counting
|
|||||||
Move constructor; steals the object from ``other`` and preserves its
|
Move constructor; steals the object from ``other`` and preserves its
|
||||||
reference count.
|
reference count.
|
||||||
|
|
||||||
.. function:: PyObject* object::release()
|
.. function:: handle object::release()
|
||||||
|
|
||||||
Release ownership of underlying ``PyObject *``. Returns raw Python object
|
Resets the internal pointer to ``nullptr`` without without decreasing the
|
||||||
pointer without decreasing its reference count and resets handle to
|
object's reference count. The function returns a raw handle to the original
|
||||||
``nullptr``-valued pointer.
|
Python object.
|
||||||
|
|
||||||
.. function:: object::~object()
|
.. function:: object::~object()
|
||||||
|
|
||||||
|
@ -29,6 +29,11 @@ public:
|
|||||||
void bark() const { std::cout << "Woof!" << std::endl; }
|
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) {
|
void pet_print(const Pet &pet) {
|
||||||
std::cout << pet.name() + " is a " + pet.species() << std::endl;
|
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("name", &Pet::name)
|
||||||
.def("species", &Pet::species);
|
.def("species", &Pet::species);
|
||||||
|
|
||||||
|
/* One way of declaring a subclass relationship: reference parent's class_ object */
|
||||||
py::class_<Dog>(m, "Dog", pet_class)
|
py::class_<Dog>(m, "Dog", pet_class)
|
||||||
.def(py::init<std::string>());
|
.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("pet_print", pet_print);
|
||||||
m.def("dog_bark", dog_bark);
|
m.def("dog_bark", dog_bark);
|
||||||
|
|
||||||
|
@ -5,11 +5,15 @@ sys.path.append('.')
|
|||||||
|
|
||||||
from example import Pet
|
from example import Pet
|
||||||
from example import Dog
|
from example import Dog
|
||||||
|
from example import Rabbit
|
||||||
from example import dog_bark
|
from example import dog_bark
|
||||||
from example import pet_print
|
from example import pet_print
|
||||||
|
|
||||||
polly = Pet('Polly', 'parrot')
|
polly = Pet('Polly', 'parrot')
|
||||||
molly = Dog('Molly')
|
molly = Dog('Molly')
|
||||||
|
roger = Rabbit('Rabbit')
|
||||||
|
print(roger.name() + " is a " + roger.species())
|
||||||
|
pet_print(roger)
|
||||||
print(polly.name() + " is a " + polly.species())
|
print(polly.name() + " is a " + polly.species())
|
||||||
pet_print(polly)
|
pet_print(polly)
|
||||||
print(molly.name() + " is a " + molly.species())
|
print(molly.name() + " is a " + molly.species())
|
||||||
|
@ -1,16 +1,7 @@
|
|||||||
|
Rabbit is a parrot
|
||||||
Polly is a parrot
|
Polly is a parrot
|
||||||
Polly is a parrot
|
|
||||||
Molly is a dog
|
|
||||||
Molly is a dog
|
Molly is a dog
|
||||||
Woof!
|
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
|
func(43) = 44
|
||||||
Payload constructor
|
Payload constructor
|
||||||
Payload copy constructor
|
Payload copy constructor
|
||||||
@ -18,3 +9,14 @@ Payload move constructor
|
|||||||
Payload destructor
|
Payload destructor
|
||||||
Payload destructor
|
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(pybind11)
|
||||||
NAMESPACE_BEGIN(detail)
|
NAMESPACE_BEGIN(detail)
|
||||||
|
|
||||||
class type_caster_generic {
|
/// Additional type information which does not fit into the PyTypeObject
|
||||||
public:
|
struct type_info {
|
||||||
PYBIND11_NOINLINE type_caster_generic(const std::type_info *type_info) {
|
PyTypeObject *type;
|
||||||
auto &types = get_internals().registered_types_cpp;
|
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);
|
PYBIND11_NOINLINE inline internals &get_internals() {
|
||||||
if (it != types.end()) {
|
static internals *internals_ptr = nullptr;
|
||||||
typeinfo = (detail::type_info *) it->second;
|
if (internals_ptr)
|
||||||
} else {
|
return *internals_ptr;
|
||||||
/* Unknown type?! Since std::type_info* often varies across
|
handle builtins(PyEval_GetBuiltins());
|
||||||
module boundaries, the following does an explicit check */
|
capsule caps(builtins["__pybind11__"]);
|
||||||
for (auto const &type : types) {
|
if (caps.check()) {
|
||||||
auto *first = (const std::type_info *) type.first;
|
internals_ptr = caps;
|
||||||
if (strcmp(first->name(), type_info->name()) == 0) {
|
} else {
|
||||||
types[type_info] = type.second;
|
internals_ptr = new internals();
|
||||||
typeinfo = (detail::type_info *) type.second;
|
builtins["__pybind11__"] = capsule(internals_ptr);
|
||||||
break;
|
}
|
||||||
}
|
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) {
|
PYBIND11_NOINLINE inline handle get_type_handle(const std::type_info &tp) {
|
||||||
if (src == nullptr || typeinfo == nullptr)
|
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;
|
return false;
|
||||||
if (PyType_IsSubtype(Py_TYPE(src), typeinfo->type)) {
|
if (PyType_IsSubtype(Py_TYPE(src.ptr()), typeinfo->type)) {
|
||||||
value = ((instance<void> *) src)->value;
|
value = ((instance<void> *) src.ptr())->value;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (convert) {
|
if (convert) {
|
||||||
for (auto &converter : typeinfo->implicit_conversions) {
|
for (auto &converter : typeinfo->implicit_conversions) {
|
||||||
temp = object(converter(src, typeinfo->type), false);
|
temp = object(converter(src.ptr(), typeinfo->type), false);
|
||||||
if (load(temp.ptr(), false))
|
if (load(temp, false))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
PYBIND11_NOINLINE static PyObject *cast(const void *_src, return_value_policy policy, PyObject *parent,
|
PYBIND11_NOINLINE static handle cast(const void *_src, return_value_policy policy, handle parent,
|
||||||
const std::type_info *type_info,
|
const std::type_info *type_info,
|
||||||
void *(*copy_constructor)(const void *),
|
void *(*copy_constructor)(const void *),
|
||||||
const void *existing_holder = nullptr) {
|
const void *existing_holder = nullptr) {
|
||||||
void *src = const_cast<void *>(_src);
|
void *src = const_cast<void *>(_src);
|
||||||
if (src == nullptr) {
|
if (src == nullptr)
|
||||||
Py_INCREF(Py_None);
|
return handle(Py_None).inc_ref();
|
||||||
return Py_None;
|
|
||||||
}
|
|
||||||
// avoid an issue with internal references matching their parent's address
|
// avoid an issue with internal references matching their parent's address
|
||||||
bool dont_cache = policy == return_value_policy::reference_internal &&
|
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& internals = get_internals();
|
||||||
auto it_instance = internals.registered_instances.find(src);
|
auto it_instance = internals.registered_instances.find(src);
|
||||||
if (it_instance != internals.registered_instances.end() && !dont_cache) {
|
if (it_instance != internals.registered_instances.end() && !dont_cache)
|
||||||
PyObject *inst = (PyObject *) it_instance->second;
|
return handle((PyObject *) it_instance->second).inc_ref();
|
||||||
Py_INCREF(inst);
|
|
||||||
return inst;
|
|
||||||
}
|
|
||||||
auto it = internals.registered_types_cpp.find(type_info);
|
auto it = internals.registered_types_cpp.find(type_info);
|
||||||
if (it == internals.registered_types_cpp.end()) {
|
if (it == internals.registered_types_cpp.end()) {
|
||||||
std::string tname = type_info->name();
|
std::string tname = type_info->name();
|
||||||
detail::clean_type_id(tname);
|
detail::clean_type_id(tname);
|
||||||
std::string msg = "Unregistered type : " + tname;
|
std::string msg = "Unregistered type : " + tname;
|
||||||
PyErr_SetString(PyExc_TypeError, msg.c_str());
|
PyErr_SetString(PyExc_TypeError, msg.c_str());
|
||||||
return nullptr;
|
return handle();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto tinfo = (const detail::type_info *) it->second;
|
auto tinfo = (const detail::type_info *) it->second;
|
||||||
instance<void> *inst = (instance<void> *) PyType_GenericAlloc(tinfo->type, 0);
|
object inst(PyType_GenericAlloc(tinfo->type, 0), false);
|
||||||
inst->value = src;
|
|
||||||
inst->owned = true;
|
auto wrapper = (instance<void> *) inst.ptr();
|
||||||
inst->parent = nullptr;
|
|
||||||
|
wrapper->value = src;
|
||||||
|
wrapper->owned = true;
|
||||||
|
wrapper->parent = nullptr;
|
||||||
|
|
||||||
if (policy == return_value_policy::automatic)
|
if (policy == return_value_policy::automatic)
|
||||||
policy = return_value_policy::take_ownership;
|
policy = return_value_policy::take_ownership;
|
||||||
|
|
||||||
if (policy == return_value_policy::copy) {
|
if (policy == return_value_policy::copy) {
|
||||||
inst->value = copy_constructor(inst->value);
|
wrapper->value = copy_constructor(wrapper->value);
|
||||||
if (inst->value == nullptr)
|
if (wrapper->value == nullptr)
|
||||||
throw cast_error("return_value_policy = copy, but the object is non-copyable!");
|
throw cast_error("return_value_policy = copy, but the object is non-copyable!");
|
||||||
} else if (policy == return_value_policy::reference) {
|
} else if (policy == return_value_policy::reference) {
|
||||||
inst->owned = false;
|
wrapper->owned = false;
|
||||||
} else if (policy == return_value_policy::reference_internal) {
|
} else if (policy == return_value_policy::reference_internal) {
|
||||||
inst->owned = false;
|
wrapper->owned = false;
|
||||||
inst->parent = parent;
|
wrapper->parent = parent.inc_ref().ptr();
|
||||||
Py_XINCREF(parent);
|
|
||||||
}
|
}
|
||||||
PyObject *inst_pyobj = (PyObject *) inst;
|
|
||||||
tinfo->init_holder(inst_pyobj, existing_holder);
|
tinfo->init_holder(inst.ptr(), existing_holder);
|
||||||
if (!dont_cache)
|
if (!dont_cache)
|
||||||
internals.registered_instances[inst->value] = inst_pyobj;
|
internals.registered_instances[wrapper->value] = inst.ptr();
|
||||||
return inst_pyobj;
|
|
||||||
|
return inst.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -121,15 +194,15 @@ template <typename type, typename Enable = void> class type_caster : public type
|
|||||||
public:
|
public:
|
||||||
static PYBIND11_DESCR name() { return type_descr(_<type>()); }
|
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)
|
if (policy == return_value_policy::automatic)
|
||||||
policy = return_value_policy::copy;
|
policy = return_value_policy::copy;
|
||||||
return type_caster_generic::cast(&src, policy, parent, &typeid(type), ©_constructor);
|
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);
|
return type_caster_generic::cast(src, policy, parent, &typeid(type), ©_constructor);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,7 +222,7 @@ protected:
|
|||||||
type value; \
|
type value; \
|
||||||
public: \
|
public: \
|
||||||
static PYBIND11_DESCR name() { return type_descr(py_name); } \
|
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); \
|
return cast(*src, policy, parent); \
|
||||||
} \
|
} \
|
||||||
operator type*() { return &value; } \
|
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;
|
typedef typename std::conditional<std::is_floating_point<T>::value, double, _py_type_1>::type py_type;
|
||||||
public:
|
public:
|
||||||
|
|
||||||
bool load(PyObject *src, bool) {
|
bool load(handle src, bool) {
|
||||||
py_type py_value;
|
py_type py_value;
|
||||||
|
|
||||||
if (std::is_floating_point<T>::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)) {
|
} else if (sizeof(T) <= sizeof(long)) {
|
||||||
if (std::is_signed<T>::value)
|
if (std::is_signed<T>::value)
|
||||||
py_value = (py_type) PyLong_AsLong(src);
|
py_value = (py_type) PyLong_AsLong(src.ptr());
|
||||||
else
|
else
|
||||||
py_value = (py_type) PyLong_AsUnsignedLong(src);
|
py_value = (py_type) PyLong_AsUnsignedLong(src.ptr());
|
||||||
} else {
|
} else {
|
||||||
if (std::is_signed<T>::value)
|
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
|
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()) ||
|
if ((py_value == (py_type) -1 && PyErr_Occurred()) ||
|
||||||
@ -200,7 +273,7 @@ public:
|
|||||||
return true;
|
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) {
|
if (std::is_floating_point<T>::value) {
|
||||||
return PyFloat_FromDouble((double) src);
|
return PyFloat_FromDouble((double) src);
|
||||||
} else if (sizeof(T) <= sizeof(long)) {
|
} 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);
|
return cast(*src, policy, parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T2 = T, typename std::enable_if<std::is_integral<T2>::value, int>::type = 0>
|
template <typename T2 = T, typename std::enable_if<std::is_integral<T2>::value, int>::type = 0>
|
||||||
static PYBIND11_DESCR name() { return type_descr(_("int")); }
|
static PYBIND11_DESCR name() { return type_descr(_("int")); }
|
||||||
|
|
||||||
template <typename T2 = T, typename std::enable_if<!std::is_integral<T2>::value, int>::type = 0>
|
template <typename T2 = T, typename std::enable_if<!std::is_integral<T2>::value, int>::type = 0>
|
||||||
static PYBIND11_DESCR name() { return type_descr(_("float")); }
|
static PYBIND11_DESCR name() { return type_descr(_("float")); }
|
||||||
|
|
||||||
@ -234,10 +308,9 @@ protected:
|
|||||||
|
|
||||||
template <> class type_caster<void_type> {
|
template <> class type_caster<void_type> {
|
||||||
public:
|
public:
|
||||||
bool load(PyObject *, bool) { return false; }
|
bool load(handle, bool) { return false; }
|
||||||
static PyObject *cast(void_type, return_value_policy /* policy */, PyObject * /* parent */) {
|
static handle cast(void_type, return_value_policy /* policy */, handle /* parent */) {
|
||||||
Py_INCREF(Py_None);
|
return handle(Py_None).inc_ref();
|
||||||
return Py_None;
|
|
||||||
}
|
}
|
||||||
PYBIND11_TYPE_CASTER(void_type, _("NoneType"));
|
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> {
|
template <> class type_caster<bool> {
|
||||||
public:
|
public:
|
||||||
bool load(PyObject *src, bool) {
|
bool load(handle src, bool) {
|
||||||
if (src == Py_True) { value = true; return true; }
|
if (src.ptr() == Py_True) { value = true; return true; }
|
||||||
else if (src == Py_False) { value = false; return true; }
|
else if (src.ptr() == Py_False) { value = false; return true; }
|
||||||
else return false;
|
else return false;
|
||||||
}
|
}
|
||||||
static PyObject *cast(bool src, return_value_policy /* policy */, PyObject * /* parent */) {
|
static handle cast(bool src, return_value_policy /* policy */, handle /* parent */) {
|
||||||
PyObject *result = src ? Py_True : Py_False;
|
return handle(src ? Py_True : Py_False).inc_ref();
|
||||||
Py_INCREF(result);
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
PYBIND11_TYPE_CASTER(bool, _("bool"));
|
PYBIND11_TYPE_CASTER(bool, _("bool"));
|
||||||
};
|
};
|
||||||
|
|
||||||
template <> class type_caster<std::string> {
|
template <> class type_caster<std::string> {
|
||||||
public:
|
public:
|
||||||
bool load(PyObject *src, bool) {
|
bool load(handle src, bool) {
|
||||||
object temp;
|
object temp;
|
||||||
PyObject *load_src = src;
|
handle load_src = src;
|
||||||
if (PyUnicode_Check(src)) {
|
if (PyUnicode_Check(load_src.ptr())) {
|
||||||
temp = object(PyUnicode_AsUTF8String(src), false);
|
temp = object(PyUnicode_AsUTF8String(load_src.ptr()), false);
|
||||||
if (!temp) { PyErr_Clear(); return false; } // UnicodeEncodeError
|
if (!temp) { PyErr_Clear(); return false; } // UnicodeEncodeError
|
||||||
load_src = temp.ptr();
|
load_src = temp;
|
||||||
}
|
}
|
||||||
char *buffer;
|
char *buffer;
|
||||||
ssize_t length;
|
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
|
if (err == -1) { PyErr_Clear(); return false; } // TypeError
|
||||||
value = std::string(buffer, length);
|
value = std::string(buffer, length);
|
||||||
return true;
|
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());
|
return PyUnicode_FromStringAndSize(src.c_str(), src.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -287,25 +358,25 @@ public:
|
|||||||
|
|
||||||
template <> class type_caster<char> {
|
template <> class type_caster<char> {
|
||||||
public:
|
public:
|
||||||
bool load(PyObject *src, bool) {
|
bool load(handle src, bool) {
|
||||||
object temp;
|
object temp;
|
||||||
PyObject *load_src = src;
|
handle load_src = src;
|
||||||
if (PyUnicode_Check(src)) {
|
if (PyUnicode_Check(load_src.ptr())) {
|
||||||
temp = object(PyUnicode_AsUTF8String(src), false);
|
temp = object(PyUnicode_AsUTF8String(load_src.ptr()), false);
|
||||||
if (!temp) { PyErr_Clear(); return false; } // UnicodeEncodeError
|
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
|
if (!ptr) { PyErr_Clear(); return false; } // TypeError
|
||||||
value = std::string(ptr);
|
value = std::string(ptr);
|
||||||
return true;
|
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);
|
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' };
|
char str[2] = { src, '\0' };
|
||||||
return PyUnicode_DecodeLatin1(str, 1, nullptr);
|
return PyUnicode_DecodeLatin1(str, 1, nullptr);
|
||||||
}
|
}
|
||||||
@ -321,25 +392,22 @@ protected:
|
|||||||
template <typename T1, typename T2> class type_caster<std::pair<T1, T2>> {
|
template <typename T1, typename T2> class type_caster<std::pair<T1, T2>> {
|
||||||
typedef std::pair<T1, T2> type;
|
typedef std::pair<T1, T2> type;
|
||||||
public:
|
public:
|
||||||
bool load(PyObject *src, bool convert) {
|
bool load(handle src, bool convert) {
|
||||||
if (!PyTuple_Check(src) || PyTuple_Size(src) != 2)
|
if (!PyTuple_Check(src.ptr()) || PyTuple_Size(src.ptr()) != 2)
|
||||||
return false;
|
return false;
|
||||||
if (!first.load(PyTuple_GET_ITEM(src, 0), convert))
|
return first.load(PyTuple_GET_ITEM(src.ptr(), 0), convert) &&
|
||||||
return false;
|
second.load(PyTuple_GET_ITEM(src.ptr(), 1), convert);
|
||||||
return second.load(PyTuple_GET_ITEM(src, 1), convert);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *cast(const type &src, return_value_policy policy, PyObject *parent) {
|
static handle cast(const type &src, return_value_policy policy, handle parent) {
|
||||||
object o1(type_caster<typename intrinsic_type<T1>::type>::cast(src.first, policy, parent), false);
|
object o1 = object(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);
|
object o2 = object(type_caster<typename intrinsic_type<T2>::type>::cast(src.second, policy, parent), false);
|
||||||
if (!o1 || !o2)
|
if (!o1 || !o2)
|
||||||
return nullptr;
|
return handle();
|
||||||
PyObject *tuple = PyTuple_New(2);
|
tuple result(2);
|
||||||
if (!tuple)
|
PyTuple_SET_ITEM(result.ptr(), 0, o1.release().ptr());
|
||||||
return nullptr;
|
PyTuple_SET_ITEM(result.ptr(), 1, o2.release().ptr());
|
||||||
PyTuple_SET_ITEM(tuple, 0, o1.release());
|
return result.release();
|
||||||
PyTuple_SET_ITEM(tuple, 1, o2.release());
|
|
||||||
return tuple;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static PYBIND11_DESCR name() {
|
static PYBIND11_DESCR name() {
|
||||||
@ -361,11 +429,11 @@ template <typename... Tuple> class type_caster<std::tuple<Tuple...>> {
|
|||||||
public:
|
public:
|
||||||
enum { size = sizeof...(Tuple) };
|
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());
|
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());
|
return cast(src, policy, parent, typename make_index_sequence<size>::type());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -398,36 +466,32 @@ protected:
|
|||||||
return type((Tuple) std::get<Index>(value)...);
|
return type((Tuple) std::get<Index>(value)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <size_t ... Indices> bool load(PyObject *src, bool convert, index_sequence<Indices...>) {
|
template <size_t ... Indices> bool load(handle src, bool convert, index_sequence<Indices...>) {
|
||||||
if (!PyTuple_Check(src))
|
if (!PyTuple_Check(src.ptr()) || PyTuple_Size(src.ptr()) != size)
|
||||||
return false;
|
return false;
|
||||||
if (PyTuple_Size(src) != size)
|
std::array<bool, size> success {{
|
||||||
return false;
|
(PyTuple_GET_ITEM(src.ptr(), Indices) != nullptr ? std::get<Indices>(value).load(PyTuple_GET_ITEM(src.ptr(), Indices), convert) : false)...
|
||||||
std::array<bool, size> results {{
|
|
||||||
(PyTuple_GET_ITEM(src, Indices) != nullptr ? std::get<Indices>(value).load(PyTuple_GET_ITEM(src, Indices), convert) : false)...
|
|
||||||
}};
|
}};
|
||||||
(void) convert; /* avoid a warning when the tuple is empty */
|
(void) convert; /* avoid a warning when the tuple is empty */
|
||||||
for (bool r : results)
|
for (bool r : success)
|
||||||
if (!r)
|
if (!r)
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Implementation: Convert a C++ tuple into a Python tuple */
|
/* 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...>) {
|
template <size_t ... Indices> static handle cast(const type &src, return_value_policy policy, handle parent, index_sequence<Indices...>) {
|
||||||
std::array<object, size> results {{
|
std::array<object, size> entries {{
|
||||||
object(type_caster<typename intrinsic_type<Tuple>::type>::cast(std::get<Indices>(src), policy, parent), false)...
|
object(type_caster<typename intrinsic_type<Tuple>::type>::cast(std::get<Indices>(src), policy, parent), false)...
|
||||||
}};
|
}};
|
||||||
for (const auto & result : results)
|
for (const auto &entry: entries)
|
||||||
if (!result)
|
if (!entry)
|
||||||
return nullptr;
|
return handle();
|
||||||
PyObject *tuple = PyTuple_New(size);
|
tuple result(size);
|
||||||
if (!tuple)
|
|
||||||
return nullptr;
|
|
||||||
int counter = 0;
|
int counter = 0;
|
||||||
for (auto & result : results)
|
for (auto & entry: entries)
|
||||||
PyTuple_SET_ITEM(tuple, counter++, result.release());
|
PyTuple_SET_ITEM(result.ptr(), counter++, entry.release().ptr());
|
||||||
return tuple;
|
return result.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -443,19 +507,21 @@ public:
|
|||||||
using type_caster<type>::temp;
|
using type_caster<type>::temp;
|
||||||
using type_caster<type>::copy_constructor;
|
using type_caster<type>::copy_constructor;
|
||||||
|
|
||||||
bool load(PyObject *src, bool convert) {
|
bool load(handle src, bool convert) {
|
||||||
if (src == nullptr || typeinfo == nullptr)
|
if (!src || !typeinfo)
|
||||||
return false;
|
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;
|
value = inst->value;
|
||||||
holder = inst->holder;
|
holder = inst->holder;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (convert) {
|
if (convert) {
|
||||||
for (auto &converter : typeinfo->implicit_conversions) {
|
for (auto &converter : typeinfo->implicit_conversions) {
|
||||||
temp = object(converter(src, typeinfo->type), false);
|
temp = object(converter(src.ptr(), typeinfo->type), false);
|
||||||
if (load(temp.ptr(), false))
|
if (load(temp, false))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -467,7 +533,7 @@ public:
|
|||||||
explicit operator holder_type&() { return holder; }
|
explicit operator holder_type&() { return holder; }
|
||||||
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(
|
return type_caster_generic::cast(
|
||||||
src.get(), policy, parent, &typeid(type), ©_constructor, &src);
|
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> {
|
struct type_caster<type, typename std::enable_if<std::is_base_of<handle, type>::value>::type> {
|
||||||
public:
|
public:
|
||||||
template <typename T = type, typename std::enable_if<std::is_same<T, handle>::value, int>::type = 0>
|
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>
|
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 */) {
|
static handle cast(const handle &src, return_value_policy /* policy */, handle /* parent */) {
|
||||||
src.inc_ref(); return (PyObject *) src.ptr();
|
return src.inc_ref();
|
||||||
}
|
}
|
||||||
PYBIND11_TYPE_CASTER(type, handle_type_name<type>::name());
|
PYBIND11_TYPE_CASTER(type, handle_type_name<type>::name());
|
||||||
};
|
};
|
||||||
|
|
||||||
NAMESPACE_END(detail)
|
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;
|
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");
|
throw cast_error("Unable to cast Python object to C++ type");
|
||||||
return conv;
|
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)
|
if (policy == return_value_policy::automatic)
|
||||||
policy = std::is_pointer<T>::value ? return_value_policy::take_ownership : return_value_policy::copy;
|
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);
|
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 {
|
template <typename... Args> inline object handle::call(Args&&... args_) const {
|
||||||
const size_t size = sizeof...(Args);
|
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(
|
{ object(detail::type_caster<typename detail::intrinsic_type<Args>::type>::cast(
|
||||||
std::forward<Args>(args_), return_value_policy::reference, nullptr), false)... }
|
std::forward<Args>(args_), return_value_policy::reference, nullptr), false)... }
|
||||||
};
|
};
|
||||||
for (const auto & result : args)
|
for (auto &arg_value : args)
|
||||||
if (!result)
|
if (!arg_value)
|
||||||
throw cast_error("handle::call(): unable to convert input arguments to Python objects");
|
throw cast_error("handle::call(): unable to convert input "
|
||||||
object tuple(PyTuple_New(size), false);
|
"arguments to Python objects");
|
||||||
if (!tuple)
|
tuple args_tuple(size);
|
||||||
throw cast_error("handle::call(): unable to allocate tuple");
|
|
||||||
int counter = 0;
|
int counter = 0;
|
||||||
for (auto & result : args)
|
for (auto &arg_value : args)
|
||||||
PyTuple_SET_ITEM(tuple.ptr(), counter++, result.release());
|
PyTuple_SET_ITEM(args_tuple.ptr(), counter++, arg_value.release().ptr());
|
||||||
PyObject *result = PyObject_CallObject(m_ptr, tuple.ptr());
|
object result(PyObject_CallObject(m_ptr, args_tuple.ptr()), false);
|
||||||
if (result == nullptr && PyErr_Occurred())
|
if (!result)
|
||||||
throw error_already_set();
|
throw error_already_set();
|
||||||
return object(result, false);
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
NAMESPACE_END(pybind11)
|
NAMESPACE_END(pybind11)
|
||||||
|
@ -73,6 +73,7 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#if PY_MAJOR_VERSION >= 3 /// Compatibility macros for various Python versions
|
#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_CHECK PyBytes_Check
|
||||||
#define PYBIND11_BYTES_FROM_STRING PyBytes_FromString
|
#define PYBIND11_BYTES_FROM_STRING PyBytes_FromString
|
||||||
#define PYBIND11_BYTES_FROM_STRING_AND_SIZE PyBytes_FromStringAndSize
|
#define PYBIND11_BYTES_FROM_STRING_AND_SIZE PyBytes_FromStringAndSize
|
||||||
@ -89,6 +90,7 @@
|
|||||||
#define PYBIND11_PLUGIN_IMPL(name) \
|
#define PYBIND11_PLUGIN_IMPL(name) \
|
||||||
extern "C" PYBIND11_EXPORT PyObject *PyInit_##name()
|
extern "C" PYBIND11_EXPORT PyObject *PyInit_##name()
|
||||||
#else
|
#else
|
||||||
|
#define PYBIND11_INSTANCE_METHOD_NEW(ptr, class_) PyMethod_New(ptr, nullptr, class_)
|
||||||
#define PYBIND11_BYTES_CHECK PyString_Check
|
#define PYBIND11_BYTES_CHECK PyString_Check
|
||||||
#define PYBIND11_BYTES_FROM_STRING PyString_FromString
|
#define PYBIND11_BYTES_FROM_STRING PyString_FromString
|
||||||
#define PYBIND11_BYTES_FROM_STRING_AND_SIZE PyString_FromStringAndSize
|
#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;
|
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 {
|
struct overload_hash {
|
||||||
inline std::size_t operator()(const std::pair<const PyObject *, const char *>& v) const {
|
inline std::size_t operator()(const std::pair<const PyObject *, const char *>& v) const {
|
||||||
size_t value = std::hash<const void *>()(v.first);
|
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
|
/// Internal data struture used to track registered instances and types
|
||||||
struct internals {
|
struct internals {
|
||||||
std::unordered_map<const void *, void*> registered_types_cpp; // std::type_info* -> type_info
|
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)
|
NAMESPACE_BEGIN(detail)
|
||||||
template <typename T> class type_caster<std::complex<T>> {
|
template <typename T> class type_caster<std::complex<T>> {
|
||||||
public:
|
public:
|
||||||
bool load(PyObject *src, bool) {
|
bool load(handle src, bool) {
|
||||||
Py_complex result = PyComplex_AsCComplex(src);
|
Py_complex result = PyComplex_AsCComplex(src.ptr());
|
||||||
if (result.real == -1.0 && PyErr_Occurred()) {
|
if (result.real == -1.0 && PyErr_Occurred()) {
|
||||||
PyErr_Clear();
|
PyErr_Clear();
|
||||||
return false;
|
return false;
|
||||||
@ -30,7 +30,7 @@ public:
|
|||||||
return true;
|
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());
|
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...)>> {
|
template <typename Return, typename... Args> struct type_caster<std::function<Return(Args...)>> {
|
||||||
typedef std::function<Return(Args...)> type;
|
typedef std::function<Return(Args...)> type;
|
||||||
public:
|
public:
|
||||||
|
bool load(handle src_, bool) {
|
||||||
bool load(PyObject *src_, bool) {
|
|
||||||
src_ = detail::get_function(src_);
|
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;
|
return false;
|
||||||
object src(src_, true);
|
object src(src_, true);
|
||||||
value = [src](Args... args) -> Return {
|
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 */
|
/* Visual studio 2015 parser issue: need parentheses around this expression */
|
||||||
return (retval.template cast<Return>());
|
return (retval.template cast<Return>());
|
||||||
};
|
};
|
||||||
@ -33,10 +32,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename Func>
|
template <typename Func>
|
||||||
static PyObject *cast(Func &&f_, return_value_policy policy, PyObject *) {
|
static handle cast(Func &&f_, return_value_policy policy, handle /* parent */) {
|
||||||
cpp_function f(std::forward<Func>(f_), policy);
|
return cpp_function(std::forward<Func>(f_), policy).release();
|
||||||
f.inc_ref();
|
|
||||||
return f.ptr();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PYBIND11_TYPE_CASTER(type, _("function<") +
|
PYBIND11_TYPE_CASTER(type, _("function<") +
|
||||||
|
@ -79,36 +79,36 @@ public:
|
|||||||
API& api = lookup_api();
|
API& api = lookup_api();
|
||||||
PyObject *descr = api.PyArray_DescrFromType_(npy_format_descriptor<Type>::value);
|
PyObject *descr = api.PyArray_DescrFromType_(npy_format_descriptor<Type>::value);
|
||||||
if (descr == nullptr)
|
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;
|
Py_intptr_t shape = (Py_intptr_t) size;
|
||||||
object tmp = object(api.PyArray_NewFromDescr_(
|
object tmp = object(api.PyArray_NewFromDescr_(
|
||||||
api.PyArray_Type_, descr, 1, &shape, nullptr, (void *) ptr, 0, nullptr), false);
|
api.PyArray_Type_, descr, 1, &shape, nullptr, (void *) ptr, 0, nullptr), false);
|
||||||
if (ptr && tmp)
|
if (ptr && tmp)
|
||||||
tmp = object(api.PyArray_NewCopy_(tmp.ptr(), -1 /* any order */), false);
|
tmp = object(api.PyArray_NewCopy_(tmp.ptr(), -1 /* any order */), false);
|
||||||
if (!tmp)
|
if (!tmp)
|
||||||
throw std::runtime_error("NumPy: unable to create array!");
|
pybind11_fail("NumPy: unable to create array!");
|
||||||
m_ptr = tmp.release();
|
m_ptr = tmp.release().ptr();
|
||||||
}
|
}
|
||||||
|
|
||||||
array(const buffer_info &info) {
|
array(const buffer_info &info) {
|
||||||
API& api = lookup_api();
|
API& api = lookup_api();
|
||||||
if ((info.format.size() < 1) || (info.format.size() > 2))
|
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];
|
int fmt = (int) info.format[0];
|
||||||
if (info.format == "Zd") fmt = API::NPY_CDOUBLE_;
|
if (info.format == "Zd") fmt = API::NPY_CDOUBLE_;
|
||||||
else if (info.format == "Zf") fmt = API::NPY_CFLOAT_;
|
else if (info.format == "Zf") fmt = API::NPY_CFLOAT_;
|
||||||
|
|
||||||
PyObject *descr = api.PyArray_DescrFromType_(fmt);
|
PyObject *descr = api.PyArray_DescrFromType_(fmt);
|
||||||
if (descr == nullptr)
|
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_(
|
object tmp(api.PyArray_NewFromDescr_(
|
||||||
api.PyArray_Type_, descr, info.ndim, (Py_intptr_t *) &info.shape[0],
|
api.PyArray_Type_, descr, info.ndim, (Py_intptr_t *) &info.shape[0],
|
||||||
(Py_intptr_t *) &info.strides[0], info.ptr, 0, nullptr), false);
|
(Py_intptr_t *) &info.strides[0], info.ptr, 0, nullptr), false);
|
||||||
if (info.ptr && tmp)
|
if (info.ptr && tmp)
|
||||||
tmp = object(api.PyArray_NewCopy_(tmp.ptr(), -1 /* any order */), false);
|
tmp = object(api.PyArray_NewCopy_(tmp.ptr(), -1 /* any order */), false);
|
||||||
if (!tmp)
|
if (!tmp)
|
||||||
throw std::runtime_error("NumPy: unable to create array!");
|
pybind11_fail("NumPy: unable to create array!");
|
||||||
m_ptr = tmp.release();
|
m_ptr = tmp.release().ptr();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -186,7 +186,7 @@ struct vectorize_helper {
|
|||||||
/* Check if the parameters are actually compatible */
|
/* Check if the parameters are actually compatible */
|
||||||
for (size_t i=0; i<N; ++i)
|
for (size_t i=0; i<N; ++i)
|
||||||
if (buffers[i].size != 1 && (buffers[i].ndim != ndim || buffers[i].shape != shape))
|
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)
|
if (size == 1)
|
||||||
return cast(f(*((Args *) buffers[Index].ptr)...));
|
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
|
/// 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, 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<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, 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<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, 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(const handle &other) : m_ptr(other.m_ptr) { }
|
||||||
handle(PyObject *ptr) : m_ptr(ptr) { }
|
handle(PyObject *ptr) : m_ptr(ptr) { }
|
||||||
PyObject *ptr() const { return m_ptr; }
|
PyObject *ptr() const { return m_ptr; }
|
||||||
void inc_ref() const { Py_XINCREF(m_ptr); }
|
PyObject *&ptr() { return m_ptr; }
|
||||||
void dec_ref() const { Py_XDECREF(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); }
|
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 begin() const;
|
||||||
inline iterator end() const;
|
inline iterator end() const;
|
||||||
inline detail::accessor operator[](handle key) const;
|
inline detail::accessor operator[](handle key) const;
|
||||||
@ -44,6 +45,8 @@ public:
|
|||||||
template <typename T> T cast() const;
|
template <typename T> T cast() const;
|
||||||
template <typename ... Args> object call(Args&&... args_) const;
|
template <typename ... Args> object call(Args&&... args_) const;
|
||||||
operator bool() const { return m_ptr != nullptr; }
|
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; }
|
bool check() const { return m_ptr != nullptr; }
|
||||||
protected:
|
protected:
|
||||||
PyObject *m_ptr;
|
PyObject *m_ptr;
|
||||||
@ -59,25 +62,25 @@ public:
|
|||||||
object(object &&other) { m_ptr = other.m_ptr; other.m_ptr = nullptr; }
|
object(object &&other) { m_ptr = other.m_ptr; other.m_ptr = nullptr; }
|
||||||
~object() { dec_ref(); }
|
~object() { dec_ref(); }
|
||||||
|
|
||||||
PyObject * release() {
|
handle release() {
|
||||||
PyObject *tmp = m_ptr;
|
PyObject *tmp = m_ptr;
|
||||||
m_ptr = nullptr;
|
m_ptr = nullptr;
|
||||||
return tmp;
|
return handle(tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
object& operator=(object &other) {
|
object& operator=(object &other) {
|
||||||
Py_XINCREF(other.m_ptr);
|
other.inc_ref();
|
||||||
Py_XDECREF(m_ptr);
|
dec_ref();
|
||||||
m_ptr = other.m_ptr;
|
m_ptr = other.m_ptr;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
object& operator=(object &&other) {
|
object& operator=(object &&other) {
|
||||||
if (this != &other) {
|
if (this != &other) {
|
||||||
PyObject *temp = m_ptr;
|
handle temp(m_ptr);
|
||||||
m_ptr = other.m_ptr;
|
m_ptr = other.m_ptr;
|
||||||
other.m_ptr = nullptr;
|
other.m_ptr = nullptr;
|
||||||
Py_XDECREF(temp);
|
temp.dec_ref();
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@ -85,7 +88,7 @@ public:
|
|||||||
|
|
||||||
class iterator : public object {
|
class iterator : public object {
|
||||||
public:
|
public:
|
||||||
iterator(PyObject *obj, bool borrowed = false) : object(obj, borrowed) { ++*this; }
|
iterator(handle obj, bool borrowed = false) : object(obj, borrowed) { ++*this; }
|
||||||
iterator& operator++() {
|
iterator& operator++() {
|
||||||
if (ptr())
|
if (ptr())
|
||||||
value = object(PyIter_Next(m_ptr), false);
|
value = object(PyIter_Next(m_ptr), false);
|
||||||
@ -100,108 +103,106 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
NAMESPACE_BEGIN(detail)
|
NAMESPACE_BEGIN(detail)
|
||||||
inline PyObject *get_function(PyObject *value) {
|
inline handle get_function(handle value) {
|
||||||
if (value == nullptr)
|
if (value) {
|
||||||
return nullptr;
|
|
||||||
#if PY_MAJOR_VERSION >= 3
|
#if PY_MAJOR_VERSION >= 3
|
||||||
if (PyInstanceMethod_Check(value))
|
if (PyInstanceMethod_Check(value.ptr()))
|
||||||
value = PyInstanceMethod_GET_FUNCTION(value);
|
value = PyInstanceMethod_GET_FUNCTION(value.ptr());
|
||||||
#endif
|
#endif
|
||||||
if (PyMethod_Check(value))
|
if (PyMethod_Check(value.ptr()))
|
||||||
value = PyMethod_GET_FUNCTION(value);
|
value = PyMethod_GET_FUNCTION(value.ptr());
|
||||||
|
}
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
class accessor {
|
class accessor {
|
||||||
public:
|
public:
|
||||||
accessor(PyObject *obj, PyObject *key, bool attr)
|
accessor(handle obj, handle key, bool attr)
|
||||||
: obj(obj), key(key), attr(attr) { Py_INCREF(key); }
|
: obj(obj), key(key, true), attr(attr) { }
|
||||||
accessor(PyObject *obj, const char *key, bool attr)
|
accessor(handle obj, const char *key, bool attr)
|
||||||
: obj(obj), key(PyUnicode_FromString(key)), attr(attr) { }
|
: obj(obj), key(PyUnicode_FromString(key), false), attr(attr) { }
|
||||||
accessor(const accessor &a) : obj(a.obj), key(a.key), attr(a.attr)
|
accessor(const accessor &a) : obj(a.obj), key(a.key), attr(a.attr) { }
|
||||||
{ Py_INCREF(key); }
|
|
||||||
~accessor() { Py_DECREF(key); }
|
|
||||||
|
|
||||||
void operator=(accessor o) { operator=(object(o)); }
|
void operator=(accessor o) { operator=(object(o)); }
|
||||||
|
|
||||||
void operator=(const handle &h) {
|
void operator=(const handle &value) {
|
||||||
if (attr) {
|
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");
|
pybind11_fail("Unable to set object attribute");
|
||||||
} else {
|
} 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");
|
pybind11_fail("Unable to set object item");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
operator object() const {
|
operator object() const {
|
||||||
object result(attr ? PyObject_GetAttr(obj, key)
|
object result(attr ? PyObject_GetAttr(obj.ptr(), key.ptr())
|
||||||
: PyObject_GetItem(obj, key), false);
|
: PyObject_GetItem(obj.ptr(), key.ptr()), false);
|
||||||
if (!result) PyErr_Clear();
|
if (!result) {PyErr_Clear(); }
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
operator bool() const {
|
operator bool() const {
|
||||||
if (attr) {
|
if (attr) {
|
||||||
return (bool) PyObject_HasAttr(obj, key);
|
return (bool) PyObject_HasAttr(obj.ptr(), key.ptr());
|
||||||
} else {
|
} else {
|
||||||
object result(PyObject_GetItem(obj, key), false);
|
object result(PyObject_GetItem(obj.ptr(), key.ptr()), false);
|
||||||
if (!result) PyErr_Clear();
|
if (!result) PyErr_Clear();
|
||||||
return (bool) result;
|
return (bool) result;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PyObject *obj;
|
handle obj;
|
||||||
PyObject *key;
|
object key;
|
||||||
bool attr;
|
bool attr;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct list_accessor {
|
struct list_accessor {
|
||||||
public:
|
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=(list_accessor o) { return operator=(object(o)); }
|
||||||
void operator=(const handle &o) {
|
void operator=(const handle &o) {
|
||||||
o.inc_ref(); // PyList_SetItem steals a reference
|
// PyList_SetItem steals a reference to 'o'
|
||||||
if (PyList_SetItem(list, (ssize_t) index, (PyObject *) o.ptr()) < 0)
|
if (PyList_SetItem(list.ptr(), (ssize_t) index, o.inc_ref().ptr()) < 0)
|
||||||
pybind11_fail("Unable to assign value in Python list!");
|
pybind11_fail("Unable to assign value in Python list!");
|
||||||
}
|
}
|
||||||
operator object() const {
|
operator object() const {
|
||||||
PyObject *result = PyList_GetItem(list, (ssize_t) index);
|
PyObject *result = PyList_GetItem(list.ptr(), (ssize_t) index);
|
||||||
if (!result)
|
if (!result)
|
||||||
pybind11_fail("Unable to retrieve value from Python list!");
|
pybind11_fail("Unable to retrieve value from Python list!");
|
||||||
return object(result, true);
|
return object(result, true);
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
PyObject *list;
|
handle list;
|
||||||
size_t index;
|
size_t index;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct tuple_accessor {
|
struct tuple_accessor {
|
||||||
public:
|
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=(tuple_accessor o) { return operator=(object(o)); }
|
||||||
void operator=(const handle &o) {
|
void operator=(const handle &o) {
|
||||||
o.inc_ref(); // PyTuple_SetItem steals a reference
|
// PyTuple_SetItem steals a referenceto 'o'
|
||||||
if (PyTuple_SetItem(tuple, (ssize_t) index, (PyObject *) o.ptr()) < 0)
|
if (PyTuple_SetItem(tuple.ptr(), (ssize_t) index, o.inc_ref().ptr()) < 0)
|
||||||
pybind11_fail("Unable to assign value in Python tuple!");
|
pybind11_fail("Unable to assign value in Python tuple!");
|
||||||
}
|
}
|
||||||
operator object() const {
|
operator object() const {
|
||||||
PyObject *result = PyTuple_GetItem(tuple, (ssize_t) index);
|
PyObject *result = PyTuple_GetItem(tuple.ptr(), (ssize_t) index);
|
||||||
if (!result)
|
if (!result)
|
||||||
pybind11_fail("Unable to retrieve value from Python tuple!");
|
pybind11_fail("Unable to retrieve value from Python tuple!");
|
||||||
return object(result, true);
|
return object(result, true);
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
PyObject *tuple;
|
handle tuple;
|
||||||
size_t index;
|
size_t index;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct dict_iterator {
|
struct dict_iterator {
|
||||||
public:
|
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++() {
|
dict_iterator& operator++() {
|
||||||
if (!PyDict_Next(dict, &pos, &key, &value))
|
if (!PyDict_Next(dict.ptr(), &pos, &key.ptr(), &value.ptr()))
|
||||||
pos = -1;
|
pos = -1;
|
||||||
return *this;
|
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; }
|
||||||
bool operator!=(const dict_iterator &it) const { return it.pos != pos; }
|
bool operator!=(const dict_iterator &it) const { return it.pos != pos; }
|
||||||
private:
|
private:
|
||||||
PyObject *dict, *key, *value;
|
handle dict, key, value;
|
||||||
ssize_t pos = 0;
|
ssize_t pos = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -410,8 +411,8 @@ public:
|
|||||||
if (!m_ptr) pybind11_fail("Could not allocate list object!");
|
if (!m_ptr) pybind11_fail("Could not allocate list object!");
|
||||||
}
|
}
|
||||||
size_t size() const { return (size_t) PyList_Size(m_ptr); }
|
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); }
|
detail::list_accessor operator[](size_t index) const { return detail::list_accessor(*this, index); }
|
||||||
void append(const object &object) const { PyList_Append(m_ptr, (PyObject *) object.ptr()); }
|
void append(const object &object) const { PyList_Append(m_ptr, object.ptr()); }
|
||||||
};
|
};
|
||||||
|
|
||||||
class set : public object {
|
class set : public object {
|
||||||
@ -421,7 +422,7 @@ public:
|
|||||||
if (!m_ptr) pybind11_fail("Could not allocate set object!");
|
if (!m_ptr) pybind11_fail("Could not allocate set object!");
|
||||||
}
|
}
|
||||||
size_t size() const { return (size_t) PySet_Size(m_ptr); }
|
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); }
|
void clear() const { PySet_Clear(m_ptr); }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -429,8 +430,8 @@ class function : public object {
|
|||||||
public:
|
public:
|
||||||
PYBIND11_OBJECT_DEFAULT(function, object, PyFunction_Check)
|
PYBIND11_OBJECT_DEFAULT(function, object, PyFunction_Check)
|
||||||
bool is_cpp_function() const {
|
bool is_cpp_function() const {
|
||||||
PyObject *ptr = detail::get_function(m_ptr);
|
handle fun = detail::get_function(m_ptr);
|
||||||
return ptr != nullptr && PyCFunction_Check(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)
|
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 std::vector<Value, Alloc> type;
|
||||||
typedef type_caster<Value> value_conv;
|
typedef type_caster<Value> value_conv;
|
||||||
public:
|
public:
|
||||||
bool load(PyObject *src, bool convert) {
|
bool load(handle src, bool convert) {
|
||||||
list l(src, true);
|
list l(src, true);
|
||||||
if (!l.check())
|
if (!l.check())
|
||||||
return false;
|
return false;
|
||||||
@ -34,21 +34,21 @@ public:
|
|||||||
value.clear();
|
value.clear();
|
||||||
value_conv conv;
|
value_conv conv;
|
||||||
for (auto it : l) {
|
for (auto it : l) {
|
||||||
if (!conv.load(it.ptr(), convert))
|
if (!conv.load(it, convert))
|
||||||
return false;
|
return false;
|
||||||
value.push_back((Value) conv);
|
value.push_back((Value) conv);
|
||||||
}
|
}
|
||||||
return true;
|
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());
|
list l(src.size());
|
||||||
size_t index = 0;
|
size_t index = 0;
|
||||||
for (auto const &value: src) {
|
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_)
|
if (!value_)
|
||||||
return nullptr;
|
return handle();
|
||||||
PyList_SET_ITEM(l.ptr(), index++, value_.release()); // steals a reference
|
PyList_SET_ITEM(l.ptr(), index++, value_.release().ptr()); // steals a reference
|
||||||
}
|
}
|
||||||
return l.release();
|
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 std::set<Key, Compare, Alloc> type;
|
||||||
typedef type_caster<Key> key_conv;
|
typedef type_caster<Key> key_conv;
|
||||||
public:
|
public:
|
||||||
bool load(PyObject *src, bool convert) {
|
bool load(handle src, bool convert) {
|
||||||
pybind11::set s(src, true);
|
pybind11::set s(src, true);
|
||||||
if (!s.check())
|
if (!s.check())
|
||||||
return false;
|
return false;
|
||||||
value.clear();
|
value.clear();
|
||||||
key_conv conv;
|
key_conv conv;
|
||||||
for (auto entry : s) {
|
for (auto entry : s) {
|
||||||
if (!conv.load(entry.ptr(), convert))
|
if (!conv.load(entry, convert))
|
||||||
return false;
|
return false;
|
||||||
value.insert((Key) conv);
|
value.insert((Key) conv);
|
||||||
}
|
}
|
||||||
return true;
|
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;
|
pybind11::set s;
|
||||||
for (auto const &value: src) {
|
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))
|
if (!value_ || !s.add(value))
|
||||||
return nullptr;
|
return handle();
|
||||||
}
|
}
|
||||||
return s.release();
|
return s.release();
|
||||||
}
|
}
|
||||||
@ -91,7 +91,7 @@ public:
|
|||||||
typedef type_caster<Key> key_conv;
|
typedef type_caster<Key> key_conv;
|
||||||
typedef type_caster<Value> value_conv;
|
typedef type_caster<Value> value_conv;
|
||||||
|
|
||||||
bool load(PyObject *src, bool convert) {
|
bool load(handle src, bool convert) {
|
||||||
dict d(src, true);
|
dict d(src, true);
|
||||||
if (!d.check())
|
if (!d.check())
|
||||||
return false;
|
return false;
|
||||||
@ -107,13 +107,13 @@ public:
|
|||||||
return true;
|
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;
|
dict d;
|
||||||
for (auto const &kv: src) {
|
for (auto const &kv: src) {
|
||||||
object key(key_conv::cast(kv.first, policy, parent), false);
|
object key = object(key_conv::cast(kv.first, policy, parent), false);
|
||||||
object value(value_conv::cast(kv.second, policy, parent), false);
|
object value = object(value_conv::cast(kv.second, policy, parent), false);
|
||||||
if (!key || !value)
|
if (!key || !value)
|
||||||
return nullptr;
|
return handle();
|
||||||
d[key] = value;
|
d[key] = value;
|
||||||
}
|
}
|
||||||
return d.release();
|
return d.release();
|
||||||
|
15
setup.py
15
setup.py
@ -15,6 +15,7 @@ setup(
|
|||||||
packages=[],
|
packages=[],
|
||||||
license='BSD',
|
license='BSD',
|
||||||
headers=[
|
headers=[
|
||||||
|
'include/pybind11/attr.h',
|
||||||
'include/pybind11/cast.h',
|
'include/pybind11/cast.h',
|
||||||
'include/pybind11/complex.h',
|
'include/pybind11/complex.h',
|
||||||
'include/pybind11/descr.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.
|
become an excessively large and unnecessary dependency.
|
||||||
|
|
||||||
Think of this library as a tiny self-contained version of Boost.Python with
|
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
|
everything stripped away that isn't relevant for binding generation. Without
|
||||||
header files only require ~2.5K lines of code and depend on Python (2.7 or 3.x)
|
comments, the core header files only require ~2.5K lines of code and depend on
|
||||||
and the C++ standard library. This compact implementation was possible thanks
|
Python (2.7 or 3.x) and the C++ standard library. This compact implementation
|
||||||
to some of the new C++11 language features (specifically: tuples, lambda
|
was possible thanks to some of the new C++11 language features (specifically:
|
||||||
functions and variadic templates). Since its creation, this library has grown
|
tuples, lambda functions and variadic templates). Since its creation, this
|
||||||
beyond Boost.Python in many ways, leading to dramatically simpler binding code
|
library has grown beyond Boost.Python in many ways, leading to dramatically
|
||||||
in many common situations.""")
|
simpler binding code in many common situations.""")
|
||||||
|
Loading…
Reference in New Issue
Block a user