Commit 38bd7113 authored by Wenzel Jakob's avatar Wenzel Jakob
Browse files

Initial commit

parents
Polly is a parrot
Molly is a dog
Woof!
Constructing Example5..
In Example5::callback()
Polly is a parrot
Molly is a dog
The following error is expected: Incompatible function arguments. The following argument types are supported:
1. dog_bark(Dog) -> None
Callback function 1 called!
False
Callback function 2 called : Hello, True, 5
5
got callback: 3 4
Destructing Example5..
/*
example/example6.cpp -- Example 6: supporting Pythons' sequence
protocol, iterators, etc.
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.
*/
#include "example.h"
#include <pybind/operators.h>
class Sequence {
public:
Sequence(size_t size) : m_size(size) {
std::cout << "Value constructor: Creating a sequence with " << m_size << " entries" << std::endl;
m_data = new float[size];
memset(m_data, 0, sizeof(float) * size);
}
Sequence(const std::vector<float> &value) : m_size(value.size()) {
std::cout << "Value constructor: Creating a sequence with " << m_size << " entries" << std::endl;
m_data = new float[m_size];
memcpy(m_data, &value[0], sizeof(float) * m_size);
}
Sequence(const Sequence &s) : m_size(s.m_size) {
std::cout << "Copy constructor: Creating a sequence with " << m_size << " entries" << std::endl;
m_data = new float[m_size];
memcpy(m_data, s.m_data, sizeof(float)*m_size);
}
Sequence(Sequence &&s) : m_size(s.m_size), m_data(s.m_data) {
std::cout << "Move constructor: Creating a sequence with " << m_size << " entries" << std::endl;
s.m_size = 0;
s.m_data = nullptr;
}
~Sequence() {
std::cout << "Freeing a sequence with " << m_size << " entries" << std::endl;
delete[] m_data;
}
Sequence &operator=(const Sequence &s) {
std::cout << "Assignment operator: Creating a sequence with " << s.m_size << " entries" << std::endl;
delete[] m_data;
m_size = s.m_size;
m_data = new float[m_size];
memcpy(m_data, s.m_data, sizeof(float)*m_size);
return *this;
}
Sequence &operator=(Sequence &&s) {
std::cout << "Move assignment operator: Creating a sequence with " << s.m_size << " entries" << std::endl;
if (&s != this) {
delete[] m_data;
m_size = s.m_size;
m_data = s.m_data;
s.m_size = 0;
s.m_data = nullptr;
}
return *this;
}
bool operator==(const Sequence &s) const {
if (m_size != s.size())
return false;
for (size_t i=0; i<m_size; ++i)
if (m_data[i] != s[i])
return false;
return true;
}
bool operator!=(const Sequence &s) const {
return !operator==(s);
}
float operator[](size_t index) const {
return m_data[index];
}
float &operator[](size_t index) {
return m_data[index];
}
bool contains(float v) const {
for (size_t i=0; i<m_size; ++i)
if (v == m_data[i])
return true;
return false;
}
Sequence reversed() const {
Sequence result(m_size);
for (size_t i=0; i<m_size; ++i)
result[m_size-i-1] = m_data[i];
return result;
}
size_t size() const { return m_size; }
private:
size_t m_size;
float *m_data;
};
namespace {
// Special iterator data structure for python
struct PySequenceIterator {
PySequenceIterator(const Sequence &seq, py::object ref) : seq(seq), ref(ref) { }
float next() {
if (index == seq.size())
throw py::stop_iteration();
return seq[index++];
}
const Sequence &seq;
py::object ref; // keep a reference
size_t index = 0;
};
};
void init_ex6(py::module &m) {
py::class_<Sequence> seq(m, "Sequence");
seq.def(py::init<size_t>())
.def(py::init<const std::vector<float>&>())
/// Bare bones interface
.def("__getitem__", [](const Sequence &s, size_t i) {
if (i >= s.size())
throw py::index_error();
return s[i];
})
.def("__setitem__", [](Sequence &s, size_t i, float v) {
if (i >= s.size())
throw py::index_error();
s[i] = v;
})
.def("__len__", &Sequence::size)
/// Optional sequence protocol operations
.def("__iter__", [](py::object s) { return PySequenceIterator(s.cast<const Sequence &>(), s); })
.def("__contains__", [](const Sequence &s, float v) { return s.contains(v); })
.def("__reversed__", [](const Sequence &s) -> Sequence { return s.reversed(); })
/// Slicing protocol (optional)
.def("__getitem__", [](const Sequence &s, py::slice slice) -> Sequence* {
py::ssize_t start, stop, step, slicelength;
if (!slice.compute(s.size(), &start, &stop, &step, &slicelength))
throw py::error_already_set();
Sequence *seq = new Sequence(slicelength);
for (int i=0; i<slicelength; ++i) {
(*seq)[i] = s[start]; start += step;
}
return seq;
})
.def("__setitem__", [](Sequence &s, py::slice slice, const Sequence &value) {
py::ssize_t start, stop, step, slicelength;
if (!slice.compute(s.size(), &start, &stop, &step, &slicelength))
throw py::error_already_set();
if ((size_t) slicelength != value.size())
throw std::runtime_error("Left and right hand size of slice assignment have different sizes!");
for (int i=0; i<slicelength; ++i) {
s[start] = value[i]; start += step;
}
})
/// Comparisons
.def(py::self == py::self)
.def(py::self != py::self);
// Could also define py::self + py::self for concatenation, etc.
py::class_<PySequenceIterator>(seq, "Iterator")
.def("__iter__", [](PySequenceIterator &it) -> PySequenceIterator& { return it; })
.def("__next__", &PySequenceIterator::next);
}
#!/usr/bin/env python3
import sys
sys.path.append('.')
from example import Sequence
s = Sequence(5)
print("s = " + str(s))
print("len(s) = " + str(len(s)))
print("s[0], s[3] = %f %f" % (s[0], s[3]))
print('12.34 in s: ' + str(12.34 in s))
s[0], s[3] = 12.34, 56.78
print('12.34 in s: ' + str(12.34 in s))
print("s[0], s[3] = %f %f" % (s[0], s[3]))
rev = reversed(s)
rev2 = s[::-1]
print("rev[0], rev[1], rev[2], rev[3], rev[4] = %f %f %f %f %f" % (rev[0], rev[1], rev[2], rev[3], rev[4]))
for i in rev:
print(i, end=' ')
print('')
for i in rev2:
print(i, end=' ')
print('')
print(rev == rev2)
rev[0::2] = Sequence([2.0, 2.0, 2.0])
for i in rev:
print(i, end=' ')
print('')
Value constructor: Creating a sequence with 5 entries
Value constructor: Creating a sequence with 5 entries
Copy constructor: Creating a sequence with 5 entries
Freeing a sequence with 5 entries
s = <example.Sequence object at 0x100380fb0>
len(s) = 5
s[0], s[3] = 0.000000 0.000000
12.34 in s: False
12.34 in s: True
s[0], s[3] = 12.340000 56.779999
rev[0], rev[1], rev[2], rev[3], rev[4] = 0.000000 56.779999 0.000000 0.000000 12.340000
12.34000015258789
0.0
0.0
56.779998779296875
0.0
Freeing a sequence with 5 entries
Freeing a sequence with 5 entries
/*
example/example7.cpp -- Example 7: supporting Pythons' buffer protocol
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.
*/
#include "example.h"
class Matrix {
public:
Matrix(size_t rows, size_t cols) : m_rows(rows), m_cols(cols) {
std::cout << "Value constructor: Creating a " << rows << "x" << cols << " matrix " << std::endl;
m_data = new float[rows*cols];
memset(m_data, 0, sizeof(float) * rows * cols);
}
Matrix(const Matrix &s) : m_rows(s.m_rows), m_cols(s.m_cols) {
std::cout << "Copy constructor: Creating a " << m_rows << "x" << m_cols << " matrix " << std::endl;
m_data = new float[m_rows * m_cols];
memcpy(m_data, s.m_data, sizeof(float) * m_rows * m_cols);
}
Matrix(Matrix &&s) : m_rows(s.m_rows), m_cols(s.m_cols), m_data(s.m_data) {
std::cout << "Move constructor: Creating a " << m_rows << "x" << m_cols << " matrix " << std::endl;
s.m_rows = 0;
s.m_cols = 0;
s.m_data = nullptr;
}
~Matrix() {
std::cout << "Freeing a " << m_rows << "x" << m_cols << " matrix " << std::endl;
delete[] m_data;
}
Matrix &operator=(const Matrix &s) {
std::cout << "Assignment operator : Creating a " << s.m_rows << "x" << s.m_cols << " matrix " << std::endl;
delete[] m_data;
m_rows = s.m_rows;
m_cols = s.m_cols;
m_data = new float[m_rows * m_cols];
memcpy(m_data, s.m_data, sizeof(float) * m_rows * m_cols);
return *this;
}
Matrix &operator=(Matrix &&s) {
std::cout << "Move assignment operator : Creating a " << s.m_rows << "x" << s.m_cols << " matrix " << std::endl;
if (&s != this) {
delete[] m_data;
m_rows = s.m_rows; m_cols = s.m_cols; m_data = s.m_data;
s.m_rows = 0; s.m_cols = 0; s.m_data = nullptr;
}
return *this;
}
float operator()(size_t i, size_t j) const {
return m_data[i*m_cols + j];
}
float &operator()(size_t i, size_t j) {
return m_data[i*m_cols + j];
}
float *data() { return m_data; }
size_t rows() const { return m_rows; }
size_t cols() const { return m_cols; }
private:
size_t m_rows;
size_t m_cols;
float *m_data;
};
void init_ex7(py::module &m) {
py::class_<Matrix> mtx(m, "Matrix");
mtx.def(py::init<size_t, size_t>())
/// Construct from a buffer
.def("__init__", [](Matrix &v, py::buffer b) {
py::buffer_info info = b.request();
if (info.format != py::format_descriptor<float>::value() || info.ndim != 2)
throw std::runtime_error("Incompatible buffer format!");
new (&v) Matrix(info.shape[0], info.shape[1]);
memcpy(v.data(), info.ptr, sizeof(float) * v.rows() * v.cols());
})
.def("rows", &Matrix::rows)
.def("cols", &Matrix::cols)
/// Bare bones interface
.def("__getitem__", [](const Matrix &m, std::pair<size_t, size_t> i) {
if (i.first >= m.rows() || i.second >= m.cols())
throw py::index_error();
return m(i.first, i.second);
})
.def("__setitem__", [](Matrix &m, std::pair<size_t, size_t> i, float v) {
if (i.first >= m.rows() || i.second >= m.cols())
throw py::index_error();
m(i.first, i.second) = v;
})
/// Provide buffer access
.def_buffer([](Matrix &m) -> py::buffer_info {
return py::buffer_info(
m.data(), /* Pointer to buffer */
sizeof(float), /* Size of one scalar */
py::format_descriptor<float>::value(), /* Python struct-style format descriptor */
2, /* Number of dimensions */
{ m.rows(), m.cols() }, /* Buffer dimensions */
{ sizeof(float) * m.rows(), /* Strides (in bytes) for each index */
sizeof(float) }
);
});
}
#!/usr/bin/env python3
import sys
sys.path.append('.')
from example import Matrix
import numpy as np
m = Matrix(5, 5)
print(m[2, 3])
m[2, 3] = 4
print(m[2, 3])
m2 = np.array(m, copy=False)
print(m2)
print(m2[2, 3])
m2[2, 3] = 5
print(m[2, 3])
m3 = np.array([[1,2,3],[4,5,6]]).astype(np.float32)
print(m3)
m4 = Matrix(m3)
for i in range(m4.rows()):
for j in range(m4.cols()):
print(m4[i, j], end = ' ')
print()
Value constructor: Creating a 5x5 matrix
0.0
4.0
[[ 0. 0. 0. 0. 0.]
[ 0. 0. 0. 0. 0.]
[ 0. 0. 0. 4. 0.]
[ 0. 0. 0. 0. 0.]
[ 0. 0. 0. 0. 0.]]
4.0
5.0
Freeing a 5x5 matrix
/*
example/example8.cpp -- Example 8: binding classes with
custom reference counting, implicit conversions between types
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.
*/
#include "example.h"
#include "object.h"
/// Object subclass
class MyObject : public Object {
public:
MyObject(int value) : value(value) {
std::cout << toString() << " constructor" << std::endl;
}
std::string toString() const {
return "MyObject[" + std::to_string(value) + "]";
}
protected:
virtual ~MyObject() {
std::cout << toString() << " destructor" << std::endl;
}
private:
int value;
};
/// Make pybind aware of the ref-counted wrapper type
namespace pybind { namespace detail {
template <typename T> class type_caster<ref<T>>
: public type_caster_holder<T, ref<T>> { };
}}
Object *make_object_1() { return new MyObject(1); }
ref<Object> make_object_2() { return new MyObject(2); }
MyObject *make_myobject_4() { return new MyObject(4); }
ref<MyObject> make_myobject_5() { return new MyObject(5); }
void print_object_1(const Object *obj) { std::cout << obj->toString() << std::endl; }
void print_object_2(ref<Object> obj) { std::cout << obj->toString() << std::endl; }
void print_object_3(const ref<Object> &obj) { std::cout << obj->toString() << std::endl; }
void print_object_4(const ref<Object> *obj) { std::cout << (*obj)->toString() << std::endl; }
void print_myobject_1(const MyObject *obj) { std::cout << obj->toString() << std::endl; }
void print_myobject_2(ref<MyObject> obj) { std::cout << obj->toString() << std::endl; }
void print_myobject_3(const ref<MyObject> &obj) { std::cout << obj->toString() << std::endl; }
void print_myobject_4(const ref<MyObject> *obj) { std::cout << (*obj)->toString() << std::endl; }
void init_ex8(py::module &m) {
py::class_<Object, ref<Object>> obj(m, "Object");
obj.def("getRefCount", &Object::getRefCount);
py::class_<MyObject, ref<MyObject>>(m, "MyObject", obj)
.def(py::init<int>());
m.def("make_object_1", &make_object_1);
m.def("make_object_2", &make_object_2);
m.def("make_myobject_4", &make_myobject_4);
m.def("make_myobject_5", &make_myobject_5);
m.def("print_object_1", &print_object_1);
m.def("print_object_2", &print_object_2);
m.def("print_object_3", &print_object_3);
m.def("print_object_4", &print_object_4);
m.def("print_myobject_1", &print_myobject_1);
m.def("print_myobject_2", &print_myobject_2);
m.def("print_myobject_3", &print_myobject_3);
m.def("print_myobject_4", &print_myobject_4);
py::implicitly_convertible<py::int_, MyObject>();
}
#!/usr/bin/env python3
import sys
sys.path.append('.')
from example import MyObject
from example import make_object_1
from example import make_object_2
from example import make_myobject_4
from example import make_myobject_5
from example import print_object_1
from example import print_object_2
from example import print_object_3
from example import print_object_4
from example import print_myobject_1
from example import print_myobject_2
from example import print_myobject_3
from example import print_myobject_4
for o in [make_object_1(), make_object_2(), MyObject(3)]:
print("Reference count = %i" % o.getRefCount())
print_object_1(o)
print_object_2(o)
print_object_3(o)
print_object_4(o)
for o in [make_myobject_4(), make_myobject_5(), MyObject(6), 7]:
print(o)
if not isinstance(o, int):
print_object_1(o)
print_object_2(o)
print_object_3(o)
print_object_4(o)
print_myobject_1(o)
print_myobject_2(o)
print_myobject_3(o)
print_myobject_4(o)
/*
example/example9.cpp -- Example 9: nested modules
and internal references
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.
*/
#include "example.h"
void submodule_func() {
std::cout << "submodule_func()" << std::endl;
}
class A {
public:
A(int v) : v(v) { std::cout << "A constructor" << std::endl; }
~A() { std::cout << "A destructor" << std::endl; }
A(const A&) { std::cout << "A copy constructor" << std::endl; }
std::string toString() { return "A[" + std::to_string(v) + "]"; }
private:
int v;
};
class B {
public:
B() { std::cout << "B constructor" << std::endl; }
~B() { std::cout << "B destructor" << std::endl; }
B(const B&) { std::cout << "B copy constructor" << std::endl; }
A &get_a1() { return a1; }
A &get_a2() { return a2; }
A a1{1};
A a2{2};
};
void init_ex9(py::module &m) {
py::module m_sub = m.def_submodule("submodule");
m_sub.def("submodule_func", &submodule_func);
py::class_<A>(m_sub, "A")
.def(py::init<int>())
.def("__repr__", &A::toString);
py::class_<B>(m_sub, "B")
.def(py::init<>())
.def("get_a1", &B::get_a1, "Return the internal A 1", py::return_value_policy::reference_internal)
.def("get_a2", &B::get_a2, "Return the internal A 2", py::return_value_policy::reference_internal)
.def_readwrite("a1", &B::a1) // def_readonly uses an internal reference return policy by default
.def_readwrite("a2", &B::a2);
}
#!/usr/bin/env python3
import sys
sys.path.append('.')
import example
print(example.__name__)
print(example.submodule.__name__)
from example.submodule import *
submodule_func()
b = B()
print(b.get_a1())
print(b.a1)
print(b.get_a2())
print(b.a2)
b.a1 = A(42)
b.a2 = A(43)
print(b.get_a1())
print(b.a1)
print(b.get_a2())
print(b.a2)
#if !defined(__OBJECT_H)
#define __OBJECT_H
#include <atomic>
/// Reference counted object base class
class Object {
public:
/// Default constructor
Object() { }
/// Copy constructor
Object(const Object &) : m_refCount(0) {}
/// Return the current reference count
int getRefCount() const { return m_refCount; };
/// Increase the object's reference count by one
void incRef() const { ++m_refCount; }
/** \brief Decrease the reference count of
* the object and possibly deallocate it.
*
* The object will automatically be deallocated once
* the reference count reaches zero.
*/
void decRef(bool dealloc = true) const {
--m_refCount;
if (m_refCount == 0 && dealloc)
delete this;
else if (m_refCount < 0)
throw std::runtime_error("Internal error: reference count < 0!");
}
virtual std::string toString() const = 0;
protected:
/** \brief Virtual protected deconstructor.
* (Will only be called by \ref ref)
*/
virtual ~Object() { }
private:
mutable std::atomic<int> m_refCount { 0 };
};
/**
* \brief Reference counting helper
*
* The \a ref refeference template is a simple wrapper to store a
* pointer to an object. It takes care of increasing and decreasing
* the reference count of the object. When the last reference goes
* out of scope, the associated object will be deallocated.
*
* \ingroup libcore
*/
template <typename T> class ref {
public:
/// Create a nullptr reference
ref() : m_ptr(nullptr) { std::cout << "Created empty ref" << std::endl; }
/// Construct a reference from a pointer
ref(T *ptr) : m_ptr(ptr) {
std::cout << "Initialized ref from pointer " << ptr<< std::endl;
if (m_ptr) ((Object *) m_ptr)->incRef();
}
/// Copy constructor
ref(const ref &r) : m_ptr(r.m_ptr) {
std::cout << "Initialized ref from ref " << r.m_ptr << std::endl;
if (m_ptr)
((Object *) m_ptr)->incRef();
}
/// Move constructor
ref(ref &&r) : m_ptr(r.m_ptr) {
std::cout << "Initialized ref with move from ref " << r.m_ptr << std::endl;
r.m_ptr = nullptr;
}
/// Destroy this reference
~ref() {
std::cout << "Destructing ref " << m_ptr << std::endl;
if (m_ptr)
((Object *) m_ptr)->decRef();
}
/// Move another reference into the current one
ref& operator=(ref&& r) {
std::cout << "Move-assigning ref " << r.m_ptr << std::endl;
if (*this == r)
return *this;
if (m_ptr)
((Object *) m_ptr)->decRef();
m_ptr = r.m_ptr;
r.m_ptr = nullptr;
return *this;
}
/// Overwrite this reference with another reference
ref& operator=(const ref& r) {
std::cout << "Assigning ref " << r.m_ptr << std::endl;
if (m_ptr == r.m_ptr)
return *this;
if (m_ptr)
((Object *) m_ptr)->decRef();
m_ptr = r.m_ptr;
if (m_ptr)
((Object *) m_ptr)->incRef();
return *this;
}
/// Overwrite this reference with a pointer to another object
ref& operator=(T *ptr) {
std::cout << "Assigning ptr " << ptr << " to ref" << std::endl;
if (m_ptr == ptr)
return *this;
if (m_ptr)
((Object *) m_ptr)->decRef();
m_ptr = ptr;
if (m_ptr)
((Object *) m_ptr)->incRef();
return *this;
}
/// Compare this reference with another reference
bool operator==(const ref &r) const { return m_ptr == r.m_ptr; }
/// Compare this reference with another reference
bool operator!=(const ref &r) const { return m_ptr != r.m_ptr; }
/// Compare this reference with a pointer
bool operator==(const T* ptr) const { return m_ptr == ptr; }
/// Compare this reference with a pointer
bool operator!=(const T* ptr) const { return m_ptr != ptr; }
/// Access the object referenced by this reference
T* operator->() { return m_ptr; }
/// Access the object referenced by this reference
const T* operator->() const { return m_ptr; }
/// Return a C++ reference to the referenced object
T& operator*() { return *m_ptr; }
/// Return a const C++ reference to the referenced object
const T& operator*() const { return *m_ptr; }
/// Return a pointer to the referenced object
operator T* () { return m_ptr; }
/// Return a const pointer to the referenced object
T* get() { return m_ptr; }
/// Return a pointer to the referenced object
const T* get() const { return m_ptr; }
private:
T *m_ptr;
};
#endif /* __OBJECT_H */
import subprocess, sys, os
path = os.path.dirname(__file__)
if path != '':
os.chdir(path)
name = sys.argv[1]
output = subprocess.check_output([sys.executable, name + ".py"]).decode('utf-8')
reference = open(name + '.ref', 'r').read()
if output == reference:
print('Test "%s" succeeded.' % name)
exit(0)
else:
print('Test "%s" FAILED!' % name)
exit(-1)
/*
pybind/cast.h: Partial template specializations to cast between
C++ and Python types
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.
*/
#if !defined(__PYBIND_CAST)
#define __PYBIND_CAST
#include "pytypes.h"
#include "mpl.h"
#include "typeid.h"
#include <map>
#include <array>
NAMESPACE_BEGIN(pybind)
NAMESPACE_BEGIN(detail)
/// Generic type caster for objects stored on the heap
template <typename type> class type_caster {
public:
typedef instance<type> instance_type;
static std::string name() { return type_id<type>(); }
type_caster() {
auto const& registered_types = get_internals().registered_types;
auto it = registered_types.find(type_id<type>());
if (it != registered_types.end())
typeinfo = &it->second;
}
bool load(PyObject *src, bool convert) {
if (src == nullptr || typeinfo == nullptr)
return false;
if (PyType_IsSubtype(Py_TYPE(src), typeinfo->type)) {
value = ((instance_type *) src)->value;
return true;
}
if (convert) {
for (auto &converter : typeinfo->implicit_conversions) {
temp = object(converter(src, typeinfo->type), false);
if (load(temp.ptr(), false))
return true;
}
}
return false;
}
static PyObject *cast(const type &src, return_value_policy policy, PyObject *parent) {
if (policy == return_value_policy::automatic)
policy = return_value_policy::copy;
return cast(&src, policy, parent);
}
static PyObject *cast(const type *_src, return_value_policy policy, PyObject *parent) {
type *src = const_cast<type *>(_src);
if (src == nullptr) {
Py_INCREF(Py_None);
return Py_None;
}
// avoid an issue with internal references matching their parent's address
bool dont_cache = parent && ((instance<void> *) parent)->value == (void *) src;
auto& internals = get_internals();
auto it_instance = internals.registered_instances.find(src);
if (it_instance != internals.registered_instances.end() && !dont_cache) {
PyObject *inst = it_instance->second;
Py_INCREF(inst);
return inst;
}
auto it = internals.registered_types.find(type_id<type>());
if (it == internals.registered_types.end()) {
std::string msg = std::string("Unregistered type : ") + type_id<type>();
PyErr_SetString(PyExc_TypeError, msg.c_str());
return nullptr;
}
auto &type_info = it->second;
instance_type *inst = (instance_type *) PyType_GenericAlloc(type_info.type, 0);
inst->value = src;
inst->owned = true;
inst->parent = nullptr;
if (policy == return_value_policy::automatic)
policy = return_value_policy::take_ownership;
handle_return_value_policy<type>(inst, policy, parent);
PyObject *inst_pyobj = (PyObject *) inst;
type_info.init_holder(inst_pyobj);
if (!dont_cache)
internals.registered_instances[inst->value] = inst_pyobj;
return inst_pyobj;
}
template <class T, typename std::enable_if<std::is_copy_constructible<T>::value, int>::type = 0>
static void handle_return_value_policy(instance<T> *inst, return_value_policy policy, PyObject *parent) {
if (policy == return_value_policy::copy) {
inst->value = new T(*(inst->value));
} else if (policy == return_value_policy::reference) {
inst->owned = false;
} else if (policy == return_value_policy::reference_internal) {
inst->owned = false;
inst->parent = parent;
Py_XINCREF(parent);
}
}
template <class T, typename std::enable_if<!std::is_copy_constructible<T>::value, int>::type = 0>
static void handle_return_value_policy(instance<T> *inst, return_value_policy policy, PyObject *parent) {
if (policy == return_value_policy::copy) {
throw cast_error("return_value_policy = copy, but the object is non-copyable!");
} else if (policy == return_value_policy::reference) {
inst->owned = false;
} else if (policy == return_value_policy::reference_internal) {
inst->owned = false;
inst->parent = parent;
Py_XINCREF(parent);
}
}
operator type*() { return value; }
operator type&() { return *value; }
protected:
type *value = nullptr;
const type_info *typeinfo = nullptr;
object temp;
};
#define TYPE_CASTER(type, py_name) \
protected: \
type value; \
public: \
static std::string name() { return py_name; } \
static PyObject *cast(const type *src, return_value_policy policy, PyObject *parent) { \
return cast(*src, policy, parent); \
} \
operator type*() { return &value; } \
operator type&() { return value; } \
#define TYPE_CASTER_NUMBER(type, py_type, from_type, to_pytype) \
template <> class type_caster<type> { \
public: \
bool load(PyObject *src, bool) { \
value = (type) from_type(src); \
if (value == (type) -1 && PyErr_Occurred()) { \
PyErr_Clear(); \
return false; \
} \
return true; \
} \
static PyObject *cast(type src, return_value_policy /* policy */, PyObject * /* parent */) { \
return to_pytype((py_type) src); \
} \
TYPE_CASTER(type, #type); \
};
TYPE_CASTER_NUMBER(int32_t, long, PyLong_AsLong, PyLong_FromLong)
TYPE_CASTER_NUMBER(uint32_t, unsigned long, PyLong_AsUnsignedLong, PyLong_FromUnsignedLong)
TYPE_CASTER_NUMBER(int64_t, PY_LONG_LONG, PyLong_AsLongLong, PyLong_FromLongLong)
TYPE_CASTER_NUMBER(uint64_t, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong, PyLong_FromUnsignedLongLong)
#if defined(__APPLE__) // size_t/ssize_t are separate types on Mac OS X
TYPE_CASTER_NUMBER(ssize_t, Py_ssize_t, PyLong_AsSsize_t, PyLong_FromSsize_t)
TYPE_CASTER_NUMBER(size_t, size_t, PyLong_AsSize_t, PyLong_FromSize_t)
#endif
TYPE_CASTER_NUMBER(float, float, PyFloat_AsDouble, PyFloat_FromDouble)
TYPE_CASTER_NUMBER(double, double, PyFloat_AsDouble, PyFloat_FromDouble)
template <> class type_caster<mpl::detail::void_type> {
public:
bool load(PyObject *, bool) { return true; }
static PyObject *cast(mpl::detail::void_type, return_value_policy /* policy */, PyObject * /* parent */) {
Py_INCREF(Py_None);
return Py_None;
}
TYPE_CASTER(mpl::detail::void_type, "None");
};
template <> class type_caster<bool> {
public:
bool load(PyObject *src, bool) {
if (src == Py_True) { value = true; return true; }
else if (src == Py_False) { value = false; return true; }
else return false;
}
static PyObject *cast(bool src, return_value_policy /* policy */, PyObject * /* parent */) {
PyObject *result = src ? Py_True : Py_False;
Py_INCREF(result);
return result;
}
TYPE_CASTER(bool, "bool");
};
template <> class type_caster<std::string> {
public:
bool load(PyObject *src, bool) {
const char *ptr = PyUnicode_AsUTF8(src);
if (!ptr) { PyErr_Clear(); return false; }
value = std::string(ptr);
return true;
}
static PyObject *cast(const std::string &src, return_value_policy /* policy */, PyObject * /* parent */) {
return PyUnicode_FromString(src.c_str());
}
TYPE_CASTER(std::string, "str");
};
template <> class type_caster<char> {
public:
bool load(PyObject *src, bool) {
char *ptr = PyUnicode_AsUTF8(src);
if (!ptr) { PyErr_Clear(); return false; }
value = ptr;
return true;
}
static PyObject *cast(const char *src, return_value_policy /* policy */, PyObject * /* parent */) {
return PyUnicode_FromString(src);
}
static PyObject *cast(char src, return_value_policy /* policy */, PyObject * /* parent */) {
char str[2] = { src, '\0' };
return PyUnicode_DecodeLatin1(str, 1, nullptr);
}
static std::string name() { return "str"; }
operator char*() { return value; }
operator char() { return *value; }
protected:
char *value;
};
template <typename Value> struct type_caster<std::vector<Value>> {
typedef std::vector<Value> type;
typedef type_caster<Value> value_conv;
public:
bool load(PyObject *src, bool convert) {
if (!PyList_Check(src))
return false;
size_t size = (size_t) PyList_GET_SIZE(src);
value.reserve(size);
value.clear();
for (size_t i=0; i<size; ++i) {
value_conv conv;
if (!conv.load(PyList_GetItem(src, (ssize_t) i), convert))
return false;
value.push_back((Value) conv);
}
return true;
}
static PyObject *cast(const type &src, return_value_policy policy, PyObject *parent) {
PyObject *list = PyList_New(src.size());
size_t index = 0;
for (auto const &value: src) {
PyObject *value_ = value_conv::cast(value, policy, parent);
if (!value_) {
Py_DECREF(list);
return nullptr;
}
PyList_SetItem(list, index++, value_);
}
return list;
}
TYPE_CASTER(type, "list<" + value_conv::name() + ">");
};
template <typename Key, typename Value> struct type_caster<std::map<Key, Value>> {
public:
typedef std::map<Key, Value> type;
typedef type_caster<Key> key_conv;
typedef type_caster<Value> value_conv;
bool load(PyObject *src, bool convert) {
if (!PyDict_Check(src))
return false;
value.clear();
PyObject *key_, *value_;
ssize_t pos = 0;
key_conv kconv;
value_conv vconv;
while (PyDict_Next(src, &pos, &key_, &value_)) {
if (!kconv.load(key_, convert) || !vconv.load(value_, convert))
return false;
value[kconv] = vconv;
}
return true;
}
static PyObject *cast(const type &src, return_value_policy policy, PyObject *parent) {
PyObject *dict = PyDict_New();
for (auto const &kv: src) {
PyObject *key = key_conv::cast(kv.first, policy, parent);
PyObject *value = value_conv::cast(kv.second, policy, parent);
if (!key || !value || PyDict_SetItem(dict, key, value) < 0) {
Py_XDECREF(key);
Py_XDECREF(value);
Py_DECREF(dict);
return nullptr;
}
Py_DECREF(key);
Py_DECREF(value);
}
return dict;
}
TYPE_CASTER(type, "dict<" + key_conv::name() + ", " + value_conv::name() + ">");
};
template <typename T1, typename T2> class type_caster<std::pair<T1, T2>> {
typedef std::pair<T1, T2> type;
public:
bool load(PyObject *src, bool convert) {
if (!PyTuple_Check(src) || PyTuple_Size(src) != 2)
return false;
if (!first.load(PyTuple_GetItem(src, 0), convert))
return false;
return second.load(PyTuple_GetItem(src, 1), convert);
}
static PyObject *cast(const type &src, return_value_policy policy, PyObject *parent) {
PyObject *o1 = type_caster<typename mpl::normalize_type<T1>::type>::cast(src.first, policy, parent);
PyObject *o2 = type_caster<typename mpl::normalize_type<T2>::type>::cast(src.second, policy, parent);
if (!o1 || !o2) {
Py_XDECREF(o1);
Py_XDECREF(o2);
return nullptr;
}
PyObject *tuple = PyTuple_New(2);
PyTuple_SetItem(tuple, 0, o1);
PyTuple_SetItem(tuple, 1, o2);
return tuple;
}
static std::string name() {
return "(" + type_caster<T1>::name() + ", " + type_caster<T2>::name() + ")";
}
operator type() {
return type(first, second);
}
protected:
type_caster<typename mpl::normalize_type<T1>::type> first;
type_caster<typename mpl::normalize_type<T2>::type> second;
};
template <typename ... Tuple> class type_caster<std::tuple<Tuple...>> {
typedef std::tuple<Tuple...> type;
public:
enum { size = sizeof...(Tuple) };
bool load(PyObject *src, bool convert) {
return load(src, convert, typename mpl::make_index_sequence<sizeof...(Tuple)>::type());
}
static PyObject *cast(const type &src, return_value_policy policy, PyObject *parent) {
return cast(src, policy, parent, typename mpl::make_index_sequence<size>::type());
}
static std::string name() {
std::array<std::string, size> names {{
type_caster<typename mpl::normalize_type<Tuple>::type>::name()...
}};
std::string result("(");
int counter = 0;
for (auto const &name : names) {
result += name;
if (++counter < size)
result += ", ";
}
result += ")";
return result;
}
operator type() {
return cast(typename mpl::make_index_sequence<sizeof...(Tuple)>::type());
}
protected:
template <size_t ... Index> type cast(mpl::index_sequence<Index...>) {
return type((Tuple) std::get<Index>(value)...);
}
template <size_t ... Indices> bool load(PyObject *src, bool convert, mpl::index_sequence<Indices...>) {
if (!PyTuple_Check(src))
return false;
if (PyTuple_Size(src) != size)
return false;
std::array<bool, size> results {{
std::get<Indices>(value).load(PyTuple_GetItem(src, Indices), convert)...
}};
for (bool r : results)
if (!r)
return false;
return true;
}
/* Implementation: Convert a C++ tuple into a Python tuple */
template <size_t ... Indices> static PyObject *cast(const type &src, return_value_policy policy, PyObject *parent, mpl::index_sequence<Indices...>) {
std::array<PyObject *, size> results {{
type_caster<typename mpl::normalize_type<Tuple>::type>::cast(std::get<Indices>(src), policy, parent)...
}};
bool success = true;
for (auto result : results)
if (result == nullptr)
success = false;
if (success) {
PyObject *tuple = PyTuple_New(size);
int counter = 0;
for (auto result : results)
PyTuple_SetItem(tuple, counter++, result);
return tuple;
} else {
for (auto result : results) {
Py_XDECREF(result);
}
return nullptr;
}
}
protected:
std::tuple<type_caster<typename mpl::normalize_type<Tuple>::type>...> value;
};
/// Type caster for holder types like std::shared_ptr, etc.
template <typename type, typename holder_type> class type_caster_holder : public type_caster<type> {
public:
typedef type_caster<type> parent;
bool load(PyObject *src, bool convert) {
if (!parent::load(src, convert))
return false;
holder = holder_type(parent::value);
return true;
}
explicit operator type*() { return this->value; }
explicit operator type&() { return *(this->value); }
explicit operator holder_type&() { return holder; }
explicit operator holder_type*() { return &holder; }
protected:
holder_type holder;
};
template <> class type_caster<handle> {
public:
bool load(PyObject *src) {
value = handle(src);
return true;
}
static PyObject *cast(const handle &src, return_value_policy /* policy */, PyObject * /* parent */) {
src.inc_ref();
return (PyObject *) src.ptr();
}
TYPE_CASTER(handle, "handle");
};
#define TYPE_CASTER_PYTYPE(name) \
template <> class type_caster<name> { \
public: \
bool load(PyObject *src, bool) { value = name(src, true); return true; } \
static PyObject *cast(const name &src, return_value_policy /* policy */, PyObject * /* parent */) { \
src.inc_ref(); return (PyObject *) src.ptr(); \
} \
TYPE_CASTER(name, #name); \
};
TYPE_CASTER_PYTYPE(object)
TYPE_CASTER_PYTYPE(buffer)
TYPE_CASTER_PYTYPE(capsule)
TYPE_CASTER_PYTYPE(dict)
TYPE_CASTER_PYTYPE(float_)
TYPE_CASTER_PYTYPE(int_)
TYPE_CASTER_PYTYPE(list)
TYPE_CASTER_PYTYPE(slice)
TYPE_CASTER_PYTYPE(tuple)
#undef TYPE_CASTER
#undef TYPE_CASTER_NUMBER
#undef TYPE_CASTER_PYTYPE
NAMESPACE_END(detail)
template <typename T> inline T cast(PyObject *object) {
detail::type_caster<typename mpl::normalize_type<T>::type> conv;
if (!conv.load(object, true))
throw cast_error("Unable to cast Python object to C++ type");
return conv;
}
template <typename T> inline object cast(const T &value, return_value_policy policy = return_value_policy::automatic, PyObject *parent = nullptr) {
if (policy == return_value_policy::automatic)
policy = std::is_pointer<T>::value ? return_value_policy::take_ownership : return_value_policy::copy;
return object(detail::type_caster<typename mpl::normalize_type<T>::type>::cast(value, policy, parent), false);
}
template <typename T> inline T handle::cast() { return pybind::cast<T>(m_ptr); }
template <typename ... Args> inline object handle::call(Args&&... args_) {
const size_t size = sizeof...(Args);
std::array<PyObject *, size> args{
{ detail::type_caster<typename mpl::normalize_type<Args>::type>::cast(
std::forward<Args>(args_), return_value_policy::automatic, nullptr)... }
};
bool fail = false;
for (auto result : args)
if (result == nullptr)
fail = true;
if (fail) {
for (auto result : args) {
Py_XDECREF(result);
}
throw cast_error("handle::call(): unable to convert input arguments to Python objects");
}
PyObject *tuple = PyTuple_New(size);
int counter = 0;
for (auto result : args)
PyTuple_SetItem(tuple, counter++, result);
PyObject *result = PyObject_CallObject(m_ptr, tuple);
Py_DECREF(tuple);
return object(result, false);
}
NAMESPACE_END(pybind)
#endif /* __PYBIND_CAST */
/*
pybind/common.h -- Basic macros
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.
*/
#if !defined(__PYBIND_COMMON_H)
#define __PYBIND_COMMON_H
#if !defined(NAMESPACE_BEGIN)
#define NAMESPACE_BEGIN(name) namespace name {
#endif
#if !defined(NAMESPACE_END)
#define NAMESPACE_END(name) }
#endif
#if !defined(PYTHON_EXPORT)
#if defined(WIN32)
#define PYTHON_EXPORT __declspec(dllexport)
#else
#define PYTHON_EXPORT __attribute__ ((visibility("default")))
#endif
#endif
#define PYTHON_PLUGIN(name) \
extern "C" PYTHON_EXPORT PyObject *PyInit_##name()
#include <vector>
#include <string>
#include <stdexcept>
#include <functional>
#include <unordered_map>
#include <iostream>
#include <memory>
/// Include Python header, disable linking to pythonX_d.lib on Windows in debug mode
#if defined(_MSC_VER)
#define HAVE_ROUND
#pragma warning(push)
#pragma warning(disable: 4510 4610 4512)
#if _DEBUG
#define _DEBUG_MARKER
#undef _DEBUG
#endif
#endif
#include <Python.h>
#if defined(_MSC_VER)
#if defined(_DEBUG_MARKER)
#define _DEBUG
#undef _DEBUG_MARKER
#endif
#pragma warning(pop)
#endif
NAMESPACE_BEGIN(pybind)
typedef Py_ssize_t ssize_t;
/// Approach used to cast a previously unknown C++ instance into a Python object
enum class return_value_policy : int {
/** Automatic: copy objects returned as values and take ownership of objects
returned as pointers */
automatic = 0,
/** Reference the object and take ownership. Python will call the
destructor and delete operator when the reference count reaches zero */
take_ownership,
/** Reference the object, but do not take ownership (dangerous when C++ code
deletes it and Python still has a nonzero reference count) */
reference,
/** Reference the object, but do not take ownership. The object is considered
be owned by the C++ instance whose method or property returned it. The
Python object will increase the reference count of this 'parent' by 1 */
reference_internal,
/// Create a new copy of the returned object, which will be owned by Python
copy
};
/// Format strings for basic number types
template <typename type> struct format_descriptor { };
template<> struct format_descriptor<int8_t> { static std::string value() { return "b"; }; };
template<> struct format_descriptor<uint8_t> { static std::string value() { return "B"; }; };
template<> struct format_descriptor<int16_t> { static std::string value() { return "h"; }; };
template<> struct format_descriptor<uint16_t> { static std::string value() { return "H"; }; };
template<> struct format_descriptor<int32_t> { static std::string value() { return "i"; }; };
template<> struct format_descriptor<uint32_t> { static std::string value() { return "I"; }; };
template<> struct format_descriptor<int64_t> { static std::string value() { return "q"; }; };
template<> struct format_descriptor<uint64_t> { static std::string value() { return "Q"; }; };
template<> struct format_descriptor<float> { static std::string value() { return "f"; }; };
template<> struct format_descriptor<double> { static std::string value() { return "d"; }; };
/// Information record describing a Python buffer object
struct buffer_info {
void *ptr;
size_t itemsize;
std::string format; // for dense contents, this should be set to format_descriptor<T>::value
int ndim;
std::vector<size_t> shape;
std::vector<size_t> strides;
buffer_info(void *ptr, size_t itemsize, const std::string &format,
int ndim, const std::vector<size_t> &shape,
const std::vector<size_t> &strides)
: ptr(ptr), itemsize(itemsize), format(format), ndim(ndim),
shape(shape), strides(strides) {}
};
// C++ bindings of core Python exceptions
struct stop_iteration : public std::runtime_error { public: stop_iteration(const std::string &w="") : std::runtime_error(w) {} };
struct index_error : public std::runtime_error { public: index_error(const std::string &w="") : std::runtime_error(w) {} };
struct error_already_set : public std::exception { public: error_already_set() {} };
/// Thrown when pybind::cast or handle::call fail due to a type casting error
struct cast_error : public std::runtime_error { public: cast_error(const std::string &w = "") : std::runtime_error(w) {} };
NAMESPACE_BEGIN(detail)
/// PyObject wrapper around generic types
template <typename type, typename holder_type = std::unique_ptr<type>> struct instance {
PyObject_HEAD
type *value;
PyObject *parent;
bool owned : 1;
bool constructed : 1;
holder_type holder;
};
/// Additional type information which does not fit into the PyTypeObjet
struct type_info {
PyTypeObject *type;
size_t type_size;
void (*init_holder)(PyObject *);
std::function<buffer_info *(PyObject *)> get_buffer;
std::vector<PyObject *(*)(PyObject *, PyTypeObject *)> implicit_conversions;
};
/// Internal data struture used to track registered instances and types
struct internals {
std::unordered_map<std::string, type_info> registered_types;
std::unordered_map<void *, PyObject *> registered_instances;
};
inline internals &get_internals();
NAMESPACE_END(detail)
NAMESPACE_END(pybind)
#endif /* __PYBIND_COMMON_H */
/*
pybind/mpl.h: Simple library for type manipulation and template metaprogramming
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.
*/
#if !defined(__PYBIND_MPL_H)
#define __PYBIND_MPL_H
#include "common.h"
#include <tuple>
NAMESPACE_BEGIN(pybind)
NAMESPACE_BEGIN(mpl)
/// Index sequence for convenient template metaprogramming involving tuples
template<size_t ...> struct index_sequence { };
template<size_t N, size_t ...S> struct make_index_sequence : make_index_sequence <N - 1, N - 1, S...> { };
template<size_t ...S> struct make_index_sequence <0, S...> { typedef index_sequence<S...> type; };
/// Helper template to strip away type modifiers
template <typename T> struct normalize_type { typedef T type; };
template <typename T> struct normalize_type<const T> { typedef typename normalize_type<T>::type type; };
template <typename T> struct normalize_type<T*> { typedef typename normalize_type<T>::type type; };
template <typename T> struct normalize_type<T&> { typedef typename normalize_type<T>::type type; };
template <typename T> struct normalize_type<T&&> { typedef typename normalize_type<T>::type type; };
template <typename T, size_t N> struct normalize_type<const T[N]> { typedef typename normalize_type<T>::type type; };
template <typename T, size_t N> struct normalize_type<T[N]> { typedef typename normalize_type<T>::type type; };
NAMESPACE_BEGIN(detail)
/// Strip the class from a method type
template <typename T> struct remove_class {};
template <typename C, typename R, typename... A> struct remove_class<R (C::*)(A...)> { typedef R type(A...); };
template <typename C, typename R, typename... A> struct remove_class<R (C::*)(A...) const> { typedef R type(A...); };
/**
* \brief Convert a lambda function to a std::function
* From http://stackoverflow.com/questions/11893141/inferring-the-call-signature-of-a-lambda-or-arbitrary-callable-for-make-functio
*/
template <typename T> struct lambda_signature_impl {
using type = typename remove_class<
decltype(&std::remove_reference<T>::type::operator())>::type;
};
template <typename R, typename... A> struct lambda_signature_impl<R (A...)> { typedef R type(A...); };
template <typename R, typename... A> struct lambda_signature_impl<R (&)(A...)> { typedef R type(A...); };
template <typename R, typename... A> struct lambda_signature_impl<R (*)(A...)> { typedef R type(A...); };
template <typename T> using lambda_signature = typename lambda_signature_impl<T>::type;
template <typename F> using make_function_type = std::function<lambda_signature<F>>;
NAMESPACE_END(detail)
template<typename F> detail::make_function_type<F> make_function(F &&f) {
return detail::make_function_type<F>(std::forward<F>(f)); }
NAMESPACE_BEGIN(detail)
struct void_type { };
/// Helper functions for calling a function using a tuple argument while dealing with void/non-void return values
template <typename RetType> struct tuple_dispatch {
typedef RetType return_type;
template<typename Func, typename Arg, size_t ... S> return_type operator()(const Func &f, Arg && args, index_sequence<S...>) {
return f(std::get<S>(std::forward<Arg>(args))...);
}
};
/// Helper functions for calling a function using a tuple argument (special case for void return values)
template <> struct tuple_dispatch<void> {
typedef void_type return_type;
template<typename Func, typename Arg, size_t ... S> return_type operator()(const Func &f, Arg &&args, index_sequence<S...>) {
f(std::get<S>(std::forward<Arg>(args))...);
return return_type();
}
};
NAMESPACE_END(detail)
/// For lambda functions delegate to their 'operator()'
template <typename T> struct function_traits : public function_traits<typename detail::make_function_type<T>> { };
/// Type traits for function pointers
template <typename ReturnType, typename... Args>
struct function_traits<ReturnType(*)(Args...)> {
enum {
nargs = sizeof...(Args),
is_method = 0,
is_const = 0
};
typedef std::function<ReturnType (Args...)> f_type;
typedef detail::tuple_dispatch<ReturnType> dispatch_type;
typedef typename dispatch_type::return_type return_type;
typedef std::tuple<Args...> args_type;
template <size_t i> struct arg {
typedef typename std::tuple_element<i, args_type>::type type;
};
static f_type cast(ReturnType (*func)(Args ...)) { return func; }
static return_type dispatch(const f_type &f, args_type &&args) {
return dispatch_type()(f, std::move(args),
typename make_index_sequence<nargs>::type());
}
};
/// Type traits for ordinary methods
template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...)> {
enum {
nargs = sizeof...(Args),
is_method = 1,
is_const = 0
};
typedef std::function<ReturnType(ClassType &, Args...)> f_type;
typedef detail::tuple_dispatch<ReturnType> dispatch_type;
typedef typename dispatch_type::return_type return_type;
typedef std::tuple<ClassType&, Args...> args_type;
template <size_t i> struct arg {
typedef typename std::tuple_element<i, args_type>::type type;
};
static f_type cast(ReturnType (ClassType::*func)(Args ...)) { return std::mem_fn(func); }
static return_type dispatch(const f_type &f, args_type &&args) {
return dispatch_type()(f, std::move(args),
typename make_index_sequence<nargs+1>::type());
}
};
/// Type traits for const methods
template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...) const> {
enum {
nargs = sizeof...(Args),
is_method = 1,
is_const = 1
};
typedef std::function<ReturnType (const ClassType &, Args...)> f_type;
typedef detail::tuple_dispatch<ReturnType> dispatch_type;
typedef typename dispatch_type::return_type return_type;
typedef std::tuple<const ClassType&, Args...> args_type;
template <size_t i> struct arg {
typedef typename std::tuple_element<i, args_type>::type type;
};
static f_type cast(ReturnType (ClassType::*func)(Args ...) const) {
return std::mem_fn(func);
}
static return_type dispatch(const f_type &f, args_type &&args) {
return dispatch_type()(f, std::move(args),
typename make_index_sequence<nargs+1>::type());
}
};
/// Type traits for std::functions
template <typename ReturnType, typename... Args>
struct function_traits<std::function<ReturnType(Args...)>> {
enum {
nargs = sizeof...(Args),
is_method = 0,
is_const = 0
};
typedef std::function<ReturnType (Args...)> f_type;
typedef detail::tuple_dispatch<ReturnType> dispatch_type;
typedef typename dispatch_type::return_type return_type;
typedef std::tuple<Args...> args_type;
template <size_t i> struct arg {
typedef typename std::tuple_element<i, args_type>::type type;
};
static f_type cast(const f_type &func) { return func; }
static return_type dispatch(const f_type &f, args_type &&args) {
return dispatch_type()(f, std::move(args),
typename make_index_sequence<nargs>::type());
}
};
NAMESPACE_END(mpl)
NAMESPACE_END(pybind)
#endif /* __PYBIND_MPL_H */
/*
pybind/operator.h: Metatemplates for operator overloading
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.
*/
#if !defined(__PYBIND_OPERATOR)
#define __PYBIND_OPERATOR
#include "pybind.h"
#include <type_traits>
NAMESPACE_BEGIN(pybind)
NAMESPACE_BEGIN(detail)
/// Enumeration with all supported operator types
enum op_id : int {
op_add, op_sub, op_mul, op_div, op_mod, op_divmod, op_pow,
op_lshift, op_rshift, op_and, op_xor, op_or, op_neg,
op_pos, op_abs, op_invert, op_int, op_long, op_float,
op_str, op_cmp, op_gt, op_ge, op_lt, op_le, op_eq, op_ne,
op_iadd, op_isub, op_imul, op_idiv, op_imod, op_ilshift,
op_irshift, op_iand, op_ixor, op_ior, op_complex, op_bool,
op_nonzero, op_repr, op_truediv
};
enum op_type : int {
op_l, /* base type on left */
op_r, /* base type on right */
op_u /* unary operator */
};
struct self_t { };
/// Type for an unused type slot
struct undefined_t { };
static const self_t self = self_t();
/// Don't warn about an unused variable
inline self_t __self() { return self; }
/// base template of operator implementations
template <op_id, op_type, typename B, typename L, typename R> struct op_impl { };
/// Operator implementation generator
template <op_id id, op_type ot, typename L, typename R> struct op_ {
template <typename base, typename holder> void execute(pybind::class_<base, holder> &class_, const char *doc, return_value_policy policy) const {
typedef typename std::conditional<std::is_same<L, self_t>::value, base, L>::type L_type;
typedef typename std::conditional<std::is_same<R, self_t>::value, base, R>::type R_type;
typedef op_impl<id, ot, base, L_type, R_type> op;
class_.def(op::name(), &op::execute, doc, policy);
}
template <typename base, typename holder> void execute_cast(pybind::class_<base, holder> &class_, const char *doc, return_value_policy policy) const {
typedef typename std::conditional<std::is_same<L, self_t>::value, base, L>::type L_type;
typedef typename std::conditional<std::is_same<R, self_t>::value, base, R>::type R_type;
typedef op_impl<id, ot, base, L_type, R_type> op;
class_.def(op::name(), &op::execute_cast, doc, policy);
}
};
#define PYBIND_BINARY_OPERATOR(id, rid, op, expr) \
template <typename B, typename L, typename R> struct op_impl<op_##id, op_l, B, L, R> { \
static char const* name() { return "__" #id "__"; } \
static auto execute(const L &l, const R &r) -> decltype(expr) { return (expr); } \
static B execute_cast(const L &l, const R &r) { return B(expr); } \
}; \
template <typename B, typename L, typename R> struct op_impl<op_##id, op_r, B, L, R> { \
static char const* name() { return "__" #rid "__"; } \
static auto execute(const L &l, const R &r) -> decltype(expr) { return (expr); } \
static B execute_cast(const L &l, const R &r) { return B(expr); } \
}; \
inline op_<op_##id, op_l, self_t, self_t> op(const self_t &, const self_t &) { \
return op_<op_##id, op_l, self_t, self_t>(); \
}; \
template <typename T> op_<op_##id, op_l, self_t, T> op(const self_t &, const T &) { \
return op_<op_##id, op_l, self_t, T>(); \
}; \
template <typename T> op_<op_##id, op_r, T, self_t> op(const T &, const self_t &) { \
return op_<op_##id, op_r, T, self_t>(); \
};
#define PYBIND_INPLACE_OPERATOR(id, op, expr) \
template <typename B, typename L, typename R> struct op_impl<op_##id, op_l, B, L, R> { \
static char const* name() { return "__" #id "__"; } \
static auto execute(L &l, const R &r) -> decltype(expr) { return expr; } \
static B execute_cast(L &l, const R &r) { return B(expr); } \
}; \
template <typename T> op_<op_##id, op_l, self_t, T> op(const self_t &, const T &) { \
return op_<op_##id, op_l, self_t, T>(); \
};
#define PYBIND_UNARY_OPERATOR(id, op, expr) \
template <typename B, typename L> struct op_impl<op_##id, op_u, B, L, undefined_t> { \
static char const* name() { return "__" #id "__"; } \
static auto execute(const L &l) -> decltype(expr) { return expr; } \
static B execute_cast(const L &l) { return B(expr); } \
}; \
inline op_<op_##id, op_u, self_t, undefined_t> op(const self_t &) { \
return op_<op_##id, op_u, self_t, undefined_t>(); \
};
PYBIND_BINARY_OPERATOR(sub, rsub, operator-, l - r)
PYBIND_BINARY_OPERATOR(add, radd, operator+, l + r)
PYBIND_BINARY_OPERATOR(mul, rmul, operator*, l * r)
PYBIND_BINARY_OPERATOR(truediv, rtruediv, operator/, l / r)
PYBIND_BINARY_OPERATOR(mod, rmod, operator%, l % r)
PYBIND_BINARY_OPERATOR(lshift, rlshift, operator<<, l << r)
PYBIND_BINARY_OPERATOR(rshift, rrshift, operator>>, l >> r)
PYBIND_BINARY_OPERATOR(and, rand, operator&, l & r)
PYBIND_BINARY_OPERATOR(xor, rxor, operator^, l ^ r)
PYBIND_BINARY_OPERATOR(eq, eq, operator==, l == r)
PYBIND_BINARY_OPERATOR(ne, ne, operator!=, l != r)
PYBIND_BINARY_OPERATOR(or, ror, operator|, l | r)
PYBIND_BINARY_OPERATOR(gt, lt, operator>, l > r)
PYBIND_BINARY_OPERATOR(ge, le, operator>=, l >= r)
PYBIND_BINARY_OPERATOR(lt, gt, operator<, l < r)
PYBIND_BINARY_OPERATOR(le, ge, operator<=, l <= r)
//PYBIND_BINARY_OPERATOR(pow, rpow, pow, std::pow(l, r))
PYBIND_INPLACE_OPERATOR(iadd, operator+=, l += r)
PYBIND_INPLACE_OPERATOR(isub, operator-=, l -= r)
PYBIND_INPLACE_OPERATOR(imul, operator*=, l *= r)
PYBIND_INPLACE_OPERATOR(idiv, operator/=, l /= r)
PYBIND_INPLACE_OPERATOR(imod, operator%=, l %= r)
PYBIND_INPLACE_OPERATOR(ilshift, operator<<=, l <<= r)
PYBIND_INPLACE_OPERATOR(irshift, operator>>=, l >>= r)
PYBIND_INPLACE_OPERATOR(iand, operator&=, l &= r)
PYBIND_INPLACE_OPERATOR(ixor, operator^=, l ^= r)
PYBIND_INPLACE_OPERATOR(ior, operator|=, l |= r)
PYBIND_UNARY_OPERATOR(neg, operator-, -l)
PYBIND_UNARY_OPERATOR(pos, operator+, +l)
PYBIND_UNARY_OPERATOR(abs, abs, std::abs(l))
PYBIND_UNARY_OPERATOR(invert, operator~, ~l)
PYBIND_UNARY_OPERATOR(bool, operator!, !!l)
PYBIND_UNARY_OPERATOR(int, int_, (int) l)
PYBIND_UNARY_OPERATOR(float, float_, (double) l)
#undef PYBIND_BINARY_OPERATOR
#undef PYBIND_INPLACE_OPERATOR
#undef PYBIND_UNARY_OPERATOR
NAMESPACE_END(detail)
using detail::self;
NAMESPACE_END(pybind)
#endif /* __PYBIND_OPERATOR */
This diff is collapsed.
/*
pybind/typeid.h: Convenience wrapper classes for basic Python types
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.
*/
#if !defined(__PYBIND_PYTYPES_H)
#define __PYBIND_PYTYPES_H
#include "common.h"
#include <utility>
NAMESPACE_BEGIN(pybind)
/* A few forward declarations */
class object;
class str;
class object;
class dict;
NAMESPACE_BEGIN(detail)
class accessor;
NAMESPACE_END(detail)
/// Holds a reference to a Python object (no reference counting)
class handle {
public:
handle() : m_ptr(nullptr) { }
handle(const handle &other) : m_ptr(other.m_ptr) { }
handle(PyObject *ptr) : m_ptr(ptr) { }
PyObject *ptr() { return m_ptr; }
const PyObject *ptr() const { return m_ptr; }
void inc_ref() const { Py_XINCREF(m_ptr); }
void dec_ref() const { Py_XDECREF(m_ptr); }
int ref_count() const { return (int) Py_REFCNT(m_ptr); }
inline detail::accessor operator[](handle key);
inline detail::accessor operator[](const char *key);
inline detail::accessor attr(handle key);
inline detail::accessor attr(const char *key);
inline pybind::str str() const;
template <typename T> T cast();
template <typename ... Args> object call(Args&&... args_);
operator bool() const { return m_ptr != nullptr; }
protected:
PyObject *m_ptr;
};
/// Holds a reference to a Python object (with reference counting)
class object : public handle {
public:
object() { }
object(const object &o) : handle(o) { inc_ref(); }
object(const handle &h, bool borrowed) : handle(h) { if (borrowed) inc_ref(); }
object(PyObject *ptr, bool borrowed) : handle(ptr) { if (borrowed) inc_ref(); }
object(object &&other) { m_ptr = other.m_ptr; other.m_ptr = nullptr; }
~object() { dec_ref(); }
object& operator=(object &other) {
Py_XINCREF(other.m_ptr);
Py_XDECREF(m_ptr);
m_ptr = other.m_ptr;
return *this;
}
object& operator=(object &&other) {
if (this != &other) {
PyObject *temp = m_ptr;
m_ptr = other.m_ptr;
other.m_ptr = nullptr;
Py_XDECREF(temp);
}
return *this;
}
};
NAMESPACE_BEGIN(detail)
class accessor {
public:
accessor(PyObject *obj, PyObject *key, bool attr)
: obj(obj), key(key), attr(attr) { Py_INCREF(key); }
accessor(PyObject *obj, const char *key, bool attr)
: obj(obj), key(PyUnicode_FromString(key)), attr(attr) { }
accessor(const accessor &a) : obj(a.obj), key(a.key), attr(a.attr)
{ Py_INCREF(key); }
~accessor() { Py_DECREF(key); }
void operator=(accessor o) { operator=(object(o)); }
void operator=(const handle &h) {
if (attr) {
if (PyObject_SetAttr(obj, key, (PyObject *) h.ptr()) < 0)
throw std::runtime_error("Unable to set object attribute");
} else {
if (PyObject_SetItem(obj, key, (PyObject *) h.ptr()) < 0)
throw std::runtime_error("Unable to set object item");
}
}
operator object() const {
object result(attr ? PyObject_GetAttr(obj, key)
: PyObject_GetItem(obj, key), false);
if (!result) PyErr_Clear();
return result;
}
operator bool() const {
if (attr) {
return (bool) PyObject_HasAttr(obj, key);
} else {
object result(PyObject_GetItem(obj, key), false);
if (!result) PyErr_Clear();
return (bool) result;
}
};
private:
PyObject *obj;
PyObject *key;
bool attr;
};
struct list_accessor {
public:
list_accessor(PyObject *list, size_t index) : list(list), index(index) { }
void operator=(list_accessor o) { return operator=(object(o)); }
void operator=(const handle &o) {
o.inc_ref(); // PyList_SetItem steals a reference
if (PyList_SetItem(list, (ssize_t) index, (PyObject *) o.ptr()) < 0)
throw std::runtime_error("Unable to assign value in Python list!");
}
operator object() const {
PyObject *result = PyList_GetItem(list, (ssize_t) index);
if (!result)
throw std::runtime_error("Unable to retrieve value from Python list!");
return object(result, true);
}
private:
PyObject *list;
size_t index;
};
struct tuple_accessor {
public:
tuple_accessor(PyObject *tuple, size_t index) : tuple(tuple), index(index) { }
void operator=(tuple_accessor o) { return operator=(object(o)); }
void operator=(const handle &o) {
o.inc_ref(); // PyTuple_SetItem steals a reference
if (PyTuple_SetItem(tuple, (ssize_t) index, (PyObject *) o.ptr()) < 0)
throw std::runtime_error("Unable to assign value in Python tuple!");
}
operator object() const {
PyObject *result = PyTuple_GetItem(tuple, (ssize_t) index);
if (!result)
throw std::runtime_error("Unable to retrieve value from Python tuple!");
return object(result, true);
}
private:
PyObject *tuple;
size_t index;
};
class list_iterator {
public:
list_iterator(PyObject *list, ssize_t pos) : list(list), pos(pos) { }
list_iterator& operator++() { ++pos; return *this; }
object operator*() { return object(PyList_GetItem(list, pos), true); }
bool operator==(const list_iterator &it) const { return it.pos == pos; }
bool operator!=(const list_iterator &it) const { return it.pos != pos; }
private:
PyObject *list;
ssize_t pos;
};
struct dict_iterator {
public:
dict_iterator(PyObject *dict = nullptr, ssize_t pos = -1) : dict(dict), pos(pos) { }
dict_iterator& operator++() {
if (!PyDict_Next(dict, &pos, &key, &value))
pos = -1;
return *this;
}
std::pair<object, object> operator*() {
return std::make_pair(object(key, true), object(value, true));
}
bool operator==(const dict_iterator &it) const { return it.pos == pos; }
bool operator!=(const dict_iterator &it) const { return it.pos != pos; }
private:
PyObject *dict, *key, *value;
ssize_t pos = 0;
};
NAMESPACE_END(detail)
inline detail::accessor handle::operator[](handle key) { return detail::accessor(ptr(), key.ptr(), false); }
inline detail::accessor handle::operator[](const char *key) { return detail::accessor(ptr(), key, false); }
inline detail::accessor handle::attr(handle key) { return detail::accessor(ptr(), key.ptr(), true); }
inline detail::accessor handle::attr(const char *key) { return detail::accessor(ptr(), key, true); }
#define PYTHON_OBJECT(Name, Parent, CheckFun) \
Name(const handle &h, bool borrowed) : Parent(h, borrowed) { } \
Name(const object& o): Parent(o) { } \
Name(object&& o): Parent(std::move(o)) { } \
Name& operator=(object&& o) { return static_cast<Name&>(object::operator=(std::move(o))); } \
Name& operator=(object& o) { return static_cast<Name&>(object::operator=(o)); } \
bool check() const { return m_ptr != nullptr && (bool) CheckFun(m_ptr); }
#define PYTHON_OBJECT_DEFAULT(Name, Parent, CheckFun) \
PYTHON_OBJECT(Name, Parent, CheckFun) \
Name() : object() { }
class str : public object {
public:
PYTHON_OBJECT_DEFAULT(str, object, PyUnicode_Check)
str(const char *s) : object(PyUnicode_FromString(s), false) { }
operator const char *() const { return PyUnicode_AsUTF8(m_ptr); }
};
inline pybind::str handle::str() const { return pybind::str(PyObject_Str(m_ptr), false); }
inline std::ostream &operator<<(std::ostream &os, const object &obj) { os << (const char *) obj.str(); return os; }
class bool_ : public object {
public:
PYTHON_OBJECT_DEFAULT(bool_, object, PyBool_Check)
operator bool() const { return m_ptr && PyLong_AsLong(m_ptr) != 0; }
};
class int_ : public object {
public:
PYTHON_OBJECT_DEFAULT(int_, object, PyLong_Check)
int_(int value) : object(PyLong_FromLong((long) value), false) { }
int_(size_t value) : object(PyLong_FromSize_t(value), false) { }
int_(ssize_t value) : object(PyLong_FromSsize_t(value), false) { }
operator int() const { return (int) PyLong_AsLong(m_ptr); }
};
class float_ : public object {
public:
PYTHON_OBJECT_DEFAULT(float_, object, PyFloat_Check)
float_(float value) : object(PyFloat_FromDouble((double) value), false) { }
float_(double value) : object(PyFloat_FromDouble((double) value), false) { }
operator float() const { return (float) PyFloat_AsDouble(m_ptr); }
operator double() const { return (double) PyFloat_AsDouble(m_ptr); }
};
class slice : public object {
public:
PYTHON_OBJECT_DEFAULT(slice, object, PySlice_Check)
slice(ssize_t start_, ssize_t stop_, ssize_t step_) {
int_ start(start_), stop(stop_), step(step_);
m_ptr = PySlice_New(start.ptr(), stop.ptr(), step.ptr());
}
bool compute(ssize_t length, ssize_t *start, ssize_t *stop, ssize_t *step, ssize_t *slicelength) const {
return PySlice_GetIndicesEx(m_ptr, length, start, stop, step, slicelength) == 0;
}
};
class capsule : public object {
public:
PYTHON_OBJECT_DEFAULT(capsule, object, PyCapsule_CheckExact)
capsule(void *value) : object(PyCapsule_New(value, nullptr, nullptr), false) { }
template <typename T> operator T *() const {
T * result = static_cast<T *>(PyCapsule_GetPointer(m_ptr, nullptr));
if (!result) throw std::runtime_error("Unable to extract capsule contents!");
return result;
}
};
class tuple : public object {
public:
PYTHON_OBJECT_DEFAULT(tuple, object, PyTuple_Check)
tuple(size_t size) : object(PyTuple_New((Py_ssize_t) size), false) { }
size_t size() const { return (size_t) PyTuple_Size(m_ptr); }
detail::tuple_accessor operator[](size_t index) { return detail::tuple_accessor(ptr(), index); }
};
class dict : public object {
public:
PYTHON_OBJECT(dict, object, PyDict_Check)
dict() : object(PyDict_New(), false) { }
size_t size() const { return (size_t) PyDict_Size(m_ptr); }
detail::dict_iterator begin() { return (++detail::dict_iterator(ptr(), 0)); }
detail::dict_iterator end() { return detail::dict_iterator(); }
};
class list : public object {
public:
PYTHON_OBJECT(list, object, PyList_Check)
list(size_t size = 0) : object(PyList_New((ssize_t) size), false) { }
size_t size() const { return (size_t) PyList_Size(m_ptr); }
detail::list_iterator begin() { return detail::list_iterator(ptr(), 0); }
detail::list_iterator end() { return detail::list_iterator(ptr(), (ssize_t) size()); }
detail::list_accessor operator[](size_t index) { return detail::list_accessor(ptr(), index); }
void append(const object &object) { PyList_Append(m_ptr, (PyObject *) object.ptr()); }
};
class buffer : public object {
public:
PYTHON_OBJECT_DEFAULT(buffer, object, PyObject_CheckBuffer)
buffer_info request(bool writable = false) {
int flags = PyBUF_STRIDES | PyBUF_FORMAT;
if (writable) flags |= PyBUF_WRITABLE;
view = new Py_buffer();
if (PyObject_GetBuffer(m_ptr, view, flags) != 0)
throw error_already_set();
std::vector<size_t> shape(view->ndim), strides(view->ndim);
for (int i=0; i<view->ndim; ++i) {
shape[i] = (size_t) view->shape[i];
strides[i] = (size_t) view->strides[i];
}
return buffer_info(view->buf, view->itemsize, view->format,
view->ndim, shape, strides);
}
~buffer() { if (view) { PyBuffer_Release(view); delete view; } }
private:
Py_buffer *view = nullptr;
};
NAMESPACE_BEGIN(detail)
inline internals &get_internals() {
static internals *internals_ptr = nullptr;
if (internals_ptr)
return *internals_ptr;
handle builtins(PyEval_GetBuiltins());
capsule caps(builtins["__pybind__"]);
if (caps.check()) {
internals_ptr = caps;
} else {
internals_ptr = new internals();
builtins["__pybind__"] = capsule(internals_ptr);
}
return *internals_ptr;
}
NAMESPACE_END(detail)
NAMESPACE_END(pybind)
#endif /* __PYBIND_PYTYPES_H */
/*
pybind/typeid.h: Compiler-independent access to type identifiers
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.
*/
#if !defined(__PYBIND_TYPEID_H)
#define __PYBIND_TYPEID_H
#include "common.h"
#include <cstdio>
#include <cstdlib>
#if defined(__GNUG__)
#include <cxxabi.h>
#endif
NAMESPACE_BEGIN(pybind)
NAMESPACE_BEGIN(detail)
/// Erase all occurrences of a substring
inline void erase_all(std::string &string, const std::string &search) {
for (size_t pos = 0;;) {
pos = string.find(search, pos);
if (pos == std::string::npos) break;
string.erase(pos, search.length());
}
}
NAMESPACE_END(detail)
/// Return a string representation of a C++ type
template <typename T> static std::string type_id() {
std::string name(typeid(T).name());
#if defined(__GNUG__)
int status = 0;
std::unique_ptr<char, void (*)(void *)> res {
abi::__cxa_demangle(name.c_str(), nullptr, nullptr, &status), std::free };
if (status == 0)
name = res.get();
#else
detail::erase_all(name, "class ");
detail::erase_all(name, "struct ");
detail::erase_all(name, "enum ");
#endif
detail::erase_all(name, "pybind::");
return name;
}
NAMESPACE_END(pybind)
#endif /* __PYBIND_TYPEID_H */
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment