Commit 38bd7113 by Wenzel Jakob

Initial commit

parents
CMakeCache.txt
CMakeFiles
Makefile
cmake_install.cmake
.DS_Store
/example/example.so
/example/example.pyd
*.sln
*.sdf
*.opensdf
*.vcxproj
*.filters
example.dir
Win32
x64
Release
Debug
.vs
CTestTestfile.cmake
Testing
# CMakeLists.txt -- Build system for the pybind11 examples
#
# 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.
cmake_minimum_required(VERSION 2.8)
project(pybind)
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
message(STATUS "Setting build type to 'MinSizeRel' as none was specified.")
set(CMAKE_BUILD_TYPE MinSizeRel CACHE STRING "Choose the type of build." FORCE)
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release"
"MinSizeRel" "RelWithDebInfo")
endif()
set(Python_ADDITIONAL_VERSIONS 3.4 3.5 3.6)
find_package(PythonLibs 3 REQUIRED)
find_package(PythonInterp 3 REQUIRED)
string(TOUPPER "${CMAKE_BUILD_TYPE}" U_CMAKE_BUILD_TYPE)
if (UNIX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wno-unsequenced")
if (NOT ${U_CMAKE_BUILD_TYPE} MATCHES DEBUG)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden")
endif()
endif()
# Compile with compiler warnings turned on
if(MSVC)
if(CMAKE_CXX_FLAGS MATCHES "/W[0-4]")
string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
endif()
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra")
endif()
include_directories(${PYTHON_INCLUDE_DIR} include)
add_library(example SHARED
include/pybind/cast.h
include/pybind/common.h
include/pybind/mpl.h
include/pybind/operators.h
include/pybind/pybind.h
include/pybind/pytypes.h
include/pybind/typeid.h
example/example.cpp
example/example1.cpp
example/example2.cpp
example/example3.cpp
example/example4.cpp
example/example5.cpp
example/example6.cpp
example/example7.cpp
example/example8.cpp
example/example9.cpp
)
set_target_properties(example PROPERTIES PREFIX "")
set_target_properties(example PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/example)
if (WIN32)
if (MSVC)
# Enforce size-based optimization and link time code generation on MSVC (~30% smaller binaries in experiments)
set_target_properties(example PROPERTIES COMPILE_FLAGS "/Os /GL")
set_target_properties(example PROPERTIES LINK_FLAGS "/LTCG")
endif()
# .PYD file extension on Windows
set_target_properties(example PROPERTIES SUFFIX ".pyd")
# Link against the Python shared library
target_link_libraries(example ${PYTHON_LIBRARY})
elseif (UNIX)
# It's quite common to have multiple copies of the same Python version
# installed on one's system. E.g.: one copy from the OS and another copy
# that's statically linked into an application like Blender or Maya.
# If we link our plugin library against the OS Python here and import it
# into Blender or Maya later on, this will cause segfaults when multiple
# conflicting Python instances are active at the same time.
# Windows does not seem to be affected by this issue. The solution for Linux
# and Mac OS is simple: we just don't link against the Python library. The
# resulting shared library will have missing symbols, but that's perfectly
# fine -- they will be resolved at import time.
# .SO file extension on Linux/Mac OS
set_target_properties(example PROPERTIES SUFFIX ".so")
# Strip unnecessary sections of the binary on Linux/Mac OS
if(APPLE)
set_target_properties(example PROPERTIES MACOSX_RPATH ".")
set_target_properties(example PROPERTIES LINK_FLAGS "-undefined dynamic_lookup -dead_strip")
if (NOT ${U_CMAKE_BUILD_TYPE} MATCHES DEBUG)
add_custom_command(TARGET example POST_BUILD COMMAND strip -u -r ${PROJECT_SOURCE_DIR}/example/example.so)
endif()
else()
if (NOT ${U_CMAKE_BUILD_TYPE} MATCHES DEBUG)
add_custom_command(TARGET example POST_BUILD COMMAND strip ${PROJECT_SOURCE_DIR}/example/example.so)
endif()
endif()
endif()
enable_testing()
set(RUN_TEST ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/example/run_test.py)
foreach(i RANGE 1 7)
add_test(NAME example${i} COMMAND ${RUN_TEST} example${i})
endforeach()
Copyright (c) 2015 Wenzel Jakob <wenzel@inf.ethz.ch>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
# pybind11 -- Seamless operability between C++11 and Python
**pybind11** is a lightweight header library that exposes C++ types in Python
and vice versa, mainly to create Python bindings of existing C++ code. Its
goals and syntax are similar to the excellent
[Boost.Python](http://www.boost.org/doc/libs/1_58_0/libs/python/doc/) library
by David Abrahams: to minimize boilerplate code in traditional extension
modules by inferring type information using compile-time introspection.
The main issue with Boost.Python—and the reason for creating such a similar
project—is Boost. Boost is an enormously large and complex suite of utility
libraries that works with almost every C++ compiler in existence. This
compatibility has its cost: arcane template tricks and workarounds are
necessary to support the oldest and buggiest of compiler specimens. Now that
C++11-compatible compilers are widely available, this heavy machinery has
become an excessively large and unnecessary dependency.
Think of this library as a tiny self-contained version of Boost.Python with
everything stripped away that isn't relevant for binding generation. The whole
codebase requires less than 2000 lines of code and just depends on Python and
the C++ standard library. This compact implementation was possible thanks to
some of the new C++11 language features (tuples, lambda functions and variadic
templates), and by only targeting Python 3.x and higher.
## Core features
The following C++ features can be mapped to Python
- Functions accepting and returning custom data structures per value, reference, or pointer
- Instance methods and static methods
- Overloaded functions
- Instance attributes and static attributes
- Exceptions
- Enumerations
- Callbacks
- Custom operators
- STL data structures
- Smart pointers with reference counting like `std::shared_ptr`
- Internal references with correct reference counting
## Goodies
In addition to the core functionality, pybind11 provides some extra goodies:
- It's easy to expose the internal storage of custom data types through
Pythons' buffer protocols. This is handy e.g. for fast conversion between
C++ matrix classes like Eigen and NumPy without expensive copy operations.
- Python's slice-based access and assignment operations can be supported with
just a few lines of code.
- pybind11 uses C++11 move constructors and move assignment operators whenever
possible to efficiently transfer custom data types.
## Limitations
Various things that Boost.Python can do remain unsupported, e.g.:
- Fine grained exception translation: currently, all exceptions derived from
`std::exception` are mapped to a Python `Exception`, but that's it.
- Default arguments in C++ functions are ignored, though their effect can be
emulated by binding multiple overloads using anonymous functions.
- Python keyword arguments are not supported in bindings
- Weak pointers are not supported
## What does the binding code look like?
Here is a simple example. The directory `example` contains many more.
```C++
#include <pybind/pybind.h>
#include <pybind/operators.h>
namespace py = pybind;
/// Example C++ class which should be bound to Python
class Test {
public:
Test();
Test(int value);
std::string toString();
Test operator+(const Test &e) const;
void print_dict(py::dict dict) {
/* Easily interact with Python types */
for (auto item : dict)
std::cout << "key=" << item.first << ", "
<< "value=" << item.second << std::endl;
}
int value = 0;
};
PYTHON_PLUGIN(example) {
py::module m("example", "pybind example plugin");
py::class_<Test>(m, "Test", "docstring for the Test class")
.def(py::init<>(), "docstring for constructor 1")
.def(py::init<int>(), "docstring for constructor 2")
.def(py::self + py::self, "Addition operator")
.def("__str__", &Test::toString, "Convert to a string representation")
.def("print_dict", &Test::print_dict, "Print a Python dictionary")
.def_readwrite("value", &Test::value, "An instance attribute");
return m.ptr();
}
```
/*
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();
}
#include <pybind/pybind.h>
#include <iostream>
using std::cout;
using std::endl;
namespace py = pybind;
/*
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);
}
#!/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))
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)
/*
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)");
}
#!/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"))
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
/*
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");
}
#!/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))
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.
/*
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();
}
#!/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)
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
/*
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>());
}
#!/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)
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/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 */
/*
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