Initial commit
diff --git a/example/example.cpp b/example/example.cpp
new file mode 100644
index 0000000..800fb9f
--- /dev/null
+++ b/example/example.cpp
@@ -0,0 +1,36 @@
+/*
+ example/example.cpp -- pybind example plugin
+
+ 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 init_ex1(py::module &);
+void init_ex2(py::module &);
+void init_ex3(py::module &);
+void init_ex4(py::module &);
+void init_ex5(py::module &);
+void init_ex6(py::module &);
+void init_ex7(py::module &);
+void init_ex8(py::module &);
+void init_ex9(py::module &);
+
+PYTHON_PLUGIN(example) {
+ py::module m("example", "pybind example plugin");
+
+ init_ex1(m);
+ init_ex2(m);
+ init_ex3(m);
+ init_ex4(m);
+ init_ex5(m);
+ init_ex6(m);
+ init_ex7(m);
+ init_ex8(m);
+ init_ex9(m);
+
+ return m.ptr();
+}
diff --git a/example/example.h b/example/example.h
new file mode 100644
index 0000000..67434bb
--- /dev/null
+++ b/example/example.h
@@ -0,0 +1,7 @@
+#include <pybind/pybind.h>
+#include <iostream>
+
+using std::cout;
+using std::endl;
+
+namespace py = pybind;
diff --git a/example/example1.cpp b/example/example1.cpp
new file mode 100644
index 0000000..0cdc1f0
--- /dev/null
+++ b/example/example1.cpp
@@ -0,0 +1,92 @@
+/*
+ example/example1.cpp -- Example 1: constructors, deconstructors,
+ attribute access, __str__, argument and return value conventions
+
+ 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 Example1 {
+public:
+ Example1() {
+ cout << "Called Example1 default constructor.." << endl;
+ }
+ Example1(int value) : value(value) {
+ cout << "Called Example1 constructor with value " << value << ".." << endl;
+ }
+ Example1(const Example1 &e) : value(e.value) {
+ cout << "Called Example1 copy constructor with value " << value << ".." << endl;
+ }
+ Example1(Example1 &&e) : value(e.value) {
+ cout << "Called Example1 move constructor with value " << value << ".." << endl;
+ e.value = 0;
+ }
+ ~Example1() {
+ cout << "Called Example1 destructor (" << value << ")" << endl;
+ }
+ std::string toString() {
+ return "Example1[value=" + std::to_string(value) + "]";
+ }
+
+ void operator=(const Example1 &e) { cout << "Assignment operator" << endl; value = e.value; }
+ void operator=(Example1 &&e) { cout << "Move assignment operator" << endl; value = e.value; e.value = 0;}
+
+ void add1(Example1 other) { value += other.value; } // passing py value
+ void add2(Example1 &other) { value += other.value; } // passing by reference
+ void add3(const Example1 &other) { value += other.value; } // passing by const reference
+ void add4(Example1 *other) { value += other->value; } // passing py pointer
+ void add5(const Example1 *other) { value += other->value; } // passing by const pointer
+
+ void add6(int other) { value += other; } // passing py value
+ void add7(int &other) { value += other; } // passing by reference
+ void add8(const int &other) { value += other; } // passing by const reference
+ void add9(int *other) { value += *other; } // passing py pointer
+ void add10(const int *other) { value += *other; } // passing by const pointer
+
+ Example1 self1() { return *this; } // return by value
+ Example1 &self2() { return *this; } // return by reference
+ const Example1 &self3() { return *this; } // return by const reference
+ Example1 *self4() { return this; } // return by pointer
+ const Example1 *self5() { return this; } // return by const pointer
+
+ int internal1() { return value; } // return by value
+ int &internal2() { return value; } // return by reference
+ const int &internal3() { return value; } // return by const reference
+ int *internal4() { return &value; } // return by pointer
+ const int *internal5() { return &value; } // return by const pointer
+
+ int value = 0;
+};
+
+void init_ex1(py::module &m) {
+ py::class_<Example1>(m, "Example1")
+ .def(py::init<>())
+ .def(py::init<int>())
+ .def(py::init<const Example1&>())
+ .def("add1", &Example1::add1)
+ .def("add2", &Example1::add2)
+ .def("add3", &Example1::add3)
+ .def("add4", &Example1::add4)
+ .def("add5", &Example1::add5)
+ .def("add6", &Example1::add6)
+ .def("add7", &Example1::add7)
+ .def("add8", &Example1::add8)
+ .def("add9", &Example1::add9)
+ .def("add10", &Example1::add10)
+ .def("self1", &Example1::self1)
+ .def("self2", &Example1::self2)
+ .def("self3", &Example1::self3)
+ .def("self4", &Example1::self4)
+ .def("self5", &Example1::self5)
+ .def("internal1", &Example1::internal1)
+ .def("internal2", &Example1::internal2)
+ .def("internal3", &Example1::internal3)
+ .def("internal4", &Example1::internal4)
+ .def("internal5", &Example1::internal5)
+ .def("__str__", &Example1::toString)
+ .def_readwrite("value", &Example1::value);
+}
diff --git a/example/example1.py b/example/example1.py
new file mode 100755
index 0000000..30cda8d
--- /dev/null
+++ b/example/example1.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python3
+import sys
+sys.path.append('.')
+
+from example import Example1
+
+instance1 = Example1()
+instance2 = Example1(32)
+instance1.add1(instance2)
+instance1.add2(instance2)
+instance1.add3(instance2)
+instance1.add4(instance2)
+instance1.add5(instance2)
+instance1.add6(32)
+instance1.add7(32)
+instance1.add8(32)
+instance1.add9(32)
+instance1.add10(32)
+
+print("Instance 1: " + str(instance1))
+print("Instance 2: " + str(instance2))
+
+print(instance1.self1())
+print(instance1.self2())
+print(instance1.self3())
+print(instance1.self4())
+print(instance1.self5())
+print(instance1.internal1())
+print(instance1.internal2())
+print(instance1.internal3())
+print(instance1.internal4())
+print(instance1.internal5())
+
+print("Instance 1, direct access = %i" % instance1.value)
+instance1.value = 100
+print("Instance 1: " + str(instance1))
diff --git a/example/example1.ref b/example/example1.ref
new file mode 100644
index 0000000..deeb40c
--- /dev/null
+++ b/example/example1.ref
@@ -0,0 +1,28 @@
+Called Example1 default constructor..
+Called Example1 constructor with value 32..
+Called Example1 copy constructor with value 32..
+Called Example1 move constructor with value 32..
+Called Example1 move constructor with value 32..
+Called Example1 destructor (32)
+Called Example1 destructor (0)
+Called Example1 destructor (0)
+Called Example1 copy constructor with value 320..
+Called Example1 copy constructor with value 320..
+Called Example1 destructor (320)
+Called Example1 destructor (320)
+Instance 1: Example1[value=320]
+Instance 2: Example1[value=32]
+Example1[value=320]
+Example1[value=320]
+Example1[value=320]
+Example1[value=320]
+Example1[value=320]
+320
+320
+320
+320
+320
+Instance 1, direct access = 320
+Instance 1: Example1[value=100]
+Called Example1 destructor (32)
+Called Example1 destructor (100)
diff --git a/example/example2.cpp b/example/example2.cpp
new file mode 100644
index 0000000..d064fb3
--- /dev/null
+++ b/example/example2.cpp
@@ -0,0 +1,117 @@
+/*
+ example/example2.cpp2 -- Example 2: singleton design pattern, static
+ functions and variables, passing and interacting with 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.
+*/
+
+#include "example.h"
+
+class Example2 {
+public:
+ static Example2 *new_instance() {
+ return new Example2();
+ }
+ ~Example2() {
+ std::cout << "Destructing Example2" << std::endl;
+ }
+
+ /* Create and return a Python dictionary */
+ py::dict get_dict() {
+ py::dict dict;
+ dict[py::str("key")] = py::str("value");
+ return dict;
+ }
+
+ /* Create and return a C++ dictionary */
+ std::map<std::string, std::string> get_dict_2() {
+ std::map<std::string, std::string> result;
+ result["key"] = "value";
+ return result;
+ }
+
+ /* Create, manipulate, and return a Python list */
+ py::list get_list() {
+ py::list list;
+ list.append(py::str("value"));
+ cout << "Entry at positon 0: " << py::object(list[0]) << endl;
+ list[0] = py::str("overwritten");
+ return list;
+ }
+
+ /* C++ STL data types are automatically casted */
+ std::vector<std::string> get_list_2() {
+ std::vector<std::string> list;
+ list.push_back("value");
+ return list;
+ }
+
+ /* Easily iterate over a dictionary using a C++11 range-based for loop */
+ void print_dict(py::dict dict) {
+ for (auto item : dict)
+ std::cout << "key: " << item.first << ", value=" << item.second << std::endl;
+ }
+
+ /* STL data types are automatically casted from Python */
+ void print_dict_2(const std::map<std::string, std::string> &dict) {
+ for (auto item : dict)
+ std::cout << "key: " << item.first << ", value=" << item.second << std::endl;
+ }
+
+ /* Easily iterate over a list using a C++11 range-based for loop */
+ void print_list(py::list list) {
+ int index = 0;
+ for (auto item : list)
+ std::cout << "list item " << index++ << ": " << item << std::endl;
+ }
+
+ /* STL data types are automatically casted from Python */
+ void print_list_2(std::vector<std::string> &list) {
+ int index = 0;
+ for (auto item : list)
+ std::cout << "list item " << index++ << ": " << item << std::endl;
+ }
+
+ /* pybind automatically translates between C++11 and Python tuples */
+ std::pair<std::string, bool> pair_passthrough(std::pair<bool, std::string> input) {
+ return std::make_pair(input.second, input.first);
+ }
+
+ /* pybind automatically translates between C++11 and Python tuples */
+ std::tuple<int, std::string, bool> tuple_passthrough(std::tuple<bool, std::string, int> input) {
+ return std::make_tuple(std::get<2>(input), std::get<1>(input), std::get<0>(input));
+ }
+
+ void throw_exception() {
+ throw std::runtime_error("This exception was intentionally thrown.");
+ }
+
+ static int value;
+ static const int value2;
+};
+
+int Example2::value = 0;
+const int Example2::value2 = 5;
+
+void init_ex2(py::module &m) {
+ /* No constructor is explicitly defined below. An exception is raised when
+ trying to construct it directly from Python */
+ py::class_<Example2>(m, "Example2")
+ .def("get_dict", &Example2::get_dict, "Return a Python dictionary")
+ .def("get_dict_2", &Example2::get_dict_2, "Return a C++ dictionary")
+ .def("get_list", &Example2::get_list, "Return a Python list")
+ .def("get_list_2", &Example2::get_list_2, "Return a C++ list")
+ .def("print_dict", &Example2::print_dict, "Print entries of a Python dictionary")
+ .def("print_dict_2", &Example2::print_dict_2, "Print entries of a C++ dictionary")
+ .def("print_list", &Example2::print_list, "Print entries of a Python list")
+ .def("print_list_2", &Example2::print_list_2, "Print entries of a C++ list")
+ .def("pair_passthrough", &Example2::pair_passthrough, "Return a pair in reversed order")
+ .def("tuple_passthrough", &Example2::tuple_passthrough, "Return a triple in reversed order")
+ .def("throw_exception", &Example2::throw_exception, "Throw an exception")
+ .def_static("new_instance", &Example2::new_instance, "Return an instance")
+ .def_readwrite_static("value", &Example2::value, "Static value member")
+ .def_readonly_static("value2", &Example2::value2, "Static value member (readonly)");
+}
diff --git a/example/example2.py b/example/example2.py
new file mode 100755
index 0000000..b0f4707
--- /dev/null
+++ b/example/example2.py
@@ -0,0 +1,47 @@
+#!/usr/bin/env python3
+import sys, pydoc
+sys.path.append('.')
+
+from example import Example2
+
+Example2.value = 15
+print(Example2.value)
+print(Example2.value2)
+
+try:
+ Example2()
+except Exception as e:
+ print(e)
+
+try:
+ Example2.value2 = 15
+except Exception as e:
+ print(e)
+
+instance = Example2.new_instance()
+
+dict_result = instance.get_dict()
+dict_result['key2'] = 'value2'
+instance.print_dict(dict_result)
+
+dict_result = instance.get_dict_2()
+dict_result['key2'] = 'value2'
+instance.print_dict_2(dict_result)
+
+list_result = instance.get_list()
+list_result.append('value2')
+instance.print_list(list_result)
+
+list_result = instance.get_list_2()
+list_result.append('value2')
+instance.print_list_2(list_result)
+
+try:
+ instance.throw_exception()
+except Exception as e:
+ print(e)
+
+print(instance.pair_passthrough((True, "test")))
+print(instance.tuple_passthrough((True, "test", 5)))
+
+print(pydoc.render_doc(Example2, "Help on %s"))
diff --git a/example/example2.ref b/example/example2.ref
new file mode 100644
index 0000000..8367f20
--- /dev/null
+++ b/example/example2.ref
@@ -0,0 +1,91 @@
+key: key, value=value
+key: key2, value=value2
+key: key, value=value
+key: key2, value=value2
+Entry at positon 0: value
+list item 0: overwritten
+list item 1: value2
+list item 0: value
+list item 1: value2
+15
+5
+example.Example2: No constructor defined!
+can't set attribute
+This exception was intentionally thrown.
+('test', True)
+(5, 'test', True)
+Help on class Example2 in module example
+
+class EExxaammppllee22(builtins.object)
+ | Methods defined here:
+ |
+ | ____iinniitt____(self, /, *args, **kwargs)
+ | Initialize self. See help(type(self)) for accurate signature.
+ |
+ | ____nneeww____ = <built-in method __new__ of example.Example2_meta object>
+ | ggeett__ddiicctt(...) from builtins.PyCapsule
+ | Signature : get_dict(Example2) -> dict
+ |
+ | Return a Python dictionary
+ |
+ | ggeett__ddiicctt__22(...) from builtins.PyCapsule
+ | Signature : get_dict_2(Example2) -> dict<str, str>
+ |
+ | Return a C++ dictionary
+ |
+ | ggeett__lliisstt(...) from builtins.PyCapsule
+ | Signature : get_list(Example2) -> list
+ |
+ | Return a Python list
+ |
+ | ggeett__lliisstt__22(...) from builtins.PyCapsule
+ | Signature : get_list_2(Example2) -> list<str>
+ |
+ | Return a C++ list
+ |
+ | nneeww__iinnssttaannccee(...) from builtins.PyCapsule
+ | Signature : new_instance() -> Example2
+ |
+ | Return an instance
+ |
+ | ppaaiirr__ppaasssstthhrroouugghh(...) from builtins.PyCapsule
+ | Signature : pair_passthrough(Example2, (bool, str)) -> (str, bool)
+ |
+ | Return a pair in reversed order
+ |
+ | pprriinntt__ddiicctt(...) from builtins.PyCapsule
+ | Signature : print_dict(Example2, dict) -> None
+ |
+ | Print entries of a Python dictionary
+ |
+ | pprriinntt__ddiicctt__22(...) from builtins.PyCapsule
+ | Signature : print_dict_2(Example2, dict<str, str>) -> None
+ |
+ | Print entries of a C++ dictionary
+ |
+ | pprriinntt__lliisstt(...) from builtins.PyCapsule
+ | Signature : print_list(Example2, list) -> None
+ |
+ | Print entries of a Python list
+ |
+ | pprriinntt__lliisstt__22(...) from builtins.PyCapsule
+ | Signature : print_list_2(Example2, list<str>) -> None
+ |
+ | Print entries of a C++ list
+ |
+ | tthhrrooww__eexxcceeppttiioonn(...) from builtins.PyCapsule
+ | Signature : throw_exception(Example2) -> None
+ |
+ | Throw an exception
+ |
+ | ttuuppllee__ppaasssstthhrroouugghh(...) from builtins.PyCapsule
+ | Signature : tuple_passthrough(Example2, (bool, str, int32_t)) -> (int32_t, str, bool)
+ |
+ | Return a triple in reversed order
+ |
+ | ----------------------------------------------------------------------
+ | Data and other attributes defined here:
+ |
+ | ____iinnssttaannccee__ssiizzee____ = 1
+
+Destructing Example2
diff --git a/example/example3.cpp b/example/example3.cpp
new file mode 100644
index 0000000..fec5d30
--- /dev/null
+++ b/example/example3.cpp
@@ -0,0 +1,65 @@
+/*
+ example/example3.cpp -- Example 3: 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.
+*/
+
+#include "example.h"
+#include <pybind/operators.h>
+
+class Vector2 {
+public:
+ Vector2(float x, float y) : x(x), y(y) { std::cout << "Value constructor" << std::endl; }
+ Vector2(const Vector2 &v) : x(v.x), y(v.y) { std::cout << "Copy constructor" << std::endl; }
+ Vector2(Vector2 &&v) : x(v.x), y(v.y) { std::cout << "Move constructor" << std::endl; v.x = v.y = 0; }
+ ~Vector2() { std::cout << "Destructor." << std::endl; }
+
+ std::string toString() const {
+ return "[" + std::to_string(x) + ", " + std::to_string(y) + "]";
+ }
+
+ void operator=(const Vector2 &v) {
+ cout << "Assignment operator" << endl;
+ x = v.x;
+ y = v.y;
+ }
+
+ void operator=(Vector2 &&v) {
+ cout << "Move assignment operator" << endl;
+ x = v.x; y = v.y; v.x = v.y = 0;
+ }
+
+ Vector2 operator+(const Vector2 &v) const { return Vector2(x + v.x, y + v.y); }
+ Vector2 operator-(const Vector2 &v) const { return Vector2(x - v.x, y - v.y); }
+ Vector2 operator-(float value) const { return Vector2(x - value, y - value); }
+ Vector2 operator+(float value) const { return Vector2(x + value, y + value); }
+ Vector2 operator*(float value) const { return Vector2(x * value, y * value); }
+ Vector2 operator/(float value) const { return Vector2(x / value, y / value); }
+ Vector2& operator+=(const Vector2 &v) { x += v.x; y += v.y; return *this; }
+ Vector2& operator-=(const Vector2 &v) { x -= v.x; y -= v.y; return *this; }
+ Vector2& operator*=(float v) { x *= v; y *= v; return *this; }
+ Vector2& operator/=(float v) { x /= v; y /= v; return *this; }
+private:
+ float x, y;
+};
+
+void init_ex3(py::module &m) {
+ py::class_<Vector2>(m, "Vector2")
+ .def(py::init<float, float>())
+ .def(py::self + py::self)
+ .def(py::self + float())
+ .def(py::self - py::self)
+ .def(py::self - float())
+ .def(py::self * float())
+ .def(py::self / float())
+ .def(py::self += py::self)
+ .def(py::self -= py::self)
+ .def(py::self *= float())
+ .def(py::self /= float())
+ .def("__str__", &Vector2::toString);
+
+ m.attr("Vector") = m.attr("Vector2");
+}
diff --git a/example/example3.py b/example/example3.py
new file mode 100755
index 0000000..a889320
--- /dev/null
+++ b/example/example3.py
@@ -0,0 +1,22 @@
+#!/usr/bin/env python3
+import sys
+sys.path.append('.')
+
+from example import Vector2, Vector
+
+v1 = Vector2(1, 2)
+v2 = Vector(3, -1)
+
+print("v1 = " + str(v1))
+print("v2 = " + str(v2))
+print("v1+v2 = " + str(v1+v2))
+print("v1-v2 = " + str(v1-v2))
+print("v1-8 = " + str(v1-8))
+print("v1+8 = " + str(v1+8))
+print("v1*8 = " + str(v1*8))
+print("v1/8 = " + str(v1/8))
+
+v1 += v2
+v1 *= 2
+
+print("(v1+v2)*2 = " + str(v1))
diff --git a/example/example3.ref b/example/example3.ref
new file mode 100644
index 0000000..e45c110
--- /dev/null
+++ b/example/example3.ref
@@ -0,0 +1,37 @@
+Value constructor
+Value constructor
+Value constructor
+Copy constructor
+Destructor.
+Destructor.
+Value constructor
+Copy constructor
+Destructor.
+Destructor.
+Value constructor
+Copy constructor
+Destructor.
+Destructor.
+Value constructor
+Copy constructor
+Destructor.
+Destructor.
+Value constructor
+Copy constructor
+Destructor.
+Destructor.
+Value constructor
+Copy constructor
+Destructor.
+Destructor.
+v1 = [1.000000, 2.000000]
+v2 = [3.000000, -1.000000]
+v1+v2 = [4.000000, 1.000000]
+v1-v2 = [-2.000000, 3.000000]
+v1-8 = [-7.000000, -6.000000]
+v1+8 = [9.000000, 10.000000]
+v1*8 = [8.000000, 16.000000]
+v1/8 = [0.125000, 0.250000]
+(v1+v2)*2 = [8.000000, 2.000000]
+Destructor.
+Destructor.
diff --git a/example/example4.cpp b/example/example4.cpp
new file mode 100644
index 0000000..ed9d0da
--- /dev/null
+++ b/example/example4.cpp
@@ -0,0 +1,60 @@
+/*
+ example/example4.cpp -- Example 4: global constants and functions, enumerations
+
+ 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"
+
+enum EMyEnumeration {
+ EFirstEntry = 1,
+ ESecondEntry
+};
+
+class Example4 {
+public:
+ enum EMode {
+ EFirstMode = 1,
+ ESecondMode
+ };
+
+ static void test_function(EMode mode) {
+ std::cout << "Example4::test_function(enum=" << mode << ")" << std::endl;
+ }
+};
+
+bool test_function1() {
+ std::cout << "test_function()" << std::endl;
+ return false;
+}
+
+float test_function2(int i) {
+ std::cout << "test_function(" << i << ")" << std::endl;
+ return i / 2.f;
+}
+
+void test_function3(EMyEnumeration k) {
+ std::cout << "test_function(enum=" << k << ")" << std::endl;
+}
+
+void init_ex4(py::module &m) {
+ m.def("test_function", &test_function1);
+ m.def("test_function", &test_function2);
+ m.def("test_function", &test_function3);
+ m.attr("some_constant") = py::int_(14);
+
+ py::enum_<EMyEnumeration>(m, "EMyEnumeration")
+ .value("EFirstEntry", EFirstEntry)
+ .value("ESecondEntry", ESecondEntry)
+ .export_values();
+
+ py::class_<Example4> ex4_class(m, "Example4");
+ ex4_class.def_static("test_function", &Example4::test_function);
+ py::enum_<Example4::EMode>(ex4_class, "EMode")
+ .value("EFirstMode", Example4::EFirstMode)
+ .value("ESecondMode", Example4::ESecondMode)
+ .export_values();
+}
diff --git a/example/example4.py b/example/example4.py
new file mode 100755
index 0000000..aa2a448
--- /dev/null
+++ b/example/example4.py
@@ -0,0 +1,24 @@
+#!/usr/bin/env python3
+import sys
+sys.path.append('.')
+
+from example import test_function
+from example import some_constant
+from example import EMyEnumeration
+from example import EFirstEntry
+from example import Example4
+
+print(EMyEnumeration)
+print(EMyEnumeration.EFirstEntry)
+print(EMyEnumeration.ESecondEntry)
+print(EFirstEntry)
+
+print(test_function())
+print(test_function(7))
+print(test_function(EMyEnumeration.EFirstEntry))
+print(test_function(EMyEnumeration.ESecondEntry))
+
+print(Example4.EMode)
+print(Example4.EMode.EFirstMode)
+print(Example4.EFirstMode)
+Example4.test_function(Example4.EFirstMode)
diff --git a/example/example4.ref b/example/example4.ref
new file mode 100644
index 0000000..09935a9
--- /dev/null
+++ b/example/example4.ref
@@ -0,0 +1,16 @@
+test_function()
+test_function(7)
+test_function(enum=1)
+test_function(enum=2)
+Example4::test_function(enum=1)
+<class 'example.EMyEnumeration'>
+EMyEnumeration.EFirstEntry
+EMyEnumeration.ESecondEntry
+EMyEnumeration.EFirstEntry
+False
+3.5
+None
+None
+<class 'example.Example4.EMode'>
+EMode.EFirstMode
+EMode.EFirstMode
diff --git a/example/example5.cpp b/example/example5.cpp
new file mode 100644
index 0000000..7d61779
--- /dev/null
+++ b/example/example5.cpp
@@ -0,0 +1,95 @@
+/*
+ example/example5.cpp -- Example 5: inheritance, callbacks, acquiring
+ and releasing the global interpreter lock
+
+ 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 Pet {
+public:
+ Pet(const std::string &name, const std::string &species)
+ : m_name(name), m_species(species) {}
+ std::string name() const { return m_name; }
+ std::string species() const { return m_species; }
+private:
+ std::string m_name;
+ std::string m_species;
+};
+
+class Dog : public Pet {
+public:
+ Dog(const std::string &name) : Pet(name, "dog") {}
+ void bark() const { std::cout << "Woof!" << std::endl; }
+};
+
+void pet_print(const Pet &pet) {
+ std::cout << pet.name() + " is a " + pet.species() << std::endl;
+}
+
+void dog_bark(const Dog &dog) {
+ dog.bark();
+}
+
+class Example5 {
+public:
+ Example5(py::handle self, int state)
+ : self(self), state(state) {
+ cout << "Constructing Example5.." << endl;
+ }
+
+ ~Example5() {
+ cout << "Destructing Example5.." << endl;
+ }
+
+ void callback(int value) {
+ py::gil_scoped_acquire gil;
+ cout << "In Example5::callback() " << endl;
+ py::object method = self.attr("callback");
+ method.call(state, value);
+ }
+private:
+ py::handle self;
+ int state;
+};
+
+bool test_callback1(py::object func) {
+ func.call();
+ return false;
+}
+
+int test_callback2(py::object func) {
+ py::object result = func.call("Hello", true, 5);
+ return result.cast<int>();
+}
+
+void test_callback3(Example5 *ex, int value) {
+ py::gil_scoped_release gil;
+ ex->callback(value);
+}
+
+void init_ex5(py::module &m) {
+ py::class_<Pet> pet_class(m, "Pet");
+ pet_class
+ .def(py::init<std::string, std::string>())
+ .def("name", &Pet::name)
+ .def("species", &Pet::species);
+
+ py::class_<Dog>(m, "Dog", pet_class)
+ .def(py::init<std::string>());
+
+ m.def("pet_print", pet_print);
+ m.def("dog_bark", dog_bark);
+
+ m.def("test_callback1", &test_callback1);
+ m.def("test_callback2", &test_callback2);
+ m.def("test_callback3", &test_callback3);
+
+ py::class_<Example5>(m, "Example5")
+ .def(py::init<py::object, int>());
+}
diff --git a/example/example5.py b/example/example5.py
new file mode 100755
index 0000000..b119de9
--- /dev/null
+++ b/example/example5.py
@@ -0,0 +1,45 @@
+#!/usr/bin/env python3
+import sys
+sys.path.append('.')
+
+from example import Pet
+from example import Dog
+from example import dog_bark
+from example import pet_print
+
+polly = Pet('Polly', 'parrot')
+molly = Dog('Molly')
+print(polly.name() + " is a " + polly.species())
+pet_print(polly)
+print(molly.name() + " is a " + molly.species())
+pet_print(molly)
+dog_bark(molly)
+try:
+ dog_bark(polly)
+except Exception as e:
+ print('The following error is expected: ' + str(e))
+
+from example import test_callback1
+from example import test_callback2
+from example import test_callback3
+from example import Example5
+
+def func1():
+ print('Callback function 1 called!')
+
+def func2(a, b, c):
+ print('Callback function 2 called : ' + str(a) + ", " + str(b) + ", "+ str(c))
+ return c
+
+class MyCallback(Example5):
+ def __init__(self, value):
+ Example5.__init__(self, self, value)
+
+ def callback(self, value1, value2):
+ print('got callback: %i %i' % (value1, value2))
+
+print(test_callback1(func1))
+print(test_callback2(func2))
+
+callback = MyCallback(3)
+test_callback3(callback, 4)
diff --git a/example/example5.ref b/example/example5.ref
new file mode 100644
index 0000000..4061128
--- /dev/null
+++ b/example/example5.ref
@@ -0,0 +1,16 @@
+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..
diff --git a/example/example6.cpp b/example/example6.cpp
new file mode 100644
index 0000000..1e0359a
--- /dev/null
+++ b/example/example6.cpp
@@ -0,0 +1,175 @@
+/*
+ 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);
+}
diff --git a/example/example6.py b/example/example6.py
new file mode 100755
index 0000000..7dbadc4
--- /dev/null
+++ b/example/example6.py
@@ -0,0 +1,29 @@
+#!/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('')
diff --git a/example/example6.ref b/example/example6.ref
new file mode 100644
index 0000000..8986be6
--- /dev/null
+++ b/example/example6.ref
@@ -0,0 +1,18 @@
+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
diff --git a/example/example7.cpp b/example/example7.cpp
new file mode 100644
index 0000000..82ab3b6
--- /dev/null
+++ b/example/example7.cpp
@@ -0,0 +1,115 @@
+/*
+ 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) }
+ );
+ });
+}
diff --git a/example/example7.py b/example/example7.py
new file mode 100755
index 0000000..565ceac
--- /dev/null
+++ b/example/example7.py
@@ -0,0 +1,26 @@
+#!/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()
diff --git a/example/example7.ref b/example/example7.ref
new file mode 100644
index 0000000..6112cf6
--- /dev/null
+++ b/example/example7.ref
@@ -0,0 +1,11 @@
+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
diff --git a/example/example8.cpp b/example/example8.cpp
new file mode 100644
index 0000000..3aac43a
--- /dev/null
+++ b/example/example8.cpp
@@ -0,0 +1,76 @@
+/*
+ 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>();
+}
diff --git a/example/example8.py b/example/example8.py
new file mode 100644
index 0000000..9c295d2
--- /dev/null
+++ b/example/example8.py
@@ -0,0 +1,36 @@
+#!/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)
diff --git a/example/example9.cpp b/example/example9.cpp
new file mode 100644
index 0000000..0e070b1
--- /dev/null
+++ b/example/example9.cpp
@@ -0,0 +1,53 @@
+/*
+ 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);
+}
diff --git a/example/example9.py b/example/example9.py
new file mode 100644
index 0000000..d8c654e
--- /dev/null
+++ b/example/example9.py
@@ -0,0 +1,27 @@
+#!/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)
+
diff --git a/example/object.h b/example/object.h
new file mode 100644
index 0000000..8097bd6
--- /dev/null
+++ b/example/object.h
@@ -0,0 +1,160 @@
+#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 */
diff --git a/example/run_test.py b/example/run_test.py
new file mode 100644
index 0000000..1c47cc0
--- /dev/null
+++ b/example/run_test.py
@@ -0,0 +1,16 @@
+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)